mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-27 08:02:01 +00:00
refacto: Hooks
This commit is contained in:
parent
83815de91b
commit
6648695015
@ -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'),
|
||||
|
@ -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 {
|
||||
|
@ -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 })
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user