Skip to content

Commit

Permalink
Hooks ready to be tested
Browse files Browse the repository at this point in the history
  • Loading branch information
Atinux committed Oct 30, 2017
1 parent f72e620 commit 94ad595
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 87 deletions.
28 changes: 11 additions & 17 deletions lib/builder/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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, {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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') {
Expand Down Expand Up @@ -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 }) => {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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 ---
Expand Down Expand Up @@ -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())
}))

Expand Down Expand Up @@ -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()
})
Expand Down
24 changes: 11 additions & 13 deletions lib/builder/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand All @@ -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) {
Expand All @@ -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 }) => {
Expand Down
1 change: 1 addition & 0 deletions lib/common/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ Options.defaults = {
editor: {
editor: 'code'
},
hooks: () => {},
messages: {
error_404: 'This page could not be found',
server_error: 'Server error',
Expand Down
43 changes: 20 additions & 23 deletions lib/core/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -102,52 +99,52 @@ 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) {
return result.then(resolve)
}
// 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 })
}
}
39 changes: 29 additions & 10 deletions lib/core/nuxt.js
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -11,17 +11,18 @@ 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`
this.nodeModulePaths = Module._nodeModulePaths(this.options.rootDir)

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)
Expand All @@ -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)
Expand All @@ -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')
Expand All @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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') {
Expand Down

0 comments on commit 94ad595

Please sign in to comment.