diff --git a/lib/build.js b/lib/build.js index a5793131a3..a12807e06c 100644 --- a/lib/build.js +++ b/lib/build.js @@ -97,8 +97,21 @@ export function options () { } export async function build () { - // Initialize modules first - await this.module.init() + // Avoid calling this method multiple times + if (this._buildDone) { + return this + } + // If building + if (this._building) { + return new Promise((resolve) => { + setTimeout(() => { + resolve(this.build()) + }, 300) + }) + } + this._building = true + // Wait for Nuxt.js to be ready + await this.ready() // Check if pages dir exists and warn if not this._nuxtPages = typeof this.createRoutes !== 'function' if (this._nuxtPages) { @@ -123,6 +136,8 @@ export async function build () { await generateRoutesAndFiles.call(this) // Generate .nuxt/dist/ files await buildFiles.call(this) + // Flag to set that building is done + this._buildDone = true return this } diff --git a/lib/module.js b/lib/module.js index 106f04b41c..f16669697a 100755 --- a/lib/module.js +++ b/lib/module.js @@ -13,18 +13,16 @@ class Module { this.nuxt = nuxt this.options = nuxt.options this.modules = [] - this.initialized = false + this.initing = this.ready() } - async init () { - if (this.initialized) { - debug('[nuxt] Modules are already initialized') + async ready () { + if (this.initing) { + await this.initing return } // Install all modules in sequence await sequence(this.options.modules, this.addModule.bind(this)) - // Indicate modules are already initialized - this.initialized = true } addVendor (vendor) { diff --git a/lib/nuxt.js b/lib/nuxt.js index c045e483c2..bce21038cc 100644 --- a/lib/nuxt.js +++ b/lib/nuxt.js @@ -16,7 +16,7 @@ import * as utils from './utils' class Nuxt { constructor (options = {}) { const defaults = { - dev: true, + dev: (process.env.NODE_ENV !== 'production'), buildDir: '.nuxt', env: {}, head: { @@ -72,6 +72,8 @@ class Nuxt { } if (typeof options.transition === 'string') options.transition = { name: options.transition } this.options = _.defaultsDeep(options, defaults) + // Ready variable + this._ready = false // Env variables this.dev = this.options.dev // Explicit srcDir, rootDir and buildDir @@ -121,6 +123,21 @@ class Nuxt { this.utils = utils // Add module integration this.module = new Module(this) + // Init nuxt.js + this.ready() + // Launch build in development but don't wait for him to be finished + if (this.dev) { + this.build() + } + // Return nuxt.js instance + return this + } + + async ready () { + if (this._ready) return this + // Init modules + await this.module.ready() + this._ready = true } close (callback) { diff --git a/lib/render.js b/lib/render.js index ccdaefc07f..ee8d371d9c 100644 --- a/lib/render.js +++ b/lib/render.js @@ -23,6 +23,9 @@ export async function render (req, res) { }, 1000) }) } + // Wait for nuxt.js to be ready + await this.ready() + // Get context const context = getContext(req, res) res.statusCode = 200 try { @@ -92,6 +95,7 @@ export async function render (req, res) { return err } const html = this.errorTemplate({ + /* istanbul ignore if */ error: err, stack: ansiHTML(encodeHtml(err.stack)) }) @@ -104,6 +108,9 @@ export async function render (req, res) { } export async function renderRoute (url, context = {}) { + // Wait for modules to be initialized + await this.ready() + // Log rendered url debug(`Rendering url ${url}`) // Add url and isSever to the context context.url = url @@ -165,6 +172,7 @@ export async function renderAndGetWindow (url, opts = {}) { const { window } = await jsdom.JSDOM.fromURL(url, options) // If Nuxt could not be loaded (error from the server-side) const nuxtExists = window.document.body.innerHTML.includes('window.__NUXT__') + /* istanbul ignore if */ if (!nuxtExists) { let error = new Error('Could not load the nuxt app') error.body = window.document.body.innerHTML diff --git a/lib/server.js b/lib/server.js index 5ad4439529..63766e4563 100644 --- a/lib/server.js +++ b/lib/server.js @@ -10,12 +10,15 @@ class Server { // Initialize this.app = connect() this.server = http.createServer(this.app) - // Add Middleware - this.nuxt.options.serverMiddleware.forEach(m => { - this.useMiddleware(m) + this.nuxt.ready() + .then(() => { + // Add Middleware + this.nuxt.options.serverMiddleware.forEach(m => { + this.useMiddleware(m) + }) + // Add default render middleware + this.useMiddleware(this.render.bind(this)) }) - // Add default render middleware - this.useMiddleware(this.render.bind(this)) return this } @@ -45,8 +48,11 @@ class Server { listen (port, host) { host = host || '127.0.0.1' port = port || 3000 - this.server.listen(port, host, () => { - console.log('Ready on http://%s:%s', host, port) // eslint-disable-line no-console + this.nuxt.ready() + .then(() => { + this.server.listen(port, host, () => { + console.log('Ready on http://%s:%s', host, port) // eslint-disable-line no-console + }) }) return this } diff --git a/test/index.test.js b/test/index.test.js index 53f05b9afa..f910f1ea5e 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -7,12 +7,14 @@ test('Nuxt.js Class', t => { t.is(typeof Nuxt, 'function') }) -test('Nuxt.js Instance', async t => { +test.serial('Nuxt.js Instance', async t => { + process.env.NODE_ENV = 'production' const nuxt = new Nuxt() t.is(typeof nuxt, 'object') - t.is(nuxt.dev, true) + t.is(nuxt.dev, false) t.is(typeof nuxt.build, 'function') t.is(typeof nuxt.generate, 'function') + delete process.env.NODE_ENV }) test.serial('Fail when build not done and try to render', async t => {