mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-23 14:15:13 +00:00
Hooks ready to be tested
This commit is contained in:
parent
f72e620d7d
commit
94ad5955e6
@ -6,7 +6,6 @@ import pify from 'pify'
|
||||
import webpack from 'webpack'
|
||||
import serialize from 'serialize-javascript'
|
||||
import { join, resolve, basename, extname, dirname } from 'path'
|
||||
import Tapable from 'tappable'
|
||||
import MFS from 'memory-fs'
|
||||
import webpackDevMiddleware from 'webpack-dev-middleware'
|
||||
import webpackHotMiddleware from 'webpack-hot-middleware'
|
||||
@ -24,9 +23,8 @@ debug.color = 2 // Force green color
|
||||
|
||||
const glob = pify(Glob)
|
||||
|
||||
export default class Builder extends Tapable {
|
||||
export default class Builder {
|
||||
constructor(nuxt) {
|
||||
super()
|
||||
this.nuxt = nuxt
|
||||
this.isStatic = false // Flag to know if the build is for a generated app
|
||||
this.options = nuxt.options
|
||||
@ -57,9 +55,6 @@ 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() {
|
||||
@ -121,8 +116,8 @@ export default class Builder extends Tapable {
|
||||
// Wait for nuxt ready
|
||||
await this.nuxt.ready()
|
||||
|
||||
// Wait for build plugins
|
||||
await this.applyPluginsAsync('build', this.options.build)
|
||||
// Call before hook
|
||||
await this.nuxt.callHook('build:before', this, this.options.build)
|
||||
|
||||
// Babel options
|
||||
this.babelOptions = _.defaults(this.options.build.babel, {
|
||||
@ -183,7 +178,8 @@ export default class Builder extends Tapable {
|
||||
// Flag to set that building is done
|
||||
this._buildStatus = STATUS.BUILD_DONE
|
||||
|
||||
await this.applyPluginsAsync('built')
|
||||
// Call done hook
|
||||
await this.nuxt.callHook('build:done', this)
|
||||
|
||||
return this
|
||||
}
|
||||
@ -267,7 +263,7 @@ export default class Builder extends Tapable {
|
||||
templateVars.router.routes = this.options.build.createRoutes(this.options.srcDir)
|
||||
}
|
||||
|
||||
await this.applyPluginsAsync('extendRoutes', templateVars.router.routes)
|
||||
await this.nuxt.callHook('build:extendRoutes', templateVars.router.routes, r)
|
||||
|
||||
// router.extendRoutes method
|
||||
if (typeof this.options.router.extendRoutes === 'function') {
|
||||
@ -335,7 +331,7 @@ export default class Builder extends Tapable {
|
||||
}
|
||||
}
|
||||
|
||||
await this.applyPluginsAsync('generate', { templatesFiles, templateVars, resolve: r })
|
||||
await this.nuxt.callHook('build:templates', { templatesFiles, templateVars, resolve: r })
|
||||
|
||||
// Interpret and move template files to .nuxt/
|
||||
await Promise.all(templatesFiles.map(async ({ src, dst, options, custom }) => {
|
||||
@ -374,8 +370,6 @@ export default class Builder extends Tapable {
|
||||
const dateFS = Date.now() / 1000 - 1000
|
||||
return utimes(path, dateFS, dateFS)
|
||||
}))
|
||||
|
||||
await this.applyPluginsAsync('generated')
|
||||
}
|
||||
|
||||
async webpackBuild() {
|
||||
@ -436,11 +430,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', { name, compiler })
|
||||
await this.nuxt.callHook('build:compile', { name, compiler })
|
||||
|
||||
// Resolve only when compiler emit done event
|
||||
compiler.plugin('done', async (stats) => {
|
||||
await this.applyPluginsAsync('compiled', { name, compiler, stats })
|
||||
await this.nuxt.callHook('build:compiled', { name, compiler, stats })
|
||||
process.nextTick(resolve)
|
||||
})
|
||||
// --- Dev Build ---
|
||||
@ -511,7 +505,7 @@ export default class Builder extends Tapable {
|
||||
}
|
||||
|
||||
// Stop webpack middleware on nuxt.close()
|
||||
this.nuxt.plugin('close', () => new Promise(resolve => {
|
||||
this.nuxt.hook('close', () => new Promise(resolve => {
|
||||
this.webpackDevMiddleware.close(() => resolve())
|
||||
}))
|
||||
|
||||
@ -548,7 +542,7 @@ export default class Builder extends Tapable {
|
||||
.on('change', refreshFiles)
|
||||
|
||||
// Stop watching on nuxt.close()
|
||||
this.nuxt.plugin('close', () => {
|
||||
this.nuxt.hook('close', () => {
|
||||
filesWatcher.close()
|
||||
customFilesWatcher.close()
|
||||
})
|
||||
|
@ -2,15 +2,13 @@ import { copy, remove, writeFile, mkdirp, removeSync, existsSync } from 'fs-extr
|
||||
import _ from 'lodash'
|
||||
import { resolve, join, dirname, sep } from 'path'
|
||||
import { minify } from 'html-minifier'
|
||||
import Tapable from 'tappable'
|
||||
import { isUrl, promisifyRoute, waitFor, flatRoutes } from 'utils'
|
||||
import Debug from 'debug'
|
||||
|
||||
const debug = Debug('nuxt:generate')
|
||||
|
||||
export default class Generator extends Tapable {
|
||||
export default class Generator {
|
||||
constructor(nuxt, builder) {
|
||||
super()
|
||||
this.nuxt = nuxt
|
||||
this.options = nuxt.options
|
||||
this.builder = builder
|
||||
@ -20,28 +18,26 @@ 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 } = {}) {
|
||||
// Wait for nuxt be ready
|
||||
await this.nuxt.ready()
|
||||
|
||||
// Call before hook
|
||||
await this.nuxt.callHook('generate:before', this, this.options.generate)
|
||||
|
||||
const s = Date.now()
|
||||
let errors = []
|
||||
|
||||
// Add flag to set process.static
|
||||
this.builder.forGenerate()
|
||||
|
||||
// Wait for nuxt be ready
|
||||
await this.nuxt.ready()
|
||||
|
||||
// Start build process
|
||||
if (build) {
|
||||
await this.builder.build()
|
||||
}
|
||||
|
||||
await this.nuxt.applyPluginsAsync('generator', this)
|
||||
|
||||
// Initialize dist directory
|
||||
if (init) {
|
||||
await this.initDist()
|
||||
@ -63,7 +59,8 @@ 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', routes)
|
||||
// extendRoutes hook
|
||||
await this.nuxt.callHook('generate:extendRoutes', routes)
|
||||
|
||||
// Start generate process
|
||||
while (routes.length) {
|
||||
@ -87,7 +84,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)
|
||||
// done hook
|
||||
await this.nuxt.callHook('generate:done', this, errors)
|
||||
|
||||
if (errors.length) {
|
||||
const report = errors.map(({ type, route, error }) => {
|
||||
|
@ -291,6 +291,7 @@ Options.defaults = {
|
||||
editor: {
|
||||
editor: 'code'
|
||||
},
|
||||
hooks: () => {},
|
||||
messages: {
|
||||
error_404: 'This page could not be found',
|
||||
server_error: 'Server error',
|
||||
|
@ -2,27 +2,24 @@ import path from 'path'
|
||||
import fs from 'fs'
|
||||
import { uniq } from 'lodash'
|
||||
import hash from 'hash-sum'
|
||||
import Tapable from 'tappable'
|
||||
import { chainFn, sequence } from 'utils'
|
||||
import Debug from 'debug'
|
||||
|
||||
const debug = Debug('nuxt:module')
|
||||
|
||||
export default class ModuleContainer extends Tapable {
|
||||
export default class ModuleContainer {
|
||||
constructor(nuxt) {
|
||||
super()
|
||||
this.nuxt = nuxt
|
||||
this.options = nuxt.options
|
||||
this.requiredModules = []
|
||||
|
||||
// Call class hook
|
||||
this.nuxt.applyPlugins('moduleContainer', this)
|
||||
}
|
||||
|
||||
async ready() {
|
||||
this.nuxt.callHook('modules:before', this, this.options.modules)
|
||||
// Load every module in sequence
|
||||
await sequence(this.options.modules, this.addModule.bind(this))
|
||||
await this.applyPluginsAsync('ready')
|
||||
// Call done hook
|
||||
await this.nuxt.callHook('modules:done', this)
|
||||
}
|
||||
|
||||
addVendor(vendor) {
|
||||
@ -102,42 +99,43 @@ export default class ModuleContainer extends Tapable {
|
||||
|
||||
// Allows passing runtime options to each module
|
||||
const options = moduleOpts.options || (typeof moduleOpts === 'object' ? moduleOpts : {})
|
||||
const originalSrc = moduleOpts.src || moduleOpts
|
||||
const src = moduleOpts.src || moduleOpts
|
||||
|
||||
// Resolve module
|
||||
let module = originalSrc
|
||||
if (typeof module === 'string') {
|
||||
module = require(this.nuxt.resolvePath(module))
|
||||
let module
|
||||
if (typeof src === 'string') {
|
||||
module = require(this.nuxt.resolvePath(src))
|
||||
}
|
||||
|
||||
// Validate module
|
||||
/* istanbul ignore if */
|
||||
if (typeof module !== 'function') {
|
||||
throw new Error(`[nuxt] Module ${JSON.stringify(originalSrc)} should export a function`)
|
||||
throw new Error(`[nuxt] Module ${JSON.stringify(src)} should export a function`)
|
||||
}
|
||||
|
||||
// Module meta
|
||||
if (!module.meta) {
|
||||
module.meta = {}
|
||||
}
|
||||
if (module.meta.name) {
|
||||
const alreadyRequired = this.requiredModules.indexOf(module.meta.name) !== -1
|
||||
module.meta = module.meta || {}
|
||||
let name = module.meta.name || module.name
|
||||
|
||||
// If requireOnce specified & module from NPM or with specified name
|
||||
if (requireOnce && name) {
|
||||
const alreadyRequired = this.requiredModules.indexOf(name) !== -1
|
||||
if (requireOnce && alreadyRequired) {
|
||||
return
|
||||
}
|
||||
if (!alreadyRequired) {
|
||||
this.requiredModules.push(module.meta.name)
|
||||
this.requiredModules.push(name)
|
||||
}
|
||||
}
|
||||
|
||||
// Call module with `this` context and pass options
|
||||
const m = await new Promise((resolve, reject) => {
|
||||
const result = module.call(this, options, (err, m) => {
|
||||
await new Promise((resolve, reject) => {
|
||||
const result = module.call(this, options, (err) => {
|
||||
/* istanbul ignore if */
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
resolve(m)
|
||||
resolve()
|
||||
})
|
||||
// If module send back a promise
|
||||
if (result && result.then instanceof Function) {
|
||||
@ -145,9 +143,8 @@ export default class ModuleContainer extends Tapable {
|
||||
}
|
||||
// If not expecting a callback but returns no promise (=synchronous)
|
||||
if (module.length < 2) {
|
||||
return resolve(module)
|
||||
return resolve()
|
||||
}
|
||||
})
|
||||
await this.applyPluginsAsync('module', { meta: module.meta, module: m })
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Tapable from 'tappable'
|
||||
import chalk from 'chalk'
|
||||
import { Options } from 'common'
|
||||
import { sequence } from 'utils'
|
||||
import ModuleContainer from './module'
|
||||
import Renderer from './renderer'
|
||||
import Debug from 'debug'
|
||||
@ -11,10 +11,8 @@ import { join, resolve } from 'path'
|
||||
const debug = Debug('nuxt:')
|
||||
debug.color = 5
|
||||
|
||||
export default class Nuxt extends Tapable {
|
||||
export default class Nuxt {
|
||||
constructor(options = {}) {
|
||||
super()
|
||||
|
||||
this.options = Options.from(options)
|
||||
|
||||
// Paths for resolving requires from `rootDir`
|
||||
@ -22,6 +20,9 @@ export default class Nuxt extends Tapable {
|
||||
|
||||
this.initialized = false
|
||||
this.errorHandler = this.errorHandler.bind(this)
|
||||
// Hooks
|
||||
this._hooks = {}
|
||||
this.hook = this.hook.bind(this)
|
||||
|
||||
// Create instance of core components
|
||||
this.moduleContainer = new ModuleContainer(this)
|
||||
@ -40,17 +41,35 @@ export default class Nuxt extends Tapable {
|
||||
return this._ready
|
||||
}
|
||||
|
||||
// Call hooks
|
||||
if (typeof this.options.hooks === 'function') {
|
||||
this.options.hooks(this.hook)
|
||||
}
|
||||
// Add nuxt modules
|
||||
await this.moduleContainer.ready()
|
||||
await this.applyPluginsAsync('ready')
|
||||
await this.renderer.ready()
|
||||
|
||||
this.initialized = true
|
||||
await this.callHook('ready', this)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
hook(name, fn) {
|
||||
this._hooks[name] = this._hooks[name] || []
|
||||
this._hooks[name].push(fn)
|
||||
}
|
||||
|
||||
async callHook(name, ...args) {
|
||||
if (!this._hooks[name]) {
|
||||
return
|
||||
}
|
||||
await sequence(this._hooks[name], (fn) => fn(...args))
|
||||
}
|
||||
|
||||
listen(port = 3000, host = 'localhost') {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = this.renderer.app.listen({ port, host, exclusive: false }, err => {
|
||||
const server = this.renderer.app.listen({ port, host, exclusive: false }, (err) => {
|
||||
/* istanbul ignore if */
|
||||
if (err) {
|
||||
return reject(err)
|
||||
@ -61,7 +80,7 @@ export default class Nuxt extends Tapable {
|
||||
console.log('\n' + chalk.bgGreen.black(' OPEN ') + chalk.green(` http://${_host}:${port}\n`))
|
||||
|
||||
// Close server on nuxt close
|
||||
this.plugin('close', () => new Promise((resolve, reject) => {
|
||||
this.hook('close', () => new Promise((resolve, reject) => {
|
||||
// Destroy server by forcing every connection to be closed
|
||||
server.destroy(err => {
|
||||
debug('server closed')
|
||||
@ -73,7 +92,7 @@ export default class Nuxt extends Tapable {
|
||||
})
|
||||
}))
|
||||
|
||||
resolve(this.applyPluginsAsync('listen', { server, port, host }))
|
||||
this.callHook('listen', server, { port, host }).then(resolve)
|
||||
})
|
||||
|
||||
// Add server.destroy(cb) method
|
||||
@ -84,7 +103,7 @@ 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)
|
||||
this.callHook('error', ...arguments).catch(console.error)
|
||||
|
||||
// Silent
|
||||
if (this.options.errorHandler === false) {
|
||||
@ -119,7 +138,7 @@ export default class Nuxt extends Tapable {
|
||||
}
|
||||
|
||||
async close(callback) {
|
||||
await this.applyPluginsAsync('close')
|
||||
await this.callHook('close', this)
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (typeof callback === 'function') {
|
||||
|
@ -2,7 +2,6 @@ import ansiHTML from 'ansi-html'
|
||||
import serialize from 'serialize-javascript'
|
||||
import generateETag from 'etag'
|
||||
import fresh from 'fresh'
|
||||
import Tapable from 'tappable'
|
||||
import serveStatic from 'serve-static'
|
||||
import compression from 'compression'
|
||||
import _ from 'lodash'
|
||||
@ -24,9 +23,8 @@ setAnsiColors(ansiHTML)
|
||||
|
||||
let jsdom = null
|
||||
|
||||
export default class Renderer extends Tapable {
|
||||
export default class Renderer {
|
||||
constructor(nuxt) {
|
||||
super()
|
||||
this.nuxt = nuxt
|
||||
this.options = nuxt.options
|
||||
|
||||
@ -49,12 +47,10 @@ 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.callHook('render:before', this, this.options.render)
|
||||
// Setup nuxt middleware
|
||||
await this.setupMiddleware()
|
||||
|
||||
@ -63,8 +59,8 @@ export default class Renderer extends Tapable {
|
||||
await this.loadResources()
|
||||
}
|
||||
|
||||
// Call ready plugin
|
||||
await this.applyPluginsAsync('ready')
|
||||
// Call done hook
|
||||
await this.nuxt.callHook('render:done', this)
|
||||
}
|
||||
|
||||
async loadResources(_fs = fs) {
|
||||
@ -109,7 +105,7 @@ export default class Renderer extends Tapable {
|
||||
}
|
||||
|
||||
// Call resourcesLoaded plugin
|
||||
await this.applyPluginsAsync('resourcesLoaded', this.resources)
|
||||
await this.nuxt.callHook('render:resourcesLoaded', this.resources)
|
||||
|
||||
if (updated.length > 0) {
|
||||
this.createRenderer()
|
||||
@ -195,7 +191,7 @@ export default class Renderer extends Tapable {
|
||||
|
||||
async setupMiddleware() {
|
||||
// Apply setupMiddleware from modules first
|
||||
await this.applyPluginsAsync('setupMiddleware', this.app)
|
||||
await this.nuxt.callHook('render:setupMiddleware', this.app)
|
||||
|
||||
// Gzip middleware for production
|
||||
if (!this.options.dev && this.options.render.gzip) {
|
||||
|
@ -107,7 +107,6 @@
|
||||
"server-destroy": "^1.0.1",
|
||||
"source-map": "^0.6.1",
|
||||
"source-map-support": "^0.5.0",
|
||||
"tappable": "^1.1.0",
|
||||
"uglifyjs-webpack-plugin": "^1.0.1",
|
||||
"url-loader": "^0.6.2",
|
||||
"vue": "^2.5.2",
|
||||
|
@ -2,17 +2,17 @@ module.exports = function () {
|
||||
let ctr = 1
|
||||
|
||||
// Add hook for module
|
||||
this.plugin('ready', moduleContainer => {
|
||||
this.plugin('modules:done', (moduleContainer) => {
|
||||
this.nuxt.__module_hook = moduleContainer && ctr++
|
||||
})
|
||||
|
||||
// Add hook for renderer
|
||||
this.nuxt.plugin('renderer', renderer => {
|
||||
this.nuxt.hook('render:done', (renderer) => {
|
||||
this.nuxt.__renderer_hook = renderer && ctr++
|
||||
})
|
||||
|
||||
// Add hook for build
|
||||
this.nuxt.plugin('build', builder => {
|
||||
this.nuxt.plugin('build:done', (builder) => {
|
||||
this.nuxt.__builder_hook = builder && ctr++
|
||||
})
|
||||
}
|
2
test/fixtures/module/nuxt.config.js
vendored
2
test/fixtures/module/nuxt.config.js
vendored
@ -2,7 +2,7 @@ module.exports = {
|
||||
loading: true,
|
||||
modules: [
|
||||
'~/modules/basic',
|
||||
'~/modules/tapable',
|
||||
'~/modules/hooks',
|
||||
{
|
||||
src: '~/modules/middleware',
|
||||
options: {
|
||||
|
@ -36,7 +36,7 @@ test('Middleware', async t => {
|
||||
t.is(response, 'It works!', '/api response is correct')
|
||||
})
|
||||
|
||||
test('Tapable', async t => {
|
||||
test('Hooks', async t => {
|
||||
t.is(nuxt.__module_hook, 1)
|
||||
t.is(nuxt.__renderer_hook, 2)
|
||||
t.is(nuxt.__builder_hook, 3)
|
||||
|
@ -6488,17 +6488,10 @@ table@^4.0.1:
|
||||
slice-ansi "1.0.0"
|
||||
string-width "^2.1.1"
|
||||
|
||||
tapable@^0.2.6, tapable@^0.2.7:
|
||||
tapable@^0.2.7:
|
||||
version "0.2.8"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
|
||||
|
||||
tappable@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tappable/-/tappable-1.1.0.tgz#521770dea7dc4715d48ddb4c471071afee012025"
|
||||
dependencies:
|
||||
pify "^3.0.0"
|
||||
tapable "^0.2.6"
|
||||
|
||||
tar-pack@^3.4.0:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f"
|
||||
|
Loading…
Reference in New Issue
Block a user