diff --git a/bin/nuxt-dev b/bin/nuxt-dev index 7e03ce816c..6e742db0ec 100755 --- a/bin/nuxt-dev +++ b/bin/nuxt-dev @@ -49,86 +49,53 @@ if (argv.help) { process.exit(0) } +const config = () => { + // Force development mode for add hot reloading and watching changes + return Object.assign(loadNuxtConfig(argv), { dev: true }) +} + +const errorHandler = (err, instance) => { + instance && instance.builder.watchServer() + consola.error(err) +} + // Start dev -let dev = startDev() +(function startDev(oldInstance) { + let nuxt, builder -function startDev(oldInstance) { - // Error handler - const onError = (err, instance) => { - consola.error(err) - return Promise.resolve(instance) // Wait for next reload - } - - // Load options - let options = {} try { - options = loadAndAugmentNuxtConfig() - } catch (err) { - return onError(err, oldInstance) - } - - // Create nuxt and builder instance - let nuxt - let builder - let instance - try { - nuxt = new Nuxt(options) + nuxt = new Nuxt(config()) builder = new Builder(nuxt) - instance = { nuxt, builder } - } catch (err) { - return onError(err, oldInstance) - } - - nuxt.hook('watch:fileChanged', (fname) => { - consola.debug(`[${fname}] changed`) - - dev = dev.then((instance) => { - consola.debug('Rebuilding the app...') - return startDev(instance) + nuxt.hook('watch:fileChanged', (builder, fname) => { + consola.debug(`[${fname}] changed, Rebuilding the app...`) + startDev({ nuxt: builder.nuxt, builder }) }) - }) + } catch (err) { + return errorHandler(err, oldInstance) + } // Get latest environment variables const { port, host } = nuxt.options.server return ( Promise.resolve() - .then(() => { - if (oldInstance && oldInstance.builder) { - return oldInstance.builder.unwatch() - } else { - return nuxt.listen(port, host) - } - }) + .then(() => oldInstance && oldInstance.nuxt.clearHook('watch:fileChanged')) + .then(() => oldInstance && oldInstance.builder.unwatch()) // Start build .then(() => builder.build()) - // Close old nuxt after successful build - .then( - () => - oldInstance && oldInstance.nuxt - ? oldInstance.nuxt.close() - : Promise.resolve() - ) - // Start listening - .then(() => { - if (oldInstance) { - return nuxt.listen(port, host) - } else { - return Promise.resolve() - } + // Close old nuxt no mater if build successfully + .catch((err) => { + oldInstance && oldInstance.nuxt.close() + // Jump to eventHandler + throw err }) - // Pass new nuxt to watch chain - .then(() => instance) + .then(() => oldInstance && oldInstance.nuxt.close()) + // Start listening + .then(() => nuxt.listen(port, host)) + // Show ready message first time, others will be shown through WebpackBar + .then(() => !oldInstance && nuxt.showReady(false)) + .then(() => builder.watchServer()) // Handle errors - .catch(err => onError(err, instance)) + .catch(err => errorHandler(err, {builder, nuxt})) ) -} - -function loadAndAugmentNuxtConfig() { - const options = loadNuxtConfig(argv) - - // Force development mode for add hot reloading and watching changes - options.dev = true - - return options -} +})() diff --git a/lib/builder/builder.js b/lib/builder/builder.js index b3808135fd..1442466cb9 100644 --- a/lib/builder/builder.js +++ b/lib/builder/builder.js @@ -103,7 +103,7 @@ export default class Builder { consola.info({ message: 'Building project', badge: true, - clear: true + clear: !this.options.dev }) // Wait for nuxt ready @@ -589,11 +589,11 @@ export default class Builder { this.nuxt.renderer.webpackHotMiddleware = this.webpackHotMiddleware } - // Start watching files - this.watchFiles() + // Start watching client files + this.watchClient() } - watchFiles() { + watchClient() { const src = this.options.srcDir let patterns = [ r(src, this.options.dir.layouts), @@ -611,9 +611,7 @@ export default class Builder { } patterns = _.map(patterns, upath.normalizeSafe) - const options = Object.assign({}, this.options.watchers.chokidar, { - ignoreInitial: true - }) + const options = this.options.watchers.chokidar /* istanbul ignore next */ const refreshFiles = _.debounce(() => this.generateRoutesAndFiles(), 200) @@ -632,22 +630,21 @@ export default class Builder { this.watchers.custom = chokidar .watch(customPatterns, options) .on('change', refreshFiles) + } - // Watch for nuxt.config.js and user-defined changes - const restartServer = _.debounce((fname) => { - this.nuxt.callHook('watch:fileChanged', fname) - }) - + watchServer() { const nuxtRestartWatch = _.concat( this.options.serverMiddleware.map(this.nuxt.resolveAlias), this.options.watch.map(this.nuxt.resolveAlias), path.join(this.options.rootDir, 'nuxt.config.js') ) + this.watchers.restart = chokidar - .watch(nuxtRestartWatch, options) + .watch(nuxtRestartWatch, this.options.watchers.chokidar) .on('change', (_path) => { - const parsedPath = path.parse(_path) - restartServer(`${parsedPath.name}${parsedPath.ext}`) + this.watchers.restart.close() + const {name, ext} = path.parse(_path) + this.nuxt.callHook('watch:fileChanged', this, `${name}${ext}`) }) } diff --git a/lib/builder/webpack/base.js b/lib/builder/webpack/base.js index 032f418628..2606d55d05 100644 --- a/lib/builder/webpack/base.js +++ b/lib/builder/webpack/base.js @@ -235,7 +235,7 @@ export default class WebpackBaseConfig { const hasErrors = Object.values(states).some(state => state.stats.hasErrors()) if (!hasErrors) { - this.nuxt.showReady() + this.nuxt.showReady(false) } } } diff --git a/lib/common/nuxt.config.js b/lib/common/nuxt.config.js index 96cad179ca..7da19fbf20 100644 --- a/lib/common/nuxt.config.js +++ b/lib/common/nuxt.config.js @@ -214,7 +214,9 @@ export default { watch: [], watchers: { webpack: {}, - chokidar: {} + chokidar: { + ignoreInitial: true + } }, editor: undefined, hooks: null, diff --git a/lib/core/nuxt.js b/lib/core/nuxt.js index c1c90f6065..0338450e6d 100644 --- a/lib/core/nuxt.js +++ b/lib/core/nuxt.js @@ -99,6 +99,12 @@ export default class Nuxt { } } + clearHook(name) { + if (name) { + delete this._hooks[name] + } + } + addObjectHooks(hooksObj) { Object.keys(hooksObj).forEach((name) => { let hooks = hooksObj[name] @@ -144,7 +150,7 @@ export default class Nuxt { () => new Promise((resolve, reject) => { // Destroy server by forcing every connection to be closed - server.destroy((err) => { + server.listening && server.destroy((err) => { consola.debug('server closed') /* istanbul ignore if */ if (err) {