refacto: Hooks

This commit is contained in:
Atinux 2017-10-30 18:41:22 +01:00
parent 83815de91b
commit 6648695015
5 changed files with 85 additions and 76 deletions

View File

@ -25,7 +25,7 @@ debug.color = 2 // Force green color
const glob = pify(Glob)
export default class Builder extends Tapable {
constructor (nuxt) {
constructor(nuxt) {
super()
this.nuxt = nuxt
this.isStatic = false // Flag to know if the build is for a generated app
@ -57,9 +57,12 @@ export default class Builder extends Tapable {
this.vueLoader = vueLoaderConfig.bind(this)
this._buildStatus = STATUS.INITIAL
// Call class hook
this.nuxt.applyPlugins('builder', this)
}
get plugins () {
get plugins() {
return this.options.plugins.map((p, i) => {
if (typeof p === 'string') p = { src: p }
return {
@ -70,7 +73,7 @@ export default class Builder extends Tapable {
})
}
vendor () {
vendor() {
return [
'vue',
'vue-router',
@ -79,7 +82,7 @@ export default class Builder extends Tapable {
].concat(this.options.build.vendor).filter(v => v)
}
vendorEntries () {
vendorEntries() {
// Used for dll
const vendor = this.vendor()
const vendorEntries = {}
@ -94,11 +97,11 @@ export default class Builder extends Tapable {
return vendorEntries
}
forGenerate () {
forGenerate() {
this.isStatic = true
}
async build () {
async build() {
// Avoid calling build() method multiple times when dev:true
/* istanbul ignore if */
if (this._buildStatus === STATUS.BUILD_DONE && this.options.dev) {
@ -119,7 +122,7 @@ export default class Builder extends Tapable {
await this.nuxt.ready()
// Wait for build plugins
await this.nuxt.applyPluginsAsync('build', this)
await this.applyPluginsAsync('build', this.options.build)
// Babel options
this.babelOptions = _.defaults(this.options.build.babel, {
@ -177,15 +180,15 @@ 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
await this.applyPluginsAsync('built')
return this
}
async generateRoutesAndFiles () {
async generateRoutesAndFiles() {
debug('Generating files...')
// -- Templates --
let templatesFiles = [
@ -264,7 +267,7 @@ export default class Builder extends Tapable {
templateVars.router.routes = this.options.build.createRoutes(this.options.srcDir)
}
await this.applyPluginsAsync('extendRoutes', { routes: templateVars.router.routes, templateVars, r })
await this.applyPluginsAsync('extendRoutes', templateVars.router.routes)
// router.extendRoutes method
if (typeof this.options.router.extendRoutes === 'function') {
@ -332,7 +335,7 @@ export default class Builder extends Tapable {
}
}
await this.applyPluginsAsync('generate', { builder: this, templatesFiles, templateVars })
await this.applyPluginsAsync('generate', { templatesFiles, templateVars, resolve: r })
// Interpret and move template files to .nuxt/
await Promise.all(templatesFiles.map(async ({ src, dst, options, custom }) => {
@ -372,10 +375,10 @@ export default class Builder extends Tapable {
return utimes(path, dateFS, dateFS)
}))
await this.applyPluginsAsync('generated', this)
await this.applyPluginsAsync('generated')
}
async webpackBuild () {
async webpackBuild() {
debug('Building files...')
const compilersOptions = []
@ -433,11 +436,11 @@ export default class Builder extends Tapable {
// Start Builds
await sequence(this.compilers, (compiler) => new Promise(async (resolve, reject) => {
const name = compiler.options.name
await this.applyPluginsAsync('compile', { builder: this, compiler, name })
await this.applyPluginsAsync('compile', { name, compiler })
// Resolve only when compiler emit done event
compiler.plugin('done', async (stats) => {
await this.applyPluginsAsync('compiled', { builder: this, compiler, name, stats })
await this.applyPluginsAsync('compiled', { name, compiler, stats })
process.nextTick(resolve)
})
// --- Dev Build ---
@ -484,7 +487,7 @@ export default class Builder extends Tapable {
}
}
webpackDev (compiler) {
webpackDev(compiler) {
debug('Adding webpack middleware...')
// Create webpack dev middleware
@ -516,7 +519,7 @@ export default class Builder extends Tapable {
this.watchFiles()
}
watchFiles () {
watchFiles() {
const patterns = [
r(this.options.srcDir, 'layouts'),
r(this.options.srcDir, 'store'),

View File

@ -9,7 +9,7 @@ import Debug from 'debug'
const debug = Debug('nuxt:generate')
export default class Generator extends Tapable {
constructor (nuxt, builder) {
constructor(nuxt, builder) {
super()
this.nuxt = nuxt
this.options = nuxt.options
@ -20,9 +20,12 @@ export default class Generator extends Tapable {
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 class hook
this.nuxt.applyPlugins('generator', this)
}
async generate ({ build = true, init = true } = {}) {
async generate({ build = true, init = true } = {}) {
const s = Date.now()
let errors = []
@ -50,10 +53,8 @@ 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
throw e // eslint-disable-line no-unreachable
}
}
@ -62,7 +63,7 @@ export default class Generator extends Tapable {
let routes = (this.options.router.mode === 'hash') ? ['/'] : flatRoutes(this.options.router.routes)
routes = this.decorateWithPayloads(routes, generateRoutes)
await this.applyPluginsAsync('generate', { generator: this, routes })
await this.applyPluginsAsync('generate', routes)
// Start generate process
while (routes.length) {
@ -86,6 +87,8 @@ export default class Generator extends Tapable {
const duration = Math.round((Date.now() - s) / 100) / 10
debug(`HTML Files generated in ${duration}s`)
await this.applyPluginsAsync('generated', errors)
if (errors.length) {
const report = errors.map(({ type, route, error }) => {
/* istanbul ignore if */
@ -98,12 +101,10 @@ 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 }
}
async initDist () {
async initDist() {
// Clean destination folder
await remove(this.distPath)
debug('Destination folder cleaned')
@ -137,7 +138,7 @@ export default class Generator extends Tapable {
debug('Static & build files copied')
}
decorateWithPayloads (routes, generateRoutes) {
decorateWithPayloads(routes, generateRoutes) {
let routeMap = {}
// Fill routeMap for known routes
routes.forEach((route) => {
@ -148,7 +149,7 @@ export default class Generator extends Tapable {
})
// Fill routeMap with given generate.routes
generateRoutes.forEach((route) => {
// route is either a string or like {route : "/my_route/1"}
// route is either a string or like { route : '/my_route/1', payload: {} }
const path = _.isString(route) ? route : route.route
routeMap[path] = {
route: path,
@ -158,7 +159,7 @@ export default class Generator extends Tapable {
return _.values(routeMap)
}
async generateRoute ({ route, payload = {}, errors = [] }) {
async generateRoute({ route, payload = {}, errors = [] }) {
let html
try {

View File

@ -9,19 +9,24 @@ import Debug from 'debug'
const debug = Debug('nuxt:module')
export default class ModuleContainer extends Tapable {
constructor (nuxt) {
constructor(nuxt) {
super()
this.nuxt = nuxt
this.options = nuxt.options
this.requiredModules = []
// Call class hook
console.log('call module container')
this.nuxt.applyPlugins('moduleContainer', this)
}
async _ready () {
async ready() {
// Load every module in sequence
await sequence(this.options.modules, this.addModule.bind(this))
await this.applyPluginsAsync('ready', this)
await this.applyPluginsAsync('ready')
}
addVendor (vendor) {
addVendor(vendor) {
/* istanbul ignore if */
if (!vendor) {
return
@ -29,7 +34,7 @@ export default class ModuleContainer extends Tapable {
this.options.build.vendor = uniq(this.options.build.vendor.concat(vendor))
}
addTemplate (template) {
addTemplate(template) {
/* istanbul ignore if */
if (!template) {
return
@ -56,7 +61,7 @@ export default class ModuleContainer extends Tapable {
return templateObj
}
addPlugin (template) {
addPlugin(template) {
const { dst } = this.addTemplate(template)
// Add to nuxt plugins
this.options.plugins.unshift({
@ -65,31 +70,29 @@ export default class ModuleContainer extends Tapable {
})
}
addServerMiddleware (middleware) {
addServerMiddleware(middleware) {
this.options.serverMiddleware.push(middleware)
}
extendBuild (fn) {
extendBuild(fn) {
this.options.build.extend = chainFn(this.options.build.extend, fn)
}
extendRoutes (fn) {
extendRoutes(fn) {
this.options.router.extendRoutes = chainFn(this.options.router.extendRoutes, fn)
}
requireModule (moduleOpts) {
requireModule(moduleOpts) {
// Require once
return this.addModule(moduleOpts, true)
}
async 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 = {
@ -129,13 +132,13 @@ export default class ModuleContainer extends Tapable {
}
// Call module with `this` context and pass options
return new Promise((resolve, reject) => {
const result = module.call(this, options, err => {
const m = await new Promise((resolve, reject) => {
const result = module.call(this, options, (err, m) => {
/* istanbul ignore if */
if (err) {
return reject(err)
}
resolve(module)
resolve(m)
})
// If module send back a promise
if (result && result.then instanceof Function) {
@ -146,5 +149,6 @@ export default class ModuleContainer extends Tapable {
return resolve(module)
}
})
await this.applyPluginsAsync('module', { meta: module.meta, module: m })
}
}

View File

@ -12,10 +12,10 @@ const debug = Debug('nuxt:')
debug.color = 5
export default class Nuxt extends Tapable {
constructor (_options = {}) {
constructor(options = {}) {
super()
this.options = Options.from(_options)
this.options = Options.from(options)
// Paths for resolving requires from `rootDir`
this.nodeModulePaths = Module._nodeModulePaths(this.options.rootDir)
@ -35,20 +35,20 @@ export default class Nuxt extends Tapable {
this._ready = this.ready().catch(this.errorHandler)
}
async ready () {
async ready() {
if (this._ready) {
return this._ready
}
await this.moduleContainer._ready()
await this.moduleContainer.ready()
await this.applyPluginsAsync('ready')
await this.renderer._ready()
await this.renderer.ready()
this.initialized = true
return this
}
listen (port = 3000, host = 'localhost') {
listen(port = 3000, host = 'localhost') {
return new Promise((resolve, reject) => {
const server = this.renderer.app.listen({ port, host, exclusive: false }, err => {
/* istanbul ignore if */
@ -81,7 +81,7 @@ export default class Nuxt extends Tapable {
})
}
errorHandler /* istanbul ignore next */() {
errorHandler/* istanbul ignore next */() {
// Apply plugins
// eslint-disable-next-line no-console
this.applyPluginsAsync('error', ...arguments).catch(console.error)
@ -101,7 +101,7 @@ export default class Nuxt extends Tapable {
console.error(...arguments)
}
resolvePath (path) {
resolvePath(path) {
// Try to resolve using NPM resolve path first
try {
let resolvedPath = Module._resolveFilename(path, { paths: this.nodeModulePaths })
@ -118,7 +118,7 @@ export default class Nuxt extends Tapable {
return resolve(this.options.srcDir, path)
}
async close (callback) {
async close(callback) {
await this.applyPluginsAsync('close')
/* istanbul ignore if */

View File

@ -25,7 +25,7 @@ setAnsiColors(ansiHTML)
let jsdom = null
export default class Renderer extends Tapable {
constructor (nuxt) {
constructor(nuxt) {
super()
this.nuxt = nuxt
this.options = nuxt.options
@ -49,11 +49,12 @@ export default class Renderer extends Tapable {
spaTemplate: null,
errorTemplate: parseTemplate('Nuxt.js Internal Server Error')
}
// Call class hook
this.nuxt.applyPlugins('renderer', this)
}
async _ready () {
await this.nuxt.applyPluginsAsync('renderer', this)
async ready() {
// Setup nuxt middleware
await this.setupMiddleware()
@ -63,10 +64,10 @@ export default class Renderer extends Tapable {
}
// Call ready plugin
await this.applyPluginsAsync('ready', this)
await this.applyPluginsAsync('ready')
}
async loadResources (_fs = fs) {
async loadResources(_fs = fs) {
let distPath = resolve(this.options.buildDir, 'dist')
let updated = []
@ -115,11 +116,11 @@ export default class Renderer extends Tapable {
}
}
get noSSR () {
get noSSR() {
return this.options.render.ssr === false
}
get isReady () {
get isReady() {
if (this.noSSR) {
return Boolean(this.resources.spaTemplate)
}
@ -127,7 +128,7 @@ export default class Renderer extends Tapable {
return Boolean(this.bundleRenderer && this.resources.ssrTemplate)
}
get isResourcesAvailable () {
get isResourcesAvailable() {
// Required for both
if (!this.resources.clientManifest) {
return false
@ -142,7 +143,7 @@ export default class Renderer extends Tapable {
return Boolean(this.resources.ssrTemplate && this.resources.serverBundle)
}
createRenderer () {
createRenderer() {
// Ensure resources are available
if (!this.isResourcesAvailable) {
return
@ -164,7 +165,7 @@ export default class Renderer extends Tapable {
}, this.options.render.bundleRenderer))
}
useMiddleware (m) {
useMiddleware(m) {
// Resolve
const $m = m
let src
@ -188,11 +189,11 @@ export default class Renderer extends Tapable {
this.app.use(path, handler)
}
get publicPath () {
get publicPath() {
return isUrl(this.options.build.publicPath) ? Options.defaults.build.publicPath : this.options.build.publicPath
}
async setupMiddleware () {
async setupMiddleware() {
// Apply setupMiddleware from modules first
await this.applyPluginsAsync('setupMiddleware', this.app)
@ -229,7 +230,7 @@ export default class Renderer extends Tapable {
if (this.options.debug) {
this.useMiddleware({
path: '_open',
handler (req, res) {
handler(req, res) {
// Lazy load open-in-editor
const openInEditor = require('open-in-editor')
const editor = openInEditor.configure(_this.options.editor)
@ -280,9 +281,10 @@ export default class Renderer extends Tapable {
this.useMiddleware(this.errorMiddleware.bind(this))
}
async nuxtMiddleware (req, res, next) {
async nuxtMiddleware(req, res, next) {
// Get context
const context = getContext(req, res)
res.statusCode = 200
try {
const { html, error, redirected, resourceHints } = await this.renderRoute(req.url, context)
@ -338,7 +340,7 @@ export default class Renderer extends Tapable {
}
}
errorMiddleware (err, req, res, next) {
errorMiddleware(err, req, res, next) {
// ensure statusCode, message and name fields
err.statusCode = err.statusCode || 500
err.message = err.message || 'Nuxt Server Error'
@ -390,7 +392,7 @@ export default class Renderer extends Tapable {
}
}
async readSource (frame) {
async readSource(frame) {
const serverBundle = this.resources.serverBundle
// Remove webpack:/// & query string from the end
@ -468,7 +470,7 @@ export default class Renderer extends Tapable {
}
}
async renderRoute (url, context = {}) {
async renderRoute(url, context = {}) {
/* istanbul ignore if */
if (!this.isReady) {
return new Promise(resolve => {
@ -546,7 +548,7 @@ export default class Renderer extends Tapable {
}
}
async renderAndGetWindow (url, opts = {}) {
async renderAndGetWindow(url, opts = {}) {
/* istanbul ignore if */
if (!jsdom) {
try {
@ -561,10 +563,9 @@ export default class Renderer extends Tapable {
let options = {
resources: 'usable', // load subresources (https://github.com/tmpvar/jsdom#loading-subresources)
runScripts: 'dangerously',
beforeParse (window) {
beforeParse(window) {
// Mock window.scrollTo
window.scrollTo = () => {
}
window.scrollTo = () => {}
}
}
if (opts.virtualConsole !== false) {