@nuxt/vue-app
Advanced tools
Comparing version 2.12.2 to 2.13.0
/*! | ||
* @nuxt/vue-app v2.12.2 (c) 2016-2020 | ||
* @nuxt/vue-app v2.13.0 (c) 2016-2020 | ||
@@ -21,7 +21,7 @@ * - All the amazing contributors | ||
"vue-client-only": "^2.0.0", | ||
"vue-meta": "^2.3.3", | ||
"vue-meta": "^2.4.0", | ||
"vue-no-ssr": "^1.1.1", | ||
"vue-router": "^3.1.6", | ||
"vue-router": "^3.3.4", | ||
"vue-template-compiler": "^2.6.11", | ||
vuex: "^3.1.3" | ||
vuex: "^3.4.0" | ||
}; | ||
@@ -33,7 +33,10 @@ | ||
files: [ | ||
'nuxt/config.json', | ||
'App.js', | ||
'client.js', | ||
'index.js', | ||
'jsonp.js', | ||
'router.js', | ||
'router.scrollBehavior.js', | ||
'routes.json', | ||
'server.js', | ||
@@ -40,0 +43,0 @@ 'utils.js', |
{ | ||
"name": "@nuxt/vue-app", | ||
"version": "2.12.2", | ||
"version": "2.13.0", | ||
"repository": "nuxt/nuxt.js", | ||
@@ -19,7 +19,7 @@ "license": "MIT", | ||
"vue-client-only": "^2.0.0", | ||
"vue-meta": "^2.3.3", | ||
"vue-meta": "^2.4.0", | ||
"vue-no-ssr": "^1.1.1", | ||
"vue-router": "^3.1.6", | ||
"vue-router": "^3.3.4", | ||
"vue-template-compiler": "^2.6.11", | ||
"vuex": "^3.1.3" | ||
"vuex": "^3.4.0" | ||
}, | ||
@@ -26,0 +26,0 @@ "publishConfig": { |
import Vue from 'vue' | ||
<% if (features.asyncData || features.fetch) { %> | ||
import { | ||
getMatchedComponentsInstances, | ||
getChildrenComponentInstancesUsingFetch, | ||
promisify, | ||
globalHandleError, | ||
sanitizeComponent | ||
} from './utils' | ||
<% } %> | ||
<% utilsImports = [ | ||
...(features.asyncData || features.fetch) ? [ | ||
'getMatchedComponentsInstances', | ||
'getChildrenComponentInstancesUsingFetch', | ||
'promisify', | ||
'globalHandleError', | ||
'urlJoin' | ||
] : [], | ||
...features.layouts ? [ | ||
'sanitizeComponent' | ||
]: [] | ||
] %> | ||
<% if (utilsImports.length) { %>import { <%= utilsImports.join(', ') %> } from './utils'<% } %> | ||
<% if (features.layouts && components.ErrorPage) { %>import NuxtError from '<%= components.ErrorPage %>'<% } %> | ||
@@ -57,3 +61,4 @@ <% if (loading) { %>import NuxtLoading from '<%= (typeof loading === "string" ? loading : "./components/nuxt-loading.vue") %>'<% } %> | ||
}, | ||
key: this.layoutName | ||
key: this.layoutName | ||
}, [layoutEl]) | ||
@@ -111,4 +116,4 @@ <% } else { %> | ||
Vue.prototype.<%= globals.nuxt %> = this | ||
// add to window so we can listen when ready | ||
if (process.client) { | ||
// add to window so we can listen when ready | ||
window.<%= globals.nuxt %> = <%= (globals.nuxt !== '$nuxt' ? 'window.$nuxt = ' : '') %>this | ||
@@ -127,6 +132,18 @@ <% if (features.clientOnline) { %> | ||
}, | ||
<% if (loading || isFullStatic) { %> | ||
async mounted () { | ||
<% if (loading) { %>this.$loading = this.$refs.loading<% } %> | ||
<% if (isFullStatic) {%> | ||
if (this.isPreview) { | ||
if (this.$store && this.$store._actions.nuxtServerInit) { | ||
<% if (loading) { %>this.$loading.start()<% } %> | ||
await this.$store.dispatch('nuxtServerInit', this.context) | ||
} | ||
await this.refresh() | ||
<% if (loading) { %>this.$loading.finish()<% } %> | ||
} | ||
<% } %> | ||
}, | ||
<% } %> | ||
<% if (loading) { %> | ||
mounted () { | ||
this.$loading = this.$refs.loading | ||
}, | ||
watch: { | ||
@@ -142,6 +159,9 @@ 'nuxt.err': 'errorChanged' | ||
<% if (features.fetch) { %> | ||
isFetching() { | ||
isFetching () { | ||
return this.nbFetching > 0 | ||
} | ||
<% } %> | ||
},<% } %> | ||
<% if (nuxtOptions.target === 'static') { %> | ||
isPreview () { | ||
return Boolean(this.$options.previewData) | ||
},<% } %> | ||
}, | ||
@@ -261,3 +281,3 @@ <% } %> | ||
}) | ||
} | ||
}, | ||
<% } else { %> | ||
@@ -282,5 +302,28 @@ setLayout (layout) { | ||
return Promise.resolve(layouts['_' + layout]) | ||
} | ||
}, | ||
<% } /* splitChunks.layouts */ %> | ||
<% } /* features.layouts */ %> | ||
<% if (isFullStatic) { %> | ||
setPagePayload(payload) { | ||
this._pagePayload = payload | ||
this._payloadFetchIndex = 0 | ||
}, | ||
async fetchPayload(route) { | ||
const { staticAssetsBase } = window.<%= globals.context %> | ||
const base = (this.$router.options.base || '').replace(/\/+$/, '') | ||
if (base && route.startsWith(base)) { | ||
route = route.substr(base.length) | ||
} | ||
route = (route.replace(/\/+$/, '') || '/').split('?')[0] | ||
const src = urlJoin(base, staticAssetsBase, route, 'payload.js') | ||
try { | ||
const payload = await window.__NUXT_IMPORT__(decodeURI(route), encodeURI(src)) | ||
this.setPagePayload(payload) | ||
return payload | ||
} catch (err) { | ||
this.setPagePayload(false) | ||
throw err | ||
} | ||
} | ||
<% } %> | ||
}, | ||
@@ -287,0 +330,0 @@ <% if (loading) { %> |
@@ -22,2 +22,3 @@ import Vue from 'vue' | ||
import NuxtLink from './components/nuxt-link.<%= features.clientPrefetch ? "client" : "server" %>.js' // should be included after ./index.js | ||
<% if (isFullStatic) { %>import './jsonp'<% } %> | ||
@@ -52,4 +53,4 @@ <% if (features.fetch) { %> | ||
if (logs.length > 0) { | ||
const ssrLogSyle = 'background: #2E495E;border-radius: 0.5em;color: white;font-weight: bold;padding: 2px 0.5em;' | ||
console.group && console.group<%= nuxtOptions.render.ssrLog === 'collapsed' ? 'Collapsed' : '' %> ('%cNuxt SSR', ssrLogSyle) | ||
const ssrLogStyle = 'background: #2E495E;border-radius: 0.5em;color: white;font-weight: bold;padding: 2px 0.5em;' | ||
console.group && console.group<%= nuxtOptions.render.ssrLog === 'collapsed' ? 'Collapsed' : '' %> ('%cNuxt SSR', ssrLogStyle) | ||
logs.forEach(logObj => (console[logObj.type] || console.log)(...logObj.args)) | ||
@@ -102,3 +103,3 @@ delete NUXT.logs | ||
// Create and mount App | ||
createApp().then(mountApp).catch(errorHandler) | ||
createApp(null, NUXT.config).then(mountApp).catch(errorHandler) | ||
@@ -142,3 +143,3 @@ <% if (features.transitions) { %> | ||
<% } %> | ||
<% if (loading) { %>async <% } %>function loadAsyncComponents (to, from, next) { | ||
async function loadAsyncComponents (to, from, next) { | ||
// Check if route changed (this._routeChanged), only if the page is not an error (for validate()) | ||
@@ -157,3 +158,2 @@ this._routeChanged = Boolean(app.nuxt.err) || from.name !== to.name | ||
try { | ||
<% if (loading) { %> | ||
if (this._queryChanged) { | ||
@@ -178,7 +178,8 @@ const Components = await resolveRouteComponents( | ||
}) | ||
<% if (loading) { %> | ||
if (startLoader && this.$loading.start && !this.$loading.manual) { | ||
this.$loading.start() | ||
} | ||
<% } %> | ||
} | ||
<% } %> | ||
// Call next() | ||
@@ -438,3 +439,3 @@ next() | ||
// Call asyncData & fetch hooks on components matched by the route. | ||
await Promise.all(Components.map((Component, i) => { | ||
await Promise.all(Components.map(async (Component, i) => { | ||
// Check if only children route changed | ||
@@ -494,11 +495,23 @@ Component._path = compile(to.matched[matches[i]].path)(to.params) | ||
if (hasAsyncData) { | ||
<% if (isFullStatic) { %> | ||
let promise | ||
if (this.isPreview) { | ||
promise = promisify(Component.options.asyncData, app.context) | ||
} else { | ||
promise = this.fetchPayload(to.path) | ||
.then(payload => payload.data[i]) | ||
.catch(_err => promisify(Component.options.asyncData, app.context)) // Fallback | ||
} | ||
<% } else { %> | ||
const promise = promisify(Component.options.asyncData, app.context) | ||
.then((asyncDataResult) => { | ||
applyAsyncData(Component, asyncDataResult) | ||
<% if (loading) { %> | ||
if (this.$loading.increase) { | ||
this.$loading.increase(loadingIncrease) | ||
} | ||
<% } %> | ||
}) | ||
<% } %> | ||
promise.then((asyncDataResult) => { | ||
applyAsyncData(Component, asyncDataResult) | ||
<% if (loading) { %> | ||
if (this.$loading.increase) { | ||
this.$loading.increase(loadingIncrease) | ||
} | ||
<% } %> | ||
}) | ||
promises.push(promise) | ||
@@ -508,2 +521,9 @@ } | ||
<% if (isFullStatic && store) { %> | ||
// Replay store mutations, catching to avoid error page on SPA fallback | ||
promises.push(this.fetchPayload(to.path).then(payload => { | ||
payload.mutations.forEach(m => { this.$store.commit(m[0], m[1]) }) | ||
}).catch(err => null)) | ||
<% } %> | ||
// Check disabled page loading | ||
@@ -513,2 +533,8 @@ this.$loading.manual = Component.options.loading === false | ||
<% if (features.fetch) { %> | ||
<% if (isFullStatic) { %> | ||
if (!this.isPreview) { | ||
// Catching the error here for letting the SPA fallback and normal fetch behaviour | ||
promises.push(this.fetchPayload(to.path).catch(err => null)) | ||
} | ||
<% } %> | ||
// Call fetch(context) | ||
@@ -582,9 +608,4 @@ if (hasFetch) { | ||
function showNextPage (to) { | ||
// Hide error component if no error | ||
if (this._hadError && this._dateLastError === this.$options.nuxt.dateErr) { | ||
this.error() | ||
} | ||
<% if (features.layouts) { %> | ||
<% if (features.layouts) { %> | ||
function setLayoutForNextPage (to) { | ||
// Set layout | ||
@@ -599,5 +620,12 @@ let layout = this.$options.nuxt.err | ||
this.setLayout(layout) | ||
<% } %> | ||
} | ||
<% } %> | ||
function checkForErrors (app) { | ||
// Hide error component if no error | ||
if (app._hadError && app._dateLastError === app.$options.nuxt.dateErr) { | ||
app.error() | ||
} | ||
} | ||
// When navigating on a different route but the same component is used, Vue.js | ||
@@ -636,3 +664,3 @@ // Will not update the instance data, so we have to update $data ourselves | ||
}) | ||
showNextPage.call(this, to) | ||
checkForErrors(this) | ||
<% if (isDev) { %> | ||
@@ -784,3 +812,3 @@ // Hot reloading | ||
<% if (features.layouts || features.transitions) { %>async <% } %>function mountApp (__app) { | ||
async function mountApp (__app) { | ||
// Set global variables | ||
@@ -794,2 +822,12 @@ app = __app.app | ||
<% if (isFullStatic) { %> | ||
// Load page chunk | ||
if (!NUXT.data && NUXT.serverRendered) { | ||
try { | ||
const payload = await _app.fetchPayload(_app.context.route.path) | ||
Object.assign(NUXT, payload) | ||
} catch (err) {} | ||
} | ||
<% } %> | ||
<% if (features.layouts && mode !== 'spa') { %> | ||
@@ -808,2 +846,5 @@ // Load layout | ||
router.afterEach(normalizeComponents) | ||
<% if (features.layouts) { %> | ||
router.afterEach(setLayoutForNextPage.bind(_app)) | ||
<% } %> | ||
router.afterEach(fixPrepatch.bind(_app)) | ||
@@ -844,2 +885,6 @@ | ||
// Fix in static: remove trailing slash to force hydration | ||
if (process.static && NUXT.serverRendered && NUXT.routePath !== '/' && NUXT.routePath.slice(-1) !== '/' && _app.context.route.path.slice(-1) === '/') { | ||
_app.context.route.path = _app.context.route.path.replace(/\/+$/, '') | ||
} | ||
// If page already is server rendered and it was done on the same route path as client side render | ||
@@ -854,3 +899,4 @@ if (NUXT.serverRendered && NUXT.routePath === _app.context.route.path) { | ||
normalizeComponents(router.currentRoute, router.currentRoute) | ||
showNextPage.call(_app, router.currentRoute) | ||
setLayoutForNextPage.call(_app, router.currentRoute) | ||
checkForErrors(_app) | ||
// Don't call fixPrepatch.call(_app, router.currentRoute, router.currentRoute) since it's first render | ||
@@ -860,2 +906,4 @@ mount() | ||
// fix: force next tick to avoid having same timestamp when an error happen on spa fallback | ||
await new Promise(resolve => setTimeout(resolve, 0)) | ||
render.call(_app, router.currentRoute, router.currentRoute, (path) => { | ||
@@ -862,0 +910,0 @@ // If not redirected |
@@ -74,3 +74,8 @@ import Vue from 'vue' | ||
shouldPrefetch () { | ||
return this.getPrefetchComponents().length > 0 | ||
<% if (isFullStatic && router.prefetchPayloads) { %> | ||
const ref = this.$router.resolve(this.to, this.$route, this.append) | ||
const Components = ref.resolved.matched.map(r => r.components.default) | ||
return Components.filter(Component => ref.href || (typeof Component === 'function' && !Component.options && !Component.__prefetched)).length | ||
<% } else { %>return this.getPrefetchComponents().length > 0<% } %> | ||
}, | ||
@@ -105,5 +110,13 @@ canPrefetch () { | ||
Component.__prefetched = true | ||
}<% if (router.linkPrefetchedClass) { %> | ||
return Promise.all(promises).then(() => this.addPrefetchedClass()) | ||
} | ||
<% if (isFullStatic && router.prefetchPayloads) { %> | ||
// Preload the data only if not in preview mode | ||
if (!this.$root.isPreview) { | ||
const { href } = this.$router.resolve(this.to, this.$route, this.append) | ||
this.$nuxt.fetchPayload(href).catch(() => {}) | ||
} | ||
<% } %> | ||
<% if (router.linkPrefetchedClass) { %> | ||
return Promise.all(promises).then(() => this.addPrefetchedClass()) | ||
<% } %> | ||
}<% if (router.linkPrefetchedClass) { %>, | ||
@@ -110,0 +123,0 @@ addPrefetchedClass () { |
@@ -86,3 +86,3 @@ import Vue from 'vue' | ||
// if an error occured within NuxtError show a simple | ||
// if an error occurred within NuxtError show a simple | ||
// error message instead to prevent looping | ||
@@ -93,4 +93,4 @@ if (this.errorFromNuxtError) { | ||
return h('div', {}, [ | ||
h('h2', 'An error occured while showing the error page'), | ||
h('p', 'Unfortunately an error occured and while showing the error page another error occured'), | ||
h('h2', 'An error occurred while showing the error page'), | ||
h('p', 'Unfortunately an error occurred and while showing the error page another error occurred'), | ||
h('p', `Error details: ${this.errorFromNuxtError.toString()}`), | ||
@@ -97,0 +97,0 @@ h('nuxt-link', { props: { to: '/' } }, 'Go back to home') |
@@ -69,3 +69,3 @@ import Vue from 'vue' | ||
async function createApp (ssrContext) { | ||
async function createApp(ssrContext, config = {}) { | ||
const router = await createRouter(ssrContext) | ||
@@ -166,4 +166,3 @@ | ||
<% if (plugins.length) { %> | ||
const inject = function (key, value) { | ||
function inject(key, value) { | ||
if (!key) { | ||
@@ -179,2 +178,6 @@ throw new Error('inject(key, value) has no key provided') | ||
app[key] = value | ||
// Add into context | ||
if (!app.context[key]) { | ||
app.context[key] = value | ||
} | ||
<% if (store) { %> | ||
@@ -201,4 +204,6 @@ // Add into store | ||
} | ||
<% } %> | ||
// Inject runtime config as $config | ||
inject('config', config) | ||
<% if (store) { %> | ||
@@ -213,2 +218,9 @@ if (process.client) { | ||
// Add enablePreview(previewData = {}) in context for plugins | ||
if (process.static && process.client) { | ||
app.context.enablePreview = function (previewData = {}) { | ||
app.previewData = Object.assign({}, previewData) | ||
inject('preview', previewData) | ||
} | ||
} | ||
// Plugin execution | ||
@@ -232,2 +244,8 @@ <%= isTest ? '/* eslint-disable camelcase */' : '' %> | ||
<%= isTest ? '/* eslint-enable camelcase */' : '' %> | ||
// Lock enablePreview in context | ||
if (process.static && process.client) { | ||
app.context.enablePreview = function () { | ||
console.warn('You cannot call enablePreview() outside a plugin.') | ||
} | ||
} | ||
@@ -234,0 +252,0 @@ // If server-side, wait for async component to be resolved first |
@@ -35,2 +35,3 @@ import Vue from 'vue' | ||
if (!isSsrHydration(this)) { | ||
<% if (isFullStatic) { %>createdFullStatic.call(this)<% } %> | ||
return | ||
@@ -56,2 +57,29 @@ } | ||
<% if (isFullStatic) { %> | ||
function createdFullStatic() { | ||
// Check if component has been fetched on server | ||
let fetchedOnServer = this.$options.fetchOnServer !== false | ||
if (typeof this.$options.fetchOnServer === 'function') { | ||
fetchedOnServer = this.$options.fetchOnServer.call(this) !== false | ||
} | ||
if (!fetchedOnServer || this.$nuxt.isPreview || !this.$nuxt._pagePayload) { | ||
return | ||
} | ||
this._hydrated = true | ||
this._fetchKey = this.$nuxt._payloadFetchIndex++ | ||
const data = this.$nuxt._pagePayload.fetch[this._fetchKey] | ||
// If fetch error | ||
if (data && data._error) { | ||
this.$fetchState.error = data._error | ||
return | ||
} | ||
// Merge data | ||
for (const key in data) { | ||
Vue.set(this.$data, key, data[key]) | ||
} | ||
} | ||
<% } %> | ||
function $fetch() { | ||
@@ -76,2 +104,5 @@ if (!this._fetchPromise) { | ||
} catch (err) { | ||
if (process.dev) { | ||
console.error('Error in fetch():', err) | ||
} | ||
error = normalizeError(err) | ||
@@ -91,2 +122,1 @@ } | ||
} | ||
@@ -13,2 +13,5 @@ import Vue from 'vue' | ||
} catch (err) { | ||
if (process.dev) { | ||
console.error('Error in fetch():', err) | ||
} | ||
this.$fetchState.error = normalizeError(err) | ||
@@ -31,3 +34,3 @@ } | ||
export default { | ||
beforeCreate() { | ||
created() { | ||
if (!hasFetch(this)) { | ||
@@ -34,0 +37,0 @@ return |
@@ -40,5 +40,5 @@ import { stringify } from 'querystring' | ||
const createNext = ssrContext => (opts) => { | ||
// If static target, render on client-side | ||
ssrContext.redirected = opts | ||
// If nuxt generate | ||
if (!ssrContext.res) { | ||
if (ssrContext.target === 'static' || !ssrContext.res) { | ||
ssrContext.nuxt.serverRendered = false | ||
@@ -75,6 +75,12 @@ return | ||
ssrContext.beforeRenderFns = [] | ||
// Nuxt object (window{{globals.context}}, defaults to window.__NUXT__) | ||
// Nuxt object (window.{{globals.context}}, defaults to window.__NUXT__) | ||
ssrContext.nuxt = { <% if (features.layouts) { %>layout: 'default', <% } %>data: [], <% if (features.fetch) { %>fetch: [], <% } %>error: null<%= (store ? ', state: null' : '') %>, serverRendered: true, routePath: '' } | ||
// Remove query from url is static target | ||
if (process.static && ssrContext.url) { | ||
ssrContext.url = ssrContext.url.split('?')[0] | ||
} | ||
// Public runtime config | ||
ssrContext.nuxt.config = ssrContext.runtimeConfig.public | ||
// Create the app definition and the instance (created for each request) | ||
const { app, router<%= (store ? ', store' : '') %> } = await createApp(ssrContext) | ||
const { app, router<%= (store ? ', store' : '') %> } = await createApp(ssrContext, { ...ssrContext.runtimeConfig.public, ...ssrContext.runtimeConfig.private }) | ||
const _app = new Vue(app) | ||
@@ -100,2 +106,6 @@ // Add ssr route path to nuxt context so we can account for page navigation between ssr and csr | ||
ssrContext.nuxt.state = store.state | ||
<% if (isFullStatic && store) { %> | ||
// Stop recording store mutations | ||
ssrContext.unsetMutationObserver() | ||
<% } %> | ||
} | ||
@@ -106,2 +116,6 @@ <% } %> | ||
const renderErrorPage = async () => { | ||
// Don't server-render the page in static target | ||
if (ssrContext.target === 'static') { | ||
ssrContext.nuxt.serverRendered = false | ||
} | ||
<% if (features.layouts) { %> | ||
@@ -173,2 +187,8 @@ // Load layout for error page | ||
<% if (isFullStatic && store) { %> | ||
// Record store mutations for full-static after nuxtServerInit and Middleware | ||
ssrContext.nuxt.mutations =[] | ||
ssrContext.unsetMutationObserver = store.subscribe(m => { ssrContext.nuxt.mutations.push([m.type, m.payload]) }) | ||
<% } %> | ||
<% if (features.layouts) { %> | ||
@@ -253,6 +273,2 @@ /* | ||
if (!isValid) { | ||
// Don't server-render the page in generate mode | ||
if (ssrContext._generate) { | ||
ssrContext.nuxt.serverRendered = false | ||
} | ||
// Render a 404 error page | ||
@@ -259,0 +275,0 @@ return render404Page() |
@@ -159,6 +159,6 @@ import Vue from 'vue' | ||
// Only set once | ||
if (context.req) { | ||
if (!process.static && context.req) { | ||
app.context.req = context.req | ||
} | ||
if (context.res) { | ||
if (!process.static && context.res) { | ||
app.context.res = context.res | ||
@@ -600,3 +600,7 @@ } | ||
let path = parts.filter(Boolean).join('/') | ||
let path = parts.join('/') | ||
if (path === '' && parts.length === 1) { | ||
result += '/' | ||
} | ||
let hash | ||
@@ -647,1 +651,9 @@ parts = path.split('#') | ||
} | ||
export const urlJoin = function urlJoin () { | ||
return [].slice | ||
.call(arguments) | ||
.join('/') | ||
.replace(/\/+/g, '/') | ||
.replace(':/', '://') | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
155265
44
3281
Updatedvue-meta@^2.4.0
Updatedvue-router@^3.3.4
Updatedvuex@^3.4.0