Refactor to use only one context and add route.meta

This commit is contained in:
Sébastien Chopin 2017-10-13 23:53:04 +02:00 committed by Sebastien Chopin
parent dd7d8bbafc
commit 5b09b92286
7 changed files with 232 additions and 221 deletions

View File

@ -1,4 +1,3 @@
<script>
import Vue from 'vue' import Vue from 'vue'
<% if (loading) { %>import NuxtLoading from '<%= (typeof loading === "string" ? loading : "./components/nuxt-loading.vue") %>'<% } %> <% if (loading) { %>import NuxtLoading from '<%= (typeof loading === "string" ? loading : "./components/nuxt-loading.vue") %>'<% } %>
<% css.forEach(function (c) { %> <% css.forEach(function (c) { %>
@ -19,7 +18,6 @@ export default {
head: <%= JSON.stringify(head) %>, head: <%= JSON.stringify(head) %>,
render(h, props) { render(h, props) {
<% if (loading) { %>const loadingEl = h('nuxt-loading', { ref: 'loading' })<% } %> <% if (loading) { %>const loadingEl = h('nuxt-loading', { ref: 'loading' })<% } %>
const layoutEl = h(this.nuxt.err ? 'nuxt' : this.layout, { const layoutEl = h(this.nuxt.err ? 'nuxt' : this.layout, {
key: this.layoutName key: this.layoutName
}) })
@ -45,7 +43,7 @@ export default {
layoutName: '' layoutName: ''
}), }),
beforeCreate () { beforeCreate () {
Vue.util.defineReactive(this, 'nuxt', this.$options._nuxt) Vue.util.defineReactive(this, 'nuxt', this.$options.nuxt)
}, },
created () { created () {
// Add this.$nuxt in child instances // Add this.$nuxt in child instances
@ -104,5 +102,4 @@ export default {
<%= (loading ? 'NuxtLoading' : '') %> <%= (loading ? 'NuxtLoading' : '') %>
} }
} }
</script>

View File

@ -1,5 +1,3 @@
import Vue from 'vue'
export default { export default {
name: 'nuxt-link', name: 'nuxt-link',
functional: true, functional: true,

View File

@ -1,4 +1,3 @@
<script>
import Vue from 'vue' import Vue from 'vue'
import NuxtChild from './nuxt-child' import NuxtChild from './nuxt-child'
import NuxtError from '<%= components.ErrorPage ? ((components.ErrorPage.includes('~') || components.ErrorPage.includes('@')) ? components.ErrorPage : "../" + components.ErrorPage) : "./nuxt-error.vue" %>' import NuxtError from '<%= components.ErrorPage ? ((components.ErrorPage.includes('~') || components.ErrorPage.includes('@')) ? components.ErrorPage : "../" + components.ErrorPage) : "./nuxt-error.vue" %>'
@ -22,7 +21,7 @@ export default {
}) })
}, },
beforeCreate () { beforeCreate () {
Vue.util.defineReactive(this, 'nuxt', this.$root.$options._nuxt) Vue.util.defineReactive(this, 'nuxt', this.$root.$options.nuxt)
}, },
computed: { computed: {
routerViewKey () { routerViewKey () {
@ -38,4 +37,3 @@ export default {
NuxtError NuxtError
} }
} }
</script>

View File

@ -6,9 +6,9 @@ import NoSSR from './components/no-ssr.js'
import NuxtChild from './components/nuxt-child.js' import NuxtChild from './components/nuxt-child.js'
import NuxtLink from './components/nuxt-link.js' import NuxtLink from './components/nuxt-link.js'
import NuxtError from '<%= components.ErrorPage ? components.ErrorPage : "./components/nuxt-error.vue" %>' import NuxtError from '<%= components.ErrorPage ? components.ErrorPage : "./components/nuxt-error.vue" %>'
import Nuxt from './components/nuxt.vue' import Nuxt from './components/nuxt.js'
import App from '<%= appPath %>' import App from '<%= appPath %>'
import { getContext, getLocation } from './utils' import { setContext, getLocation } from './utils'
<% if (store) { %>import { createStore } from './store.js'<% } %> <% if (store) { %>import { createStore } from './store.js'<% } %>
<% plugins.forEach(plugin => { %>import <%= plugin.name %> from '<%= plugin.name %>' <% plugins.forEach(plugin => { %>import <%= plugin.name %> from '<%= plugin.name %>'
<% }) %> <% }) %>
@ -37,7 +37,8 @@ const defaultTransition = <%=
serialize(transition) serialize(transition)
.replace('beforeEnter(', 'function(').replace('enter(', 'function(').replace('afterEnter(', 'function(') .replace('beforeEnter(', 'function(').replace('enter(', 'function(').replace('afterEnter(', 'function(')
.replace('enterCancelled(', 'function(').replace('beforeLeave(', 'function(').replace('leave(', 'function(') .replace('enterCancelled(', 'function(').replace('beforeLeave(', 'function(').replace('leave(', 'function(')
.replace('afterLeave(', 'function(').replace('leaveCancelled(', 'function(') .replace('afterLeave(', 'function(').replace('leaveCancelled(', 'function(').replace('beforeAppear(', 'function(')
.replace('appear(', 'function(').replace('afterAppear(', 'function(').replace('appearCancelled(', 'function(')
%> %>
async function createApp (ssrContext) { async function createApp (ssrContext) {
@ -55,7 +56,7 @@ async function createApp (ssrContext) {
const app = { const app = {
router, router,
<% if (store) { %>store,<% } %> <% if (store) { %>store,<% } %>
_nuxt: { nuxt: {
defaultTransition, defaultTransition,
transitions: [ defaultTransition ], transitions: [ defaultTransition ],
setTransitions (transitions) { setTransitions (transitions) {
@ -72,29 +73,30 @@ async function createApp (ssrContext) {
} }
return transition return transition
}) })
this.$options._nuxt.transitions = transitions this.$options.nuxt.transitions = transitions
return transitions return transitions
}, },
err: null, err: null,
dateErr: null, dateErr: null,
error (err) { error (err) {
err = err || null err = err || null
if (typeof err === 'string') { if (typeof err === 'string') err = { statusCode: 500, message: err }
err = { statusCode: 500, message: err } const nuxt = this.nuxt || this.$options.nuxt
} nuxt.dateErr = Date.now()
const _nuxt = this._nuxt || this.$options._nuxt nuxt.err = err
_nuxt.dateErr = Date.now() // Used in lib/server.js
_nuxt.err = err if (ssrContext) ssrContext.nuxt.error = err
return err return err
} }
}, },
...App ...App
} }
<% if (store) { %> <% if (store) { %>
// Make app available in store // Make app available into store via this.app
store.app = app store.app = app
<% } %> <% } %>
const next = ssrContext ? ssrContext.next : location => app.router.push(location) const next = ssrContext ? ssrContext.next : location => app.router.push(location)
// Resolve route
let route let route
if (ssrContext) { if (ssrContext) {
route = router.resolve(ssrContext.url).route route = router.resolve(ssrContext.url).route
@ -102,17 +104,19 @@ async function createApp (ssrContext) {
const path = getLocation(router.options.base) const path = getLocation(router.options.base)
route = router.resolve(path).route route = router.resolve(path).route
} }
const ctx = getContext({
// Set context to app.context
await setContext(app, {
isServer: !!ssrContext, isServer: !!ssrContext,
isClient: !ssrContext, isClient: !ssrContext,
route, route,
next, next,
error: app._nuxt.error.bind(app), error: app.nuxt.error.bind(app),
<% if (store) { %>store,<% } %> <% if (store) { %>store,<% } %>
req: ssrContext ? ssrContext.req : undefined, req: ssrContext ? ssrContext.req : undefined,
res: ssrContext ? ssrContext.res : undefined, res: ssrContext ? ssrContext.res : undefined,
beforeRenderFns: ssrContext ? ssrContext.beforeRenderFns : undefined beforeRenderFns: ssrContext ? ssrContext.beforeRenderFns : undefined
}, app) })
const inject = function (key, value) { const inject = function (key, value) {
if (!key) throw new Error('inject(key, value) has no key provided') if (!key) throw new Error('inject(key, value) has no key provided')
@ -120,11 +124,12 @@ async function createApp (ssrContext) {
key = '$' + key key = '$' + key
// Add into app // Add into app
app[key] = value app[key] = value
// Add into vm // Check if plugin not already installed
Vue.use(() => {
const installKey = '__nuxt_' + key + '_installed__' const installKey = '__nuxt_' + key + '_installed__'
if (Vue[installKey]) return if (Vue[installKey]) return
Vue[installKey] = true Vue[installKey] = true
// Call Vue.use() to install the plugin into vm
Vue.use(() => {
if (!Vue.prototype.hasOwnProperty(key)) { if (!Vue.prototype.hasOwnProperty(key)) {
Object.defineProperty(Vue.prototype, key, { Object.defineProperty(Vue.prototype, key, {
get () { get () {
@ -148,16 +153,15 @@ async function createApp (ssrContext) {
} }
<% } %> <% } %>
// Plugin execution
<% plugins.filter(p => p.ssr).forEach(plugin => { %> <% plugins.filter(p => p.ssr).forEach(plugin => { %>
if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(ctx, inject)<% }) %> if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(app.context, inject)<% }) %>
<% if (plugins.filter(p => !p.ssr).length) { %> <% if (plugins.filter(p => !p.ssr).length) { %>
if (process.browser) { <% plugins.filter(p => !p.ssr).forEach(plugin => { %> if (process.browser) { <% plugins.filter(p => !p.ssr).forEach(plugin => { %>
if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(ctx, inject)<% }) %> if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(app.context, inject)<% }) %>
}<% } %> }<% } %>
// Inject context // If server-side, wait for async component to be resolved first
inject('ctx', ctx)
if (process.server && ssrContext && ssrContext.url) { if (process.server && ssrContext && ssrContext.url) {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
router.push(ssrContext.url, resolve, reject) router.push(ssrContext.url, resolve, reject)

View File

@ -13,11 +13,11 @@ const isDev = <%= isDev %>
const noopApp = () => new Vue({ render: (h) => h('div') }) const noopApp = () => new Vue({ render: (h) => h('div') })
const createNext = context => opts => { const createNext = ssrContext => opts => {
context.redirected = opts ssrContext.redirected = opts
// If nuxt generate // If nuxt generate
if (!context.res) { if (!ssrContext.res) {
context.nuxt.serverRendered = false ssrContext.nuxt.serverRendered = false
return return
} }
opts.query = stringify(opts.query) opts.query = stringify(opts.query)
@ -26,14 +26,14 @@ const createNext = context => opts => {
opts.path = urlJoin('<%= router.base %>', opts.path) opts.path = urlJoin('<%= router.base %>', opts.path)
} }
// Avoid loop redirect // Avoid loop redirect
if (opts.path === context.url) { if (opts.path === ssrContext.url) {
context.redirected = false ssrContext.redirected = false
return return
} }
context.res.writeHead(opts.status, { ssrContext.res.writeHead(opts.status, {
'Location': opts.path 'Location': opts.path
}) })
context.res.end() ssrContext.res.end()
} }
// This exported function will be called by `bundleRenderer`. // This exported function will be called by `bundleRenderer`.
@ -41,87 +41,91 @@ const createNext = context => opts => {
// state of our application before actually rendering it. // state of our application before actually rendering it.
// Since data fetching is async, this function is expected to // Since data fetching is async, this function is expected to
// return a Promise that resolves to the app instance. // return a Promise that resolves to the app instance.
export default async context => { export default async ssrContext => {
// Create context.next for simulate next() of beforeEach() when wanted to redirect // Create ssrContext.next for simulate next() of beforeEach() when wanted to redirect
context.redirected = false ssrContext.redirected = false
context.next = createNext(context) ssrContext.next = createNext(ssrContext)
context.beforeRenderFns = [] // Used for beforeNuxtRender({ Components, nuxtState })
ssrContext.beforeRenderFns = []
const { app, router<%= (store ? ', store' : '') %> } = await createApp(context) // Create the app definition and the instance (created for each request)
const { app, router<%= (store ? ', store' : '') %> } = await createApp(ssrContext)
const _app = new Vue(app) const _app = new Vue(app)
// Nuxt object (window.__NUXT__)
ssrContext.nuxt = { layout: 'default', data: [], error: null<%= (store ? ', state: null' : '') %>, serverRendered: true }
// Add meta infos (used in renderer.js)
ssrContext.meta = _app.$meta()
// Keep asyncData for each matched component in ssrContext (used in app/utils.js via this.$ssrContext)
ssrContext.asyncData = {}
const beforeRender = async () => {
// Call beforeNuxtRender() methods
await Promise.all(ssrContext.beforeRenderFns.map((fn) => promisify(fn, { Components, nuxtState: ssrContext.nuxt })))
<% if (store) { %> <% if (store) { %>
// Add store to the context // Add the state from the vuex store
context.store = store ssrContext.nuxt.state = store.state
<% } %> <% } %>
}
// Add route to the context const renderErrorPage = async () => {
context.route = router.currentRoute // Load layout for error page
let errLayout = (typeof NuxtError.layout === 'function' ? NuxtError.layout(app.context) : NuxtError.layout)
// Nuxt object ssrContext.nuxt.layout = errLayout || ''
context.nuxt = { layout: 'default', data: [], error: null<%= (store ? ', state: null' : '') %>, serverRendered: true } await _app.loadLayout(errLayout)
_app.setLayout(errLayout)
// Add meta infos await beforeRender()
context.meta = _app.$meta() return _app
}
// Error function const render404Page = async () => {
context.error = _app.$options._nuxt.error.bind(_app) app.context.error({ statusCode: 404, message: '<%= messages.error_404 %>' })
return await renderErrorPage()
// Keep asyncData for each matched component in context }
context.asyncData = {}
// Create shared ctx
const ctx = getContext(context, app)
<% if (isDev) { %>const s = isDev && Date.now()<% } %> <% if (isDev) { %>const s = isDev && Date.now()<% } %>
// Resolve components // Components are already resolved by setContext -> getRouteData (app/utils.js)
let Components = [] const Components = getMatchedComponents(router.match(ssrContext.url))
try {
Components = await Promise.all(getMatchedComponents(router.match(context.url)).map(Component => {
if (typeof Component !== 'function' || Component.cid) {
return sanitizeComponent(Component)
}
return Component().then(Component => sanitizeComponent(Component))
}))
} catch (err) {
// Throw back error to renderRoute()
throw err
}
<% if (store) { %> <% if (store) { %>
// Dispatch store nuxtServerInit /*
** Dispatch store nuxtServerInit
*/
if (store._actions && store._actions.nuxtServerInit) { if (store._actions && store._actions.nuxtServerInit) {
await store.dispatch('nuxtServerInit', ctx) await store.dispatch('nuxtServerInit', app.context)
} }
// ...If there is a redirect // ...If there is a redirect or an error, stop the process
if (context.redirected) return noopApp() if (ssrContext.redirected) return noopApp()
if (ssrContext.nuxt.error) return await renderErrorPage()
<% } %> <% } %>
// Call global middleware (nuxt.config.js) /*
** Call global middleware (nuxt.config.js)
*/
let midd = <%= serialize(router.middleware, { isJSON: true }) %> let midd = <%= serialize(router.middleware, { isJSON: true }) %>
midd = midd.map((name) => { midd = midd.map((name) => {
if (typeof middleware[name] !== 'function') { if (typeof middleware[name] !== 'function') {
context.nuxt.error = context.error({ statusCode: 500, message: 'Unknown middleware ' + name }) ssrContext.error({ statusCode: 500, message: 'Unknown middleware ' + name })
} }
return middleware[name] return middleware[name]
}) })
if (!context.nuxt.error) { await middlewareSeries(midd, app.context)
await middlewareSeries(midd, ctx) // ...If there is a redirect or an error, stop the process
} if (ssrContext.redirected) return noopApp()
// ...If there is a redirect if (ssrContext.nuxt.error) return await renderErrorPage()
if (context.redirected) return noopApp()
// Set layout /*
** Set layout
*/
let layout = Components.length ? Components[0].options.layout : NuxtError.layout let layout = Components.length ? Components[0].options.layout : NuxtError.layout
if (typeof layout === 'function') layout = layout(ctx) if (typeof layout === 'function') layout = layout(app.context)
await _app.loadLayout(layout) await _app.loadLayout(layout)
layout = _app.setLayout(layout) layout = _app.setLayout(layout)
// ...Set layout to __NUXT__ // ...Set layout to __NUXT__
context.nuxt.layout = _app.layoutName ssrContext.nuxt.layout = _app.layoutName
// Call middleware (layout + pages) /*
if (!context.nuxt.error) { ** Call middleware (layout + pages)
*/
midd = [] midd = []
if (layout.middleware) midd = midd.concat(layout.middleware) if (layout.middleware) midd = midd.concat(layout.middleware)
Components.forEach((Component) => { Components.forEach((Component) => {
@ -131,47 +135,48 @@ export default async context => {
}) })
midd = midd.map((name) => { midd = midd.map((name) => {
if (typeof middleware[name] !== 'function') { if (typeof middleware[name] !== 'function') {
context.nuxt.error = context.error({ statusCode: 500, message: 'Unknown middleware ' + name }) app.context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
} }
return middleware[name] return middleware[name]
}) })
await middlewareSeries(midd, app.context)
// ...If there is a redirect or an error, stop the process
if (ssrContext.redirected) return noopApp()
if (ssrContext.nuxt.error) return await renderErrorPage()
await middlewareSeries(midd, ctx) /*
** Call .validate()
// If there is a redirect */
if (context.redirected) return noopApp()
}
// Call .validate()
let isValid = true let isValid = true
Components.forEach((Component) => { Components.forEach((Component) => {
if (!isValid) return if (!isValid) return
if (typeof Component.options.validate !== 'function') return if (typeof Component.options.validate !== 'function') return
isValid = Component.options.validate({ isValid = Component.options.validate({
params: context.route.params || {}, params: app.context.route.params || {},
query: context.route.query || {}, query: app.context.route.query || {},
<%= (store ? 'store: ctx.store' : '') %> <%= (store ? 'store' : '') %>
}) })
}) })
// ...If .validate() returned false // ...If .validate() returned false
if (!isValid) { if (!isValid) {
// Don't server-render the page in generate mode // Don't server-render the page in generate mode
if (context._generate) { if (ssrContext._generate) ssrContext.nuxt.serverRendered = false
context.nuxt.serverRendered = false // Render a 404 error page
} return render404Page()
// Call the 404 error by making the Components array empty
Components = []
} }
// If no Components found, returns 404
if (!Components.length) return render404Page()
// Call asyncData & fetch hooks on components matched by the route. // Call asyncData & fetch hooks on components matched by the route.
let asyncDatas = await Promise.all(Components.map(Component => { let asyncDatas = await Promise.all(Components.map(Component => {
let promises = [] let promises = []
// Call asyncData(context) // Call asyncData(context)
if (Component.options.asyncData && typeof Component.options.asyncData === 'function') { if (Component.options.asyncData && typeof Component.options.asyncData === 'function') {
let promise = promisify(Component.options.asyncData, ctx) let promise = promisify(Component.options.asyncData, app.context)
promise.then(asyncDataResult => { promise.then(asyncDataResult => {
context.asyncData[Component.cid] = asyncDataResult ssrContext.asyncData[Component.cid] = asyncDataResult
applyAsyncData(Component) applyAsyncData(Component)
return asyncDataResult return asyncDataResult
}) })
@ -182,7 +187,7 @@ export default async context => {
// Call fetch(context) // Call fetch(context)
if (Component.options.fetch) { if (Component.options.fetch) {
promises.push(Component.options.fetch(ctx)) promises.push(Component.options.fetch(app.context))
} }
else { else {
promises.push(null) promises.push(null)
@ -191,38 +196,17 @@ export default async context => {
return Promise.all(promises) return Promise.all(promises)
})) }))
// If no Components found, returns 404 <% if (isDev) { %>if (asyncDatas.length) debug('Data fetching ' + ssrContext.url + ': ' + (Date.now() - s) + 'ms')<% } %>
if (!Components.length) {
context.nuxt.error = context.error({ statusCode: 404, message: '<%= messages.error_404 %>' })
}
<% if (isDev) { %>if (asyncDatas.length) debug('Data fetching ' + context.url + ': ' + (Date.now() - s) + 'ms')<% } %>
// datas are the first row of each // datas are the first row of each
context.nuxt.data = asyncDatas.map(r => r[0] || {}) ssrContext.nuxt.data = asyncDatas.map(r => r[0] || {})
// If an error occured in the execution // ...If there is a redirect or an error, stop the process
if (_app.$options._nuxt.err) { if (ssrContext.redirected) return noopApp()
context.nuxt.error = _app.$options._nuxt.err if (ssrContext.nuxt.error) return await renderErrorPage()
}
<% if (store) { %> // Call beforeNuxtRender methods & add store state
// Add the state from the vuex store await beforeRender()
context.nuxt.state = store.state
<% } %>
await Promise.all(context.beforeRenderFns.map((fn) => promisify(fn, { Components, nuxtState: context.nuxt })))
// If no error, return main app
if (!context.nuxt.error) {
return _app
}
// Load layout for error page
layout = (typeof NuxtError.layout === 'function' ? NuxtError.layout(ctx) : NuxtError.layout)
context.nuxt.layout = layout || ''
await _app.loadLayout(layout)
_app.setLayout(layout)
return _app return _app
} }

View File

@ -31,6 +31,10 @@ export function applyAsyncData (Component, asyncData) {
} }
export function sanitizeComponent(Component) { export function sanitizeComponent(Component) {
// If Component already sanitized
if (Component.options && Component._Ctor === Component) {
return Component
}
if (!Component.options) { if (!Component.options) {
Component = Vue.extend(Component) // fix issue #6 Component = Vue.extend(Component) // fix issue #6
Component._Ctor = Component Component._Ctor = Component
@ -69,25 +73,51 @@ export function flatMapComponents (route, fn) {
})) }))
} }
export function getContext (context, app) { export async function resolveRouteComponents(route) {
let ctx = { await Promise.all(
flatMapComponents(route, async (Component, _, match, key) => {
// If component is a function, resolve it
if (typeof Component === 'function' && !Component.options) {
Component = await Component()
}
return match.components[key] = sanitizeComponent(Component)
})
)
}
async function getRouteData(route) {
// Make sure the components are resolved (code-splitting)
await resolveRouteComponents(route)
// Send back a copy of route with meta based on Component definition
return {
...route,
meta: getMatchedComponents(route).map((Component) => {
return Component.options.meta || {}
})
}
}
export async function setContext(app, context) {
const route = (context.to ? context.to : context.route)
// If context not defined, create it
if (!app.context) {
app.context = {
isServer: !!context.isServer, isServer: !!context.isServer,
isClient: !!context.isClient, isClient: !!context.isClient,
isStatic: process.static, isStatic: process.static,
isDev: <%= isDev %>, isDev: <%= isDev %>,
isHMR: context.isHMR || false, isHMR: false,
app: app, app,
<%= (store ? 'store: context.store,' : '') %> <%= (store ? 'store: app.store,' : '') %>
route: (context.to ? context.to : context.route),
payload: context.payload, payload: context.payload,
error: context.error, error: context.error,
base: '<%= router.base %>', base: '<%= router.base %>',
env: <%= JSON.stringify(env) %> env: <%= JSON.stringify(env) %>
} }
const next = context.next // Only set once
ctx.params = ctx.route.params || {} if (context.req) app.context.req = context.req
ctx.query = ctx.route.query || {} if (context.res) app.context.res = context.res
ctx.redirect = function (status, path, query) { app.context.redirect = function (status, path, query) {
if (!status) return if (!status) return
ctx._redirected = true // Used in middleware ctx._redirected = true // Used in middleware
// if only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' }) // if only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' })
@ -96,26 +126,26 @@ export function getContext (context, app) {
path = status path = status
status = 302 status = 302
} }
next({ app.context.next({
path: path, path: path,
query: query, query: query,
status: status status: status
}) })
} }
if (context.req) ctx.req = context.req if (app.context.isServer) app.context.beforeNuxtRender = (fn) => context.beforeRenderFns.push(fn)
if (context.res) ctx.res = context.res if (app.context.isClient) app.context.nuxtState = window.__NUXT__
if (context.from) ctx.from = context.from
if (ctx.isServer && context.beforeRenderFns) {
ctx.beforeNuxtRender = (fn) => context.beforeRenderFns.push(fn)
} }
if (ctx.isClient && window.__NUXT__) { // Dynamic keys
ctx.nuxtState = window.__NUXT__ app.context.next = context.next
} app.context.isHMR = !!context.isHMR
return ctx if (context.route) app.context.route = await getRouteData(context.route)
app.context.params = app.context.route.params || {}
app.context.query = app.context.route.query || {}
if (context.from) app.context.from = await getRouteData(context.from)
} }
export function middlewareSeries (promises, context) { export function middlewareSeries(promises, appContext) {
if (!promises.length || context._redirected) { if (!promises.length || appContext._redirected || appContext.app.nuxt.err) {
return Promise.resolve() return Promise.resolve()
} }
return promisify(promises[0], context) return promisify(promises[0], context)

View File

@ -184,7 +184,7 @@ export default class Builder extends Tapable {
debug('Generating files...') debug('Generating files...')
// -- Templates -- // -- Templates --
let templatesFiles = [ let templatesFiles = [
'App.vue', 'App.js',
'client.js', 'client.js',
'index.js', 'index.js',
'middleware.js', 'middleware.js',
@ -196,7 +196,7 @@ export default class Builder extends Tapable {
'components/nuxt-loading.vue', 'components/nuxt-loading.vue',
'components/nuxt-child.js', 'components/nuxt-child.js',
'components/nuxt-link.js', 'components/nuxt-link.js',
'components/nuxt.vue', 'components/nuxt.js',
'components/no-ssr.js', 'components/no-ssr.js',
'views/app.template.html', 'views/app.template.html',
'views/error.html' 'views/error.html'
@ -215,7 +215,7 @@ export default class Builder extends Tapable {
store: this.options.store, store: this.options.store,
css: this.options.css, css: this.options.css,
plugins: this.plugins, plugins: this.plugins,
appPath: './App.vue', appPath: './App.js',
layouts: Object.assign({}, this.options.layouts), layouts: Object.assign({}, this.options.layouts),
loading: typeof this.options.loading === 'string' ? this.relativeToBuild(this.options.srcDir, this.options.loading) : this.options.loading, loading: typeof this.options.loading === 'string' ? this.relativeToBuild(this.options.srcDir, this.options.loading) : this.options.loading,
transition: this.options.transition, transition: this.options.transition,