diff --git a/bin/nuxt-build b/bin/nuxt-build index 53393a42ea..19276e72ca 100755 --- a/bin/nuxt-build +++ b/bin/nuxt-build @@ -6,7 +6,7 @@ process.env.DEBUG = process.env.DEBUG || 'nuxt:*' const fs = require('fs') const parseArgs = require('minimist') -const { Nuxt, Builder, Generator } = require('../') +const { Nuxt, Builder, Generator, Utils } = require('../') const resolve = require('path').resolve const debug = require('debug')('nuxt:build') debug.color = 2 // Force green color @@ -49,8 +49,7 @@ var options = {} if (fs.existsSync(nuxtConfigFile)) { options = require(nuxtConfigFile) } else if (argv['config-file'] !== 'nuxt.config.js') { - console.error(`> Could not load config file ${argv['config-file']}`) - process.exit(1) + Utils.fatalError(`Could not load config file`, argv['config-file']) } if (typeof options.rootDir !== 'string') { options.rootDir = rootDir @@ -59,7 +58,8 @@ if (typeof options.rootDir !== 'string') { options.dev = false // Nuxt Mode -options.mode = (argv['spa'] && 'spa') || (argv['universal'] && 'universal') || options.mode +options.mode = + (argv['spa'] && 'spa') || (argv['universal'] && 'universal') || options.mode // Analyze option options.build = options.build || {} @@ -71,11 +71,15 @@ debug('Building...') const nuxt = new Nuxt(options) const builder = new Builder(nuxt) +// Setup hooks +nuxt.hook('error', (_err, from) => Utils.fatalError(_err, from)) + if (options.mode !== 'spa') { // Build for SSR app - builder.build() + builder + .build() .then(() => debug('Building done')) - .catch((err) => { + .catch(err => { console.error(err) process.exit(1) }) @@ -108,7 +112,7 @@ if (options.mode !== 'spa') { return `Route: '${route}' thrown an error: \n` + JSON.stringify(error) } }) - console.error('==== Error report ==== \n' + report.join('\n\n')) // eslint-disable-line no-console + Utils.printError(report.join('\n\n'), 'Generate errors') } }) @@ -116,8 +120,6 @@ if (options.mode !== 'spa') { nuxt.options.generate.minify = false // Generate on spa mode new Generator(nuxt, builder).generate({ build: true }).then(() => { - if (!nuxt.options.dev) { - console.log(`✓ You can now directly upload ${nuxt.options.generate.dir}/ or start server using "nuxt start"`) - } + process.exit(0) }) } diff --git a/bin/nuxt-dev b/bin/nuxt-dev index 28266f1e92..e118d5c245 100755 --- a/bin/nuxt-dev +++ b/bin/nuxt-dev @@ -9,7 +9,7 @@ const debug = require('debug')('nuxt:build') debug.color = 2 // force green color const fs = require('fs') const parseArgs = require('minimist') -const { Nuxt, Builder } = require('../') +const { Nuxt, Builder, Utils } = require('../') const chokidar = require('chokidar') const path = require('path') const resolve = path.resolve @@ -38,8 +38,7 @@ if (argv.version) { } if (argv.hostname === '') { - console.error(`> Provided hostname argument has no value`) - process.exit(1) + Utils.fatalError('Provided hostname argument has no value') } if (argv.help) { @@ -72,29 +71,31 @@ let dev = startDev() let needToRestart = false // Start watching for nuxt.config.js changes -chokidar - .watch(nuxtConfigFile, nuxtConfig.watchers.chokidar) - .on('all', () => { - debug('[nuxt.config.js] changed') - needToRestart = true +chokidar.watch(nuxtConfigFile, nuxtConfig.watchers.chokidar).on('all', () => { + debug('[nuxt.config.js] changed') + needToRestart = true - dev = dev.then((instance) => { - if (needToRestart === false) return instance - needToRestart = false + dev = dev.then(instance => { + if (needToRestart === false) return instance + needToRestart = false - debug('Rebuilding the app...') - return startDev(instance) - }) + debug('Rebuilding the app...') + return startDev(instance) }) +}) function startDev(oldInstance) { // Get latest environment variables - const port = argv.port || process.env.PORT || process.env.npm_package_config_nuxt_port - const host = argv.hostname || process.env.HOST || process.env.npm_package_config_nuxt_host + const port = + argv.port || process.env.PORT || process.env.npm_package_config_nuxt_port + const host = + argv.hostname || + process.env.HOST || + process.env.npm_package_config_nuxt_host // Error handler const onError = (err, instance) => { - debug('Error while reloading [nuxt.config.js]', err) + Utils.printError(err) return Promise.resolve(instance) // Wait for next reload } @@ -118,18 +119,30 @@ function startDev(oldInstance) { return onError(err, instance || oldInstance) } - return Promise.resolve() - .then(() => oldInstance && oldInstance.builder ? oldInstance.builder.unwatch() : Promise.resolve()) - // Start build - .then(() => builder.build()) - // Close old nuxt after successful build - .then(() => oldInstance && oldInstance.nuxt ? oldInstance.nuxt.close() : Promise.resolve()) - // Start listening - .then(() => nuxt.listen(port, host)) - // Pass new nuxt to watch chain - .then(() => instance) - // Handle errors - .catch((err) => onError(err, instance)) + return ( + Promise.resolve() + .then( + () => + oldInstance && oldInstance.builder + ? oldInstance.builder.unwatch() + : Promise.resolve() + ) + // Start build + .then(() => builder.build()) + // Close old nuxt after successful build + .then( + () => + oldInstance && oldInstance.nuxt + ? oldInstance.nuxt.close() + : Promise.resolve() + ) + // Start listening + .then(() => nuxt.listen(port, host)) + // Pass new nuxt to watch chain + .then(() => instance) + // Handle errors + .catch(err => onError(err, instance)) + ) } function loadNuxtConfig() { @@ -139,8 +152,7 @@ function loadNuxtConfig() { delete require.cache[nuxtConfigFile] options = require(nuxtConfigFile) } else if (argv['config-file'] !== 'nuxt.config.js') { - console.error(`> Could not load config file ${argv['config-file']}`) - process.exit(1) + Utils.fatalError('Could not load config file: ' + argv['config-file']) } if (typeof options.rootDir !== 'string') { @@ -151,7 +163,8 @@ function loadNuxtConfig() { options.dev = true // Nuxt Mode - options.mode = (argv['spa'] && 'spa') || (argv['universal'] && 'universal') || options.mode + options.mode = + (argv['spa'] && 'spa') || (argv['universal'] && 'universal') || options.mode return options } diff --git a/bin/nuxt-generate b/bin/nuxt-generate index 44a0b03cf2..7f9b7f47f8 100755 --- a/bin/nuxt-generate +++ b/bin/nuxt-generate @@ -8,7 +8,7 @@ const fs = require('fs') const parseArgs = require('minimist') const debug = require('debug')('nuxt:generate') -const { Nuxt, Builder, Generator } = require('../') +const { Nuxt, Builder, Generator, Utils } = require('../') const resolve = require('path').resolve const argv = parseArgs(process.argv.slice(2), { @@ -49,8 +49,7 @@ var options = {} if (fs.existsSync(nuxtConfigFile)) { options = require(nuxtConfigFile) } else if (argv['config-file'] !== 'nuxt.config.js') { - console.error(`> Could not load config file ${argv['config-file']}`) - process.exit(1) + Utils.fatalError('Could not load config file: ' + argv['config-file']) } if (typeof options.rootDir !== 'string') { options.rootDir = rootDir @@ -58,7 +57,8 @@ if (typeof options.rootDir !== 'string') { options.dev = false // Force production mode (no webpack middleware called) // Nuxt Mode -options.mode = (argv['spa'] && 'spa') || (argv['universal'] && 'universal') || options.mode +options.mode = + (argv['spa'] && 'spa') || (argv['universal'] && 'universal') || options.mode debug('Generating...') const nuxt = new Nuxt(options) @@ -72,19 +72,17 @@ const generateOptions = { const s = Date.now() -nuxt.hook('generate:distRemoved', function () { - debug('Destination folder cleaned') -}) +// Setup hooks -nuxt.hook('generate:distCopied', function () { - debug('Static & build files copied') -}) +nuxt.hook('error', (_err, from) => Utils.fatalError(_err, from)) -nuxt.hook('generate:page', function (page) { - debug('Generate file: ' + page.path) -}) +nuxt.hook('generate:distRemoved', () => debug('Destination folder cleaned')) -nuxt.hook('generate:done', function (generator, errors) { +nuxt.hook('generate:distCopied', () => debug('Static & build files copied')) + +nuxt.hook('generate:page', page => debug('Generate file: ' + page.path)) + +nuxt.hook('generate:done', (generator, errors) => { const duration = Math.round((Date.now() - s) / 100) / 10 debug(`HTML Files generated in ${duration}s`) @@ -98,16 +96,16 @@ nuxt.hook('generate:done', function (generator, errors) { return `Route: '${route}' thrown an error: \n` + JSON.stringify(error) } }) - console.error('==== Error report ==== \n' + report.join('\n\n')) // eslint-disable-line no-console + Utils.printError(report.join('\n\n'), 'generate') } }) -generator.generate(generateOptions) +generator + .generate(generateOptions) .then(() => { debug('Generate done') process.exit(0) }) - .catch((err) => { - console.error(err) - process.exit(1) + .catch(err => { + Utils.fatalError(err) }) diff --git a/bin/nuxt-start b/bin/nuxt-start index cc18b1dada..f4d85a8abb 100755 --- a/bin/nuxt-start +++ b/bin/nuxt-start @@ -3,7 +3,7 @@ const fs = require('fs') const parseArgs = require('minimist') -const { Nuxt } = require('../') +const { Nuxt, Utils } = require('../') const { resolve } = require('path') const argv = parseArgs(process.argv.slice(2), { @@ -23,8 +23,7 @@ const argv = parseArgs(process.argv.slice(2), { }) if (argv.hostname === '') { - console.error(`> Provided hostname argument has no value`) - process.exit(1) + Utils.fatalError('Provided hostname argument has no value') } if (argv.help) { @@ -53,8 +52,7 @@ let options = {} if (fs.existsSync(nuxtConfigFile)) { options = require(nuxtConfigFile) } else if (argv['config-file'] !== 'nuxt.config.js') { - console.error(`> Could not load config file ${argv['config-file']}`) - process.exit(1) + Utils.fatalError('Could not load config file: ' + argv['config-file']) } if (typeof options.rootDir !== 'string') { @@ -65,27 +63,39 @@ if (typeof options.rootDir !== 'string') { options.dev = false // Nuxt Mode -options.mode = (argv['spa'] && 'spa') || (argv['universal'] && 'universal') || options.mode +options.mode = + (argv['spa'] && 'spa') || (argv['universal'] && 'universal') || options.mode const nuxt = new Nuxt(options) +// Setup hooks +nuxt.hook('error', (_err, from) => Utils.fatalError(_err, from)) + // Check if project is built for production -const distDir = resolve(nuxt.options.rootDir, nuxt.options.buildDir || '.nuxt', 'dist') +const distDir = resolve( + nuxt.options.rootDir, + nuxt.options.buildDir || '.nuxt', + 'dist' +) if (!fs.existsSync(distDir)) { - console.error('> No build files found, please run `nuxt build` before launching `nuxt start`') - process.exit(1) + Utils.fatalError( + 'No build files found, please run `nuxt build` before launching `nuxt start`' + ) } // Check if SSR Bundle is required if (nuxt.options.render.ssr === true) { const ssrBundlePath = resolve(distDir, 'server-bundle.json') if (!fs.existsSync(ssrBundlePath)) { - console.error('> No SSR build! Please start with `nuxt start --spa` or build using `nuxt build --universal`') - process.exit(1) + Utils.fatalError( + 'No SSR build! Please start with `nuxt start --spa` or build using `nuxt build --universal`' + ) } } -const port = argv.port || process.env.PORT || process.env.npm_package_config_nuxt_port -const host = argv.hostname || process.env.HOST || process.env.npm_package_config_nuxt_host +const port = + argv.port || process.env.PORT || process.env.npm_package_config_nuxt_port +const host = + argv.hostname || process.env.HOST || process.env.npm_package_config_nuxt_host nuxt.listen(port, host) diff --git a/lib/common/utils.js b/lib/common/utils.js index c3404abecf..849dee4ec5 100644 --- a/lib/common/utils.js +++ b/lib/common/utils.js @@ -15,12 +15,17 @@ exports.printWarn = function (msg, from) { exports.printError = function (_error, from) { /* eslint-disable no-console */ const errStr = pe.render(_error) - const fromStr = from ? Chalk.red(` ${from}\n`) : ' ' + const fromStr = from ? Chalk.red(` ${from}`) : '' - console.error('\n' + Chalk.bgRed.black(' ERROR ') + fromStr) + console.error('\n' + Chalk.bgRed.black(' ERROR ') + fromStr + '\n') console.error(errStr + '\n') } +exports.fatalError = function () { + exports.printError(...arguments) + process.exit(1) +} + exports.encodeHtml = function encodeHtml(str) { return str.replace(//g, '>') } diff --git a/lib/core/module.js b/lib/core/module.js index 78e3a82c2f..1ea7ed6ca1 100755 --- a/lib/core/module.js +++ b/lib/core/module.js @@ -2,7 +2,7 @@ const path = require('path') const fs = require('fs') const { uniq } = require('lodash') const hash = require('hash-sum') -const { chainFn, sequence, printError, printWarn } = require('../common/utils') +const { chainFn, sequence, printWarn } = require('../common/utils') module.exports = class ModuleContainer { constructor(nuxt) { @@ -116,8 +116,7 @@ module.exports = class ModuleContainer { try { handler = require(this.nuxt.resolvePath(src)) } catch (err) { - printError(err) - throw new Error('Error while resolving module: ' + src) + this.nuxt.onError(err, src) } } diff --git a/lib/core/nuxt.js b/lib/core/nuxt.js index cf0a87ad3b..fe35e62b9b 100644 --- a/lib/core/nuxt.js +++ b/lib/core/nuxt.js @@ -18,6 +18,7 @@ module.exports = class Nuxt { this.options = Options.from(options) this.initialized = false + this.onError = this.onError.bind(this) // Hooks this._hooks = {} @@ -28,16 +29,14 @@ module.exports = class Nuxt { this.renderer = new Renderer(this) // Backward compatibility + this.errorHandler = this.onError this.render = this.renderer.app this.renderRoute = this.renderer.renderRoute.bind(this.renderer) this.renderAndGetWindow = this.renderer.renderAndGetWindow.bind( this.renderer ) - this._ready = this.ready().catch(err => { - this.callHook('error', err) - printError(err) - }) + this._ready = this.ready().catch(err => this.onError(err)) } static get version() { @@ -102,6 +101,17 @@ module.exports = class Nuxt { this._hooks[name].push(fn) } + onError(err, from = 'Nuxt error') { + // Log error to the console if there is not any error listener + if (!this._hooks['error']) { + printError(err, from) + return + } + + // Call error hooks + this.callHook('error', err, from) + } + async callHook(name, ...args) { if (!this._hooks[name]) { return @@ -110,7 +120,7 @@ module.exports = class Nuxt { try { await sequence(this._hooks[name], fn => fn(...args)) } catch (err) { - printError(err, name) + this.onError(err, name) } }