diff --git a/bin/nuxt-dev b/bin/nuxt-dev index b26fcbe623..419fe79a44 100755 --- a/bin/nuxt-dev +++ b/bin/nuxt-dev @@ -8,7 +8,7 @@ const debug = require('debug')('nuxt:build') debug.color = 2 // force green color const fs = require('fs') const parseArgs = require('minimist') -const { Nuxt, Server, Builder } = require('../') +const { Nuxt, Builder } = require('../') const chokidar = require('chokidar') const resolve = require('path').resolve @@ -50,64 +50,64 @@ if (argv.help) { const rootDir = resolve(argv._[0] || '.') const nuxtConfigFile = resolve(rootDir, argv['config-file']) -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) -} -if (typeof options.rootDir !== 'string') { - options.rootDir = rootDir -} -// Force development mode: add hot reloading and watching changes -options.dev = true +// Load config once for chokidar +const nuxtConfig = loadNuxtConfig() +_.defaultsDeep(nuxtConfig, { watchers: { chokidar: { ignoreInitial: true } } }) -const nuxt = new Nuxt(options) -const builder = new Builder(nuxt) +// Start dev +let dev = startDev() -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 server = new Server(nuxt) -server.listen(port, host) - -builder.build().then(() => { - listenOnConfigChanges(nuxt, server) -}) - -function listenOnConfigChanges (nuxt, server) { - // Listen on nuxt.config.js changes - const build = _.debounce(() => { +// Start watching for nuxt.config.js changes +chokidar + .watch(nuxtConfigFile, nuxtConfig.watchers.chokidar) + .on('all', _.debounce(() => { debug('[nuxt.config.js] changed') - delete require.cache[nuxtConfigFile] - var options = {} - if (fs.existsSync(nuxtConfigFile)) { - try { - options = require(nuxtConfigFile) - } catch (e) { - return console.error(e) // eslint-disable-line no-console - } - } + debug('Rebuilding the app...') + dev = dev.then(startDev) + }), 2500) - if (typeof options.rootDir !== 'string') { - options.rootDir = rootDir - } +function startDev (oldNuxt) { + // 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 - nuxt.close() - .then(() => { - debug('Rebuilding the app...') - const nuxt = new Nuxt(options) - const builder = new Builder(nuxt) - server.nuxt = nuxt - return builder.build() - }) - .catch((error) => { - console.error('Error while rebuild the app:', error) // eslint-disable-line no-console - process.exit(1) - }) - }, 200) - chokidar.watch(nuxtConfigFile, Object.assign({}, nuxt.options.watchers.chokidar, { ignoreInitial: true })) - .on('all', build) + // Load options + let options = {} + try { + options = loadNuxtConfig() + } catch (err) { + console.error(err) + return // Wait for next reload + } + + // Create nuxt and builder instance + const nuxt = new Nuxt(options) + const builder = new Builder(nuxt) + + return Promise.resolve() + .then(() => builder.build()) // 1- Start build + .then(() => oldNuxt ? oldNuxt.close() : Promise.resolve()) // 2- Close old nuxt after successful build + .then(() => nuxt.listen(port, host)) // 3- Start listening + .then(() => nuxt) // 4- Pass new nuxt to watch chain } -module.exports = nuxt +function loadNuxtConfig () { + let options = {} + + if (fs.existsSync(nuxtConfigFile)) { + 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) + } + + if (typeof options.rootDir !== 'string') { + options.rootDir = rootDir + } + + // Force development mode for add hot reloading and watching changes + options.dev = true + + return options +} diff --git a/bin/nuxt-start b/bin/nuxt-start index 97f5818f94..13551694aa 100755 --- a/bin/nuxt-start +++ b/bin/nuxt-start @@ -43,17 +43,21 @@ if (argv.help) { const rootDir = resolve(argv._[0] || '.') const nuxtConfigFile = resolve(rootDir, argv['config-file']) -var options = {} +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) } + if (typeof options.rootDir !== 'string') { options.rootDir = rootDir } -options.dev = false // Force production mode (no webpack middleware called) + +// Force production mode (no webpack middleware called) +options.dev = false // Check if project is built for production const distDir = join(options.rootDir, options.buildDir || '.nuxt', 'dist' ) @@ -65,6 +69,4 @@ if (!fs.existsSync(join(distDir, 'server-bundle.json'))) { const nuxt = new Nuxt(options) 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 -new Server(nuxt).listen(port, host) - -module.exports = nuxt +nuxt.listen(port, host) diff --git a/lib/core/index.js b/lib/core/index.js index 19e55a107e..4bf8a61bf0 100755 --- a/lib/core/index.js +++ b/lib/core/index.js @@ -2,7 +2,6 @@ import Options from './options' import ModuleContainer from './module' import Nuxt from './nuxt' import Renderer from './renderer' -import Server from './server' import * as Utils from 'utils' export default { @@ -10,6 +9,5 @@ export default { ModuleContainer, Nuxt, Renderer, - Server, Utils } diff --git a/lib/core/nuxt.js b/lib/core/nuxt.js index 38b98a5775..f8da1adc69 100644 --- a/lib/core/nuxt.js +++ b/lib/core/nuxt.js @@ -1,7 +1,12 @@ import Tapable from 'tappable' +import chalk from 'chalk' import ModuleContainer from './module' import Renderer from './renderer' import Options from './options' +import Debug from 'debug' + +const debug = Debug('nuxt:') +debug.color = 5 export default class Nuxt extends Tapable { constructor (_options = {}) { @@ -38,6 +43,34 @@ export default class Nuxt extends Tapable { return this } + listen (port = 3000, host = 'localhost') { + return new Promise((resolve, reject) => { + const server = this.renderer.app.listen({ port, host, exclusive: false }, err => { + if (err) { + return reject(err) + } + + // Show Open URL + let _host = host === '0.0.0.0' ? 'localhost' : host + // eslint-disable-next-line no-console + console.log('\n' + chalk.bold(chalk.bgBlue.black(' OPEN ') + chalk.blue(` http://${_host}:${port}\n`))) + + // Close server on nuxt close + this.plugin('close', () => new Promise((_resolve, _reject) => { + server.close(_err => { + debug('server closed') + if (_err) { + return _reject(err) + } + _resolve() + }) + })) + + resolve() + }) + }) + } + errorHandler /* istanbul ignore next */ () { // Silent if (this.options.errorHandler === false) { @@ -54,7 +87,6 @@ export default class Nuxt extends Tapable { } async close (callback) { - // Call for close await this.applyPluginsAsync('close') if (typeof callback === 'function') { diff --git a/lib/core/renderer.js b/lib/core/renderer.js index fff8b2ec70..d6352d738d 100644 --- a/lib/core/renderer.js +++ b/lib/core/renderer.js @@ -21,31 +21,6 @@ setAnsiColors(ansiHTML) let jsdom = null -const parseTemplate = templateStr => _.template(templateStr, { - interpolate: /{{([\s\S]+?)}}/g -}) - -const resourceMap = [ - { - key: 'clientManifest', - fileName: 'vue-ssr-client-manifest.json', - transform: JSON.parse - }, - { - key: 'serverBundle', - fileName: 'server-bundle.json', - transform: JSON.parse - }, - { - key: 'appTemplate', - fileName: 'index.html', - transform: parseTemplate - } -] - -// Protector utility against request to SSR bundle files -const ssrResourceRegex = new RegExp(resourceMap.map(resource => resource.fileName).join('|'), 'i') - export default class Renderer extends Tapable { constructor (nuxt) { super() @@ -403,3 +378,28 @@ export default class Renderer extends Tapable { return window } } + +const parseTemplate = templateStr => _.template(templateStr, { + interpolate: /{{([\s\S]+?)}}/g +}) + +const resourceMap = [ + { + key: 'clientManifest', + fileName: 'vue-ssr-client-manifest.json', + transform: JSON.parse + }, + { + key: 'serverBundle', + fileName: 'server-bundle.json', + transform: JSON.parse + }, + { + key: 'appTemplate', + fileName: 'index.html', + transform: parseTemplate + } +] + +// Protector utility against request to SSR bundle files +const ssrResourceRegex = new RegExp(resourceMap.map(resource => resource.fileName).join('|'), 'i') diff --git a/lib/core/server.js b/lib/core/server.js deleted file mode 100644 index cec7a7f3b6..0000000000 --- a/lib/core/server.js +++ /dev/null @@ -1,62 +0,0 @@ -import http from 'http' -import chalk from 'chalk' - -class Server { - constructor (nuxt) { - this.nuxt = nuxt - this.options = nuxt.options - - // Initialize - /* istanbul ignore if */ - if (nuxt.initialized) { - // If nuxt already initialized - this._ready = this.ready().catch(this.nuxt.errorHandler) - } else { - // Wait for hook - this.nuxt.plugin('afterInit', () => { - this._ready = this.ready() - return this._ready - }) - } - - // Stop server on nuxt.close() - this.nuxt.plugin('close', () => this.close()) - } - - async ready () { - /* istanbul ignore if */ - if (this._ready) { - return this._ready - } - - this.server = http.createServer(this.nuxt.render) - - return this - } - - listen (port, host) { - host = host || 'localhost' - port = port || 3000 - return this.ready() - .then(() => { - this.server.listen(port, host, () => { - let _host = host === '0.0.0.0' ? 'localhost' : host - // eslint-disable-next-line no-console - console.log('\n' + chalk.bold(chalk.bgBlue.black(' OPEN ') + chalk.blue(` http://${_host}:${port}\n`))) - }) - }).catch(this.nuxt.errorHandler) - } - - close () { - return new Promise((resolve, reject) => { - this.server.close(err => { - if (err) { - return reject(err) - } - resolve() - }) - }) - } -} - -export default Server diff --git a/test/basic.dev.test.js b/test/basic.dev.test.js index b0639decd8..1ca828d9d1 100644 --- a/test/basic.dev.test.js +++ b/test/basic.dev.test.js @@ -1,7 +1,7 @@ import test from 'ava' import { resolve } from 'path' import rp from 'request-promise-native' -import { Nuxt, Server, Builder } from '../index.js' +import { Nuxt, Builder } from '../index.js' const port = 4001 const url = (route) => 'http://localhost:' + port + route @@ -17,8 +17,8 @@ test.before('Init Nuxt.js', async t => { } nuxt = new Nuxt(options) await new Builder(nuxt).build() - server = new Server(nuxt) - server.listen(port, 'localhost') + + await nuxt.listen(port, 'localhost') }) test('/stateless', async t => { diff --git a/test/basic.generate.test.js b/test/basic.generate.test.js index b75e71a4b2..3e01db6c8a 100644 --- a/test/basic.generate.test.js +++ b/test/basic.generate.test.js @@ -30,7 +30,7 @@ test.before('Init Nuxt.js', async t => { server = http.createServer((req, res) => { serve(req, res, finalhandler(req, res)) }) - server.listen(port) + await nuxt.listen(port) }) test('/stateless', async t => { diff --git a/test/basic.test.js b/test/basic.test.js index e1fa0820eb..2d3abd389b 100755 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -2,7 +2,7 @@ import test from 'ava' import { resolve } from 'path' import rp from 'request-promise-native' import stdMocks from 'std-mocks' -import { Nuxt, Server, Builder } from '../index.js' +import { Nuxt, Builder } from '../index.js' const port = 4003 const url = (route) => 'http://localhost:' + port + route @@ -19,8 +19,8 @@ test.before('Init Nuxt.js', async t => { } nuxt = new Nuxt(options) await new Builder(nuxt).build() - server = new Server(nuxt) - server.listen(port, 'localhost') + + await nuxt.listen(port, 'localhost') }) test('/stateless', async t => { diff --git a/test/children.test.js b/test/children.test.js index 6f5629df3b..98fe9d06c8 100644 --- a/test/children.test.js +++ b/test/children.test.js @@ -1,6 +1,6 @@ import test from 'ava' import { resolve } from 'path' -import { Nuxt, Server, Builder } from '../index.js' +import { Nuxt, Builder } from '../index.js' const port = 4004 // const url = (route) => 'http://localhost:' + port + route @@ -17,8 +17,8 @@ test.before('Init Nuxt.js', async t => { } nuxt = new Nuxt(options) await new Builder(nuxt).build() - server = new Server(nuxt) - server.listen(port, 'localhost') + + await nuxt.listen(port, 'localhost') }) test('/parent', async t => { diff --git a/test/error.test.js b/test/error.test.js index 7ed40fa136..44d7fcffec 100644 --- a/test/error.test.js +++ b/test/error.test.js @@ -1,6 +1,6 @@ import test from 'ava' import { resolve } from 'path' -import { Nuxt, Server, Builder } from '../index.js' +import { Nuxt, Builder } from '../index.js' const port = 4005 const url = (route) => 'http://localhost:' + port + route @@ -17,8 +17,8 @@ test.before('Init Nuxt.js', async t => { } nuxt = new Nuxt(options) await new Builder(nuxt).build() - server = new Server(nuxt) - server.listen(port, 'localhost') + + await nuxt.listen(port, 'localhost') }) test('/ should display an error', async t => { diff --git a/test/module.test.js b/test/module.test.js index 6745df79a4..69a409a7d4 100755 --- a/test/module.test.js +++ b/test/module.test.js @@ -1,7 +1,7 @@ import test from 'ava' import { resolve, normalize } from 'path' import rp from 'request-promise-native' -import { Nuxt, Server, Builder } from '../index.js' +import { Nuxt, Builder } from '../index.js' const port = 4006 const url = (route) => 'http://localhost:' + port + route @@ -18,8 +18,8 @@ test.before('Init Nuxt.js', async t => { config.runBuild = true nuxt = new Nuxt(config) await new Builder(nuxt).build() - server = new Server(nuxt) - server.listen(port, 'localhost') + + await nuxt.listen(port, 'localhost') }) test('Vendor', async t => { diff --git a/test/with-config.test.js b/test/with-config.test.js index 1b5b3169ad..2e281bd22f 100644 --- a/test/with-config.test.js +++ b/test/with-config.test.js @@ -1,7 +1,7 @@ import test from 'ava' import { resolve } from 'path' import rp from 'request-promise-native' -import { Nuxt, Server, Builder } from '../index.js' +import { Nuxt, Builder } from '../index.js' const port = 4007 const url = (route) => 'http://localhost:' + port + route @@ -18,8 +18,8 @@ test.before('Init Nuxt.js', async t => { config.runBuild = true nuxt = new Nuxt(config) await new Builder(nuxt).build() - server = new Server(nuxt) - server.listen(port, 'localhost') + + await nuxt.listen(port, 'localhost') }) test('/', async t => {