diff --git a/lib/app/client.js b/lib/app/client.js index 1f171f4c1f..fbd3d42cde 100644 --- a/lib/app/client.js +++ b/lib/app/client.js @@ -9,7 +9,9 @@ const noopFetch = () => {} let _lastPaths = [] let _lastComponentsFiles = [] -const { app, router<%= (store ? ', store' : '') %> } = createApp() +let app +let router +<%= (store ? 'let store' : '') %> function mapTransitions(Components, to, from) { return Components.map((Component) => { @@ -319,25 +321,27 @@ if (!NUXT) { throw new Error('[nuxt.js] cannot find the global variable __NUXT__, make sure the server is working.') } // Get matched components -const path = getLocation(router.options.base) -const resolveComponents = flatMapComponents(router.match(path), (Component, _, match, key, index) => { - if (typeof Component === 'function' && !Component.options) { - return new Promise(function (resolve, reject) { - const _resolve = (Component) => { - Component = sanitizeComponent(Component) - if (NUXT.serverRendered) { - applyAsyncData(Component, NUXT.data[index]) +const resolveComponents = function (router) { + const path = getLocation(router.options.base) + return flatMapComponents(router.match(path), (Component, _, match, key, index) => { + if (typeof Component === 'function' && !Component.options) { + return new Promise(function (resolve, reject) { + const _resolve = (Component) => { + Component = sanitizeComponent(Component) + if (NUXT.serverRendered) { + applyAsyncData(Component, NUXT.data[index]) + } + match.components[key] = Component + resolve(Component) } - match.components[key] = Component - resolve(Component) - } - Component().then(_resolve).catch(reject) - }) - } - Component = sanitizeComponent(Component) - match.components[key] = Component - return Component -}) + Component().then(_resolve).catch(reject) + }) + } + Component = sanitizeComponent(Component) + match.components[key] = Component + return Component + }) +} function nuxtReady (app) { window._nuxtReadyCbs.forEach((cb) => { @@ -351,7 +355,13 @@ function nuxtReady (app) { }) } -Promise.all(resolveComponents) +createApp() +.then((__app) => { + app = __app.app + router = __app.router + <%= (store ? 'store = __app.store' : '') %> + return Promise.all(resolveComponents(router)) +}) .then((Components) => { const _app = new Vue(app) diff --git a/lib/app/index.js b/lib/app/index.js index ca90697ac0..b3a45134a4 100644 --- a/lib/app/index.js +++ b/lib/app/index.js @@ -10,6 +10,8 @@ import NuxtError from '<%= components.ErrorPage ? components.ErrorPage : "./comp import Nuxt from './components/nuxt.vue' import App from '<%= appPath %>' +import { getContext } from './utils' + // Component: Vue.component(NuxtChild.name, NuxtChild) // Component: @@ -32,12 +34,18 @@ const defaultTransition = <%= .replace('afterLeave(', 'function(').replace('leaveCancelled(', 'function(') %> -function createApp (ssrContext) { +async function createApp (ssrContext) { <% if (store) { %> const store = createStore() <% } %> const router = createRouter() + if (process.server && ssrContext && ssrContext.url) { + await new Promise((resolve, reject) => { + router.push(ssrContext.url, resolve, reject) + }) + } + if (process.browser) { <% if (store) { %> // Replace store state before calling plugins @@ -59,7 +67,6 @@ function createApp (ssrContext) { let app = { router, <%= (store ? 'store,' : '') %> - ssrContext, _nuxt: { defaultTransition: defaultTransition, transitions: [ defaultTransition ], @@ -95,22 +102,32 @@ function createApp (ssrContext) { ...App } + const ctx = getContext({ + isServer: !!ssrContext, + isClient: !ssrContext, + route: router.currentRoute, + <%= (store ? 'store,' : '') %> + req: ssrContext ? ssrContext.req : undefined, + res: ssrContext ? ssrContext.res : undefined, + }, app) + delete ctx.redirect + delete ctx.error // Includes & Inject external plugins <% plugins.forEach(function (plugin) { if (plugin.ssr) { %> - <%= (plugin.injectAs ? 'let ' + plugin.injectAs + ' = ' : '') %>require('<%= plugin.src %>') - <% if (plugin.injectAs) { %> - <%= plugin.injectAs + ' = ' + plugin.injectAs + '.default || ' + plugin.injectAs %> - app['<%= plugin.injectAs %>'] = <%= plugin.injectAs %> - <% } - } else { %> + let <%= plugin.name %> = require('<%= plugin.src %>') + <%= plugin.name %> = <%= plugin.name %>.default || <%= plugin.name %> + if (typeof <%= plugin.name %> === 'function') { + <%= plugin.name %>(ctx) + } + <% } else { %> if (process.browser) { - <%= (plugin.injectAs ? 'let ' + plugin.injectAs + ' = ' : '') %>require('<%= plugin.src %>') - <% if (plugin.injectAs) { %> - <%= plugin.injectAs + ' = ' + plugin.injectAs + '.default || ' + plugin.injectAs %> - app['<%= plugin.injectAs %>'] = <%= plugin.injectAs %> - <% } %> + let <%= plugin.name %> = require('<%= plugin.src %>') + <%= plugin.name %> = <%= plugin.name %>.default || <%= plugin.name %> + if (typeof <%= plugin.name %> === 'function') { + <%= plugin.name %>(ctx) + } } <% } }) %> diff --git a/lib/app/server.js b/lib/app/server.js index a53382293c..d83b55b093 100644 --- a/lib/app/server.js +++ b/lib/app/server.js @@ -17,10 +17,12 @@ const isDev = <%= isDev %> // Since data fetching is async, this function is expected to // return a Promise that resolves to the app instance. export default async (context) => { - const { app, router<%= (store ? ', store' : '') %> } = createApp(context) + const { app, router<%= (store ? ', store' : '') %> } = await createApp(context) const _app = new Vue(app) // Add store to the context <%= (store ? 'context.store = store' : '') %> + // Add route to the context + context.route = router.currentRoute // Nuxt object context.nuxt = { layout: 'default', data: [], error: null<%= (store ? ', state: null' : '') %>, serverRendered: true } // create context.next for simulate next() of beforeEach() when wanted to redirect @@ -46,7 +48,7 @@ export default async (context) => { context.error = _app.$options._nuxt.error.bind(_app) <%= (isDev ? 'const s = isDev && Date.now()' : '') %> - let ctx = null + let ctx = getContext(context, app) let Components = [] let promises = getMatchedComponents(router.match(context.url)).map((Component) => { return new Promise((resolve, reject) => { @@ -61,14 +63,6 @@ export default async (context) => { // Throw back error to renderRoute() throw err } - // set router's location - await new Promise((resolve) => { - router.push(context.url, resolve) - }) - // Add route to the context - context.route = router.currentRoute - // Update context - ctx = getContext(context, app) // nuxtServerInit <% if (store) { %> let promise = (store._actions && store._actions.nuxtServerInit ? store.dispatch('nuxtServerInit', omit(getContext(context, app), 'redirect', 'error')) : null) diff --git a/lib/app/utils.js b/lib/app/utils.js index d665a9d6e5..7a8d399152 100644 --- a/lib/app/utils.js +++ b/lib/app/utils.js @@ -58,6 +58,7 @@ export function getContext (context, app) { isServer: !!context.isServer, isClient: !!context.isClient, isDev: <%= isDev %>, + app: app, <%= (store ? 'store: context.store,' : '') %> route: (context.to ? context.to : context.route), error: context.error, @@ -84,16 +85,6 @@ export function getContext (context, app) { } if (context.req) ctx.req = context.req if (context.res) ctx.res = context.res - // Inject external plugins in context - <% plugins.forEach(function (plugin) { - if (plugin.injectAs && plugin.ssr) { %> - ctx['<%= plugin.injectAs %>'] = app['<%= plugin.injectAs %>'] - <% } else if (plugin.injectAs) { %> - if (process.browser) { - ctx['<%= plugin.injectAs %>'] = app['<%= plugin.injectAs %>'] - } - <% } %> - <% }) %> return ctx } diff --git a/lib/build.js b/lib/build.js index d6aec52959..f42ded6aa9 100644 --- a/lib/build.js +++ b/lib/build.js @@ -181,11 +181,10 @@ async function generateRoutesAndFiles () { middleware: fs.existsSync(join(this.srcDir, 'middleware')), store: this.options.store || fs.existsSync(join(this.srcDir, 'store')), css: this.options.css, - plugins: this.options.plugins.map((p) => { - if (typeof p === 'string') { - return { src: r(this.srcDir, p), ssr: true } - } - return { src: r(this.srcDir, p.src), ssr: (p.ssr !== false), injectAs: (p.injectAs || false) } + plugins: this.options.plugins.map((p, i) => { + if (typeof p === 'string') p = { src: p } + p.src = r(this.srcDir, p.src) + return { src: p.src, ssr: (p.ssr !== false), name: `plugin${i}` } }), appPath: './App.vue', layouts: Object.assign({}, this.options.layouts), diff --git a/lib/module.js b/lib/module.js index 90c980342e..b0744ff54c 100755 --- a/lib/module.js +++ b/lib/module.js @@ -53,8 +53,7 @@ class Module { // Add to nuxt plugins this.options.plugins.push({ src: '~/.nuxt/' + dst, - ssr: template.ssr, - injectAs: template.injectAs + ssr: template.ssr }) } diff --git a/lib/render.js b/lib/render.js index c1a3e7adc6..2365af27d4 100644 --- a/lib/render.js +++ b/lib/render.js @@ -19,7 +19,6 @@ export async function render (req, res) { if (!this.renderer || !this.appTemplate) { return new Promise((resolve) => { setTimeout(() => { - // debug('Waiting for renderer to be ready') resolve(this.render(req, res)) }, 1000) })