feat: add tappable hooks

This commit is contained in:
Pooya Parsa 2017-07-03 15:41:40 +04:30
parent a587b798e4
commit b209c80d2b
5 changed files with 63 additions and 23 deletions

View File

@ -43,6 +43,9 @@ export default class Builder extends Tapable {
// Helper to resolve build paths
this.relativeToBuild = (...args) => relativeTo(this.options.buildDir, ...args)
// Call builder plugin on parent nuxt to notify all modules of builder existence
this.nuxt.applyPluginsAsync('builder', this).catch(this.nuxt.errorHandler)
this._buildStatus = STATUS.INITIAL
}
@ -66,6 +69,8 @@ export default class Builder extends Tapable {
// Wait for nuxt ready
await this.nuxt.ready()
await this.applyPluginsAsync('build', this)
// Check if pages dir exists and warn if not
this._nuxtPages = typeof this.options.build.createRoutes !== 'function'
if (this._nuxtPages) {
@ -95,6 +100,8 @@ export default class Builder extends Tapable {
// Start webpack build
await this.webpackBuild()
await this.applyPluginsAsync('built', this)
// Flag to set that building is done
this._buildStatus = STATUS.BUILD_DONE
@ -173,6 +180,9 @@ export default class Builder extends Tapable {
} else {
templateVars.router.routes = this.options.build.createRoutes(this.options.srcDir)
}
await this.applyPluginsAsync('extendRoutes', {routes: templateVars.router.routes, templateVars, r})
// router.extendRoutes method
if (typeof this.options.router.extendRoutes === 'function') {
// let the user extend the routes
@ -216,6 +226,8 @@ export default class Builder extends Tapable {
}, t)
}))
await this.applyPluginsAsync('generate', { builder: this, templatesFiles, templateVars })
// Interpret and move template files to .nuxt/
await Promise.all(templatesFiles.map(async ({ src, dst, options, custom }) => {
// Add template to watchers
@ -246,9 +258,11 @@ export default class Builder extends Tapable {
const dateFS = Date.now() / 1000 - 1000
return utimes(path, dateFS, dateFS)
}))
await this.applyPluginsAsync('generated', this)
}
webpackBuild () {
async webpackBuild () {
debug('Building files...')
let compilersOptions = []
@ -291,7 +305,7 @@ export default class Builder extends Tapable {
})
// Run after each compile
this.compiler.plugin('done', stats => {
this.compiler.plugin('done', async stats => {
// Don't reload failed builds
/* istanbul ignore if */
if (stats.hasErrors() || stats.hasWarnings()) {
@ -301,6 +315,8 @@ export default class Builder extends Tapable {
if (this.nuxt.renderer) {
this.nuxt.renderer.loadResources(sharedFS || fs)
}
await this.applyPluginsAsync('compiled', { builder: this, stats })
})
// Add dev Stuff
@ -308,6 +324,8 @@ export default class Builder extends Tapable {
this.webpackDev()
}
await this.applyPluginsAsync('compile', { builder: this, compiler: this.compiler })
// Start Builds
return parallel(this.compiler.compilers, compiler => new Promise((resolve, reject) => {
if (this.options.dev) {

View File

@ -15,6 +15,15 @@ export default class Generator extends Tapable {
this.nuxt = nuxt
this.options = nuxt.options
this.builder = builder
// Set variables
this.generateRoutes = resolve(this.options.srcDir, 'static')
this.srcBuiltPath = resolve(this.options.buildDir, 'dist')
this.distPath = resolve(this.options.rootDir, this.options.generate.dir)
this.distNuxtPath = join(this.distPath, (isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath))
// Call generator plugin on parent nuxt to notify all modules of generator existence
this.nuxt.applyPluginsAsync('generator', this).catch(this.nuxt.errorHandler)
}
async generate (doBuild = true) {
@ -22,12 +31,6 @@ export default class Generator extends Tapable {
let errors = []
let generateRoutes = []
// Set variables
let srcStaticPath = resolve(this.options.srcDir, 'static')
let srcBuiltPath = resolve(this.options.buildDir, 'dist')
let distPath = resolve(this.options.rootDir, this.options.generate.dir)
let distNuxtPath = join(distPath, (isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath))
// Wait for nuxt be ready
await this.nuxt.ready()
@ -36,16 +39,18 @@ export default class Generator extends Tapable {
await this.builder.build()
}
await this.applyPluginsAsync('before-generate', this)
// Clean destination folder
await remove(distPath)
await remove(this.distPath)
debug('Destination folder cleaned')
// Copy static and built files
/* istanbul ignore if */
if (fs.existsSync(srcStaticPath)) {
await copy(srcStaticPath, distPath)
if (fs.existsSync(this.generateRoutes)) {
await copy(this.generateRoutes, this.distPath)
}
await copy(srcBuiltPath, distNuxtPath)
await copy(this.srcBuiltPath, this.distNuxtPath)
debug('Static & build files copied')
// Resolve config.generate.routes promises before generating the routes
@ -53,6 +58,7 @@ export default class Generator extends Tapable {
try {
console.log('Generating routes') // eslint-disable-line no-console
generateRoutes = await promisifyRoute(this.options.generate.routes || [])
await this.applyPluginsAsync('generateRoutes', {generator: this, generateRoutes})
} catch (e) {
console.error('Could not resolve routes') // eslint-disable-line no-console
console.error(e) // eslint-disable-line no-console
@ -85,6 +91,8 @@ export default class Generator extends Tapable {
let routes = (this.options.router.mode === 'hash') ? ['/'] : flatRoutes(this.options.router.routes)
routes = decorateWithPayloads(routes)
await this.applyPluginsAsync('generate', {generator: this, routes})
while (routes.length) {
let n = 0
await Promise.all(routes.splice(0, 500).map(async ({ route, payload }) => {
@ -111,7 +119,7 @@ export default class Generator extends Tapable {
let path = join(route, sep, 'index.html') // /about -> /about/index.html
path = (path === '/404/index.html') ? '/404.html' : path // /404 -> /404.html
debug('Generate file: ' + path)
path = join(distPath, path)
path = join(this.distPath, path)
// Make sure the sub folders are created
await mkdirp(dirname(path))
await writeFile(path, html, 'utf8')
@ -120,7 +128,7 @@ export default class Generator extends Tapable {
// Add .nojekyll file to let Github Pages add the _nuxt/ folder
// https://help.github.com/articles/files-that-start-with-an-underscore-are-missing/
const nojekyllPath = resolve(distPath, '.nojekyll')
const nojekyllPath = resolve(this.distPath, '.nojekyll')
writeFile(nojekyllPath, '')
const duration = Math.round((Date.now() - s) / 100) / 10
debug(`HTML Files generated in ${duration}s`)
@ -137,6 +145,8 @@ export default class Generator extends Tapable {
console.error('==== Error report ==== \n' + report.join('\n\n')) // eslint-disable-line no-console
}
await this.applyPluginsAsync('generated', this)
return { duration, errors }
}
}

View File

@ -15,8 +15,9 @@ export default class ModuleContainer extends Tapable {
this.options = nuxt.options
this.requiredModules = []
this.nuxt.plugin('beforeInit', () => {
return sequence(this.options.modules, this.addModule.bind(this))
this.nuxt.plugin('beforeInit', async () => {
await sequence(this.options.modules, this.addModule.bind(this))
await this.applyPluginsAsync('ready', this)
})
}
@ -81,11 +82,14 @@ export default class ModuleContainer extends Tapable {
return this.addModule(moduleOpts, true)
}
addModule (moduleOpts, requireOnce) {
async addModule (moduleOpts, requireOnce) {
/* istanbul ignore if */
if (!moduleOpts) {
return
}
await this.applyPluginsAsync('add', {moduleOpts, requireOnce})
// Allow using babel style array options
if (Array.isArray(moduleOpts)) {
moduleOpts = {
@ -93,12 +97,13 @@ export default class ModuleContainer extends Tapable {
options: moduleOpts[1]
}
}
// Allows passing runtime options to each module
const options = moduleOpts.options || (typeof moduleOpts === 'object' ? moduleOpts : {})
const originalSrc = moduleOpts.src || moduleOpts
// Resolve module
let module = originalSrc
if (typeof module === 'string') {
module = require(this.nuxt.resolvePath(module))
}
@ -108,6 +113,7 @@ export default class ModuleContainer extends Tapable {
if (typeof module !== 'function') {
throw new Error(`[nuxt] Module ${JSON.stringify(originalSrc)} should export a function`)
}
// Module meta
if (!module.meta) {
module.meta = {}
@ -121,6 +127,7 @@ export default class ModuleContainer extends Tapable {
this.requiredModules.push(module.meta.name)
}
}
// Call module with `this` context and pass options
return new Promise((resolve, reject) => {
const result = module.call(this, options, err => {

View File

@ -79,18 +79,23 @@ export default class Nuxt extends Tapable {
}
errorHandler /* istanbul ignore next */() {
// Apply plugins
// eslint-disable-next-line no-console
this.applyPluginsAsync('error', ...arguments).catch(console.error)
// Silent
if (this.options.errorHandler === false) {
return
}
// Custom errorHandler
if (typeof this.options.errorHandler === 'function') {
return this.options.errorHandler.apply(this, arguments)
}
// Default handler
// eslint-disable-next-line no-console
console.error.apply(this, arguments)
process.exit(1)
console.error(...arguments)
}
resolvePath (path) {

View File

@ -71,7 +71,7 @@ export default class Renderer extends Tapable {
}
// Setup all middleWare
this.setupMiddleware()
await this.setupMiddleware()
// Load error template
const errorTemplatePath = resolve(this.options.buildDir, 'views/error.html')
@ -165,9 +165,9 @@ export default class Renderer extends Tapable {
}
}
setupMiddleware () {
async setupMiddleware () {
// Apply setupMiddleware from modules first
this.applyPlugins('setupMiddleware', this.app)
await this.applyPluginsAsync('setupMiddleware', this.app)
// Gzip middleware for production
if (!this.options.dev && this.options.render.gzip) {