UNPKG

29.1 kBJavaScriptView Raw
1import Vue from 'vue'
2<% if (fetch.client) { %>import fetch from 'unfetch'<% } %>
3<% if (features.middleware) { %>import middleware from './middleware.js'<% } %>
4import {
5 <% if (features.asyncData) { %>applyAsyncData,
6 promisify,<% } %>
7 <% if (features.middleware) { %>middlewareSeries,<% } %>
8 <% if (features.transitions || (features.middleware && features.layouts)) { %>sanitizeComponent,<% } %>
9 resolveRouteComponents,
10 getMatchedComponents,
11 getMatchedComponentsInstances,
12 flatMapComponents,
13 setContext,
14 <% if (features.transitions || features.asyncData || features.fetch) { %>getLocation,<% } %>
15 compile,
16 getQueryDiff,
17 globalHandleError,
18 isSamePath
19} from './utils.js'
20import { createApp<% if (features.layouts) { %>, NuxtError<% } %> } from './index.js'
21<% if (features.fetch) { %>import fetchMixin from './mixins/fetch.client'<% } %>
22import NuxtLink from './components/nuxt-link.<%= features.clientPrefetch ? "client" : "server" %>.js' // should be included after ./index.js
23<% if (isFullStatic) { %>import './jsonp'<% } %>
24
25<% if (features.fetch) { %>
26// Fetch mixin
27if (!Vue.__nuxt__fetch__mixin__) {
28 Vue.mixin(fetchMixin)
29 Vue.__nuxt__fetch__mixin__ = true
30}
31<% } %>
32
33// Component: <NuxtLink>
34Vue.component(NuxtLink.name, NuxtLink)
35<% if (features.componentAliases) { %>Vue.component('NLink', NuxtLink)<% } %>
36
37<% if (fetch.client) { %>if (!global.fetch) { global.fetch = fetch }<% } %>
38
39// Global shared references
40let _lastPaths = []<%= isTest ? '// eslint-disable-line no-unused-vars' : '' %>
41let app
42let router
43<% if (store) { %>let store<%= isTest ? '// eslint-disable-line no-unused-vars' : '' %><% } %>
44
45// Try to rehydrate SSR data from window
46const NUXT = window.<%= globals.context %> || {}
47
48Object.assign(Vue.config, <%= serialize(vue.config) %>)<%= isTest ? '// eslint-disable-line' : '' %>
49
50<% if (nuxtOptions.render.ssrLog) { %>
51const logs = NUXT.logs || []
52 if (logs.length > 0) {
53 const ssrLogStyle = 'background: #2E495E;border-radius: 0.5em;color: white;font-weight: bold;padding: 2px 0.5em;'
54 console.group && console.group<%= nuxtOptions.render.ssrLog === 'collapsed' ? 'Collapsed' : '' %> ('%cNuxt SSR', ssrLogStyle)
55 logs.forEach(logObj => (console[logObj.type] || console.log)(...logObj.args))
56 delete NUXT.logs
57 console.groupEnd && console.groupEnd()
58}
59<% } %>
60<% if (debug) { %>
61// Setup global Vue error handler
62if (!Vue.config.$nuxt) {
63 const defaultErrorHandler = Vue.config.errorHandler
64 Vue.config.errorHandler = async (err, vm, info, ...rest) => {
65 // Call other handler if exist
66 let handled = null
67 if (typeof defaultErrorHandler === 'function') {
68 handled = defaultErrorHandler(err, vm, info, ...rest)
69 }
70 if (handled === true) {
71 return handled
72 }
73
74 if (vm && vm.$root) {
75 const nuxtApp = Object.keys(Vue.config.$nuxt)
76 .find(nuxtInstance => vm.$root[nuxtInstance])
77
78 // Show Nuxt Error Page
79 if (nuxtApp && vm.$root[nuxtApp].error && info !== 'render function') {
80 const currentApp = vm.$root[nuxtApp]
81 <% if (features.layouts) { %>
82 // Load error layout
83 let layout = (NuxtError.options || NuxtError).layout
84 if (typeof layout === 'function') {
85 layout = layout(currentApp.context)
86 }
87 if (layout) {
88 await currentApp.loadLayout(layout).catch(() => {})
89 }
90 currentApp.setLayout(layout)
91 <% } %>
92 currentApp.error(err)
93 }
94 }
95
96 if (typeof defaultErrorHandler === 'function') {
97 return handled
98 }
99
100 // Log to console
101 if (process.env.NODE_ENV !== 'production') {
102 console.error(err)
103 } else {
104 console.error(err.message || err)
105 }
106 }
107 Vue.config.$nuxt = {}
108}
109Vue.config.$nuxt.<%= globals.nuxt %> = true
110<% } %>
111const errorHandler = Vue.config.errorHandler || console.error
112
113// Create and mount App
114createApp(null, NUXT.config).then(mountApp).catch(errorHandler)
115
116<% if (features.transitions) { %>
117function componentOption (component, key, ...args) {
118 if (!component || !component.options || !component.options[key]) {
119 return {}
120 }
121 const option = component.options[key]
122 if (typeof option === 'function') {
123 return option(...args)
124 }
125 return option
126}
127
128function mapTransitions (toComponents, to, from) {
129 const componentTransitions = (component) => {
130 const transition = componentOption(component, 'transition', to, from) || {}
131 return (typeof transition === 'string' ? { name: transition } : transition)
132 }
133
134 const fromComponents = from ? getMatchedComponents(from) : []
135 const maxDepth = Math.max(toComponents.length, fromComponents.length)
136
137 const mergedTransitions = []
138 for (let i=0; i<maxDepth; i++) {
139 // Clone original objects to prevent overrides
140 const toTransitions = Object.assign({}, componentTransitions(toComponents[i]))
141 const transitions = Object.assign({}, componentTransitions(fromComponents[i]))
142
143 // Combine transitions & prefer `leave` properties of "from" route
144 Object.keys(toTransitions)
145 .filter(key => typeof toTransitions[key] !== 'undefined' && !key.toLowerCase().includes('leave'))
146 .forEach((key) => { transitions[key] = toTransitions[key] })
147
148 mergedTransitions.push(transitions)
149 }
150 return mergedTransitions
151}
152<% } %>
153async function loadAsyncComponents (to, from, next) {
154 // Check if route changed (this._routeChanged), only if the page is not an error (for validate())
155 this._routeChanged = Boolean(app.nuxt.err) || from.name !== to.name
156 this._paramChanged = !this._routeChanged && from.path !== to.path
157 this._queryChanged = !this._paramChanged && from.fullPath !== to.fullPath
158 this._diffQuery = (this._queryChanged ? getQueryDiff(to.query, from.query) : [])
159
160 <% if (loading) { %>
161 if ((this._routeChanged || this._paramChanged) && this.$loading.start && !this.$loading.manual) {
162 this.$loading.start()
163 }
164 <% } %>
165
166 try {
167 if (this._queryChanged) {
168 const Components = await resolveRouteComponents(
169 to,
170 (Component, instance) => ({ Component, instance })
171 )
172 // Add a marker on each component that it needs to refresh or not
173 const startLoader = Components.some(({ Component, instance }) => {
174 const watchQuery = Component.options.watchQuery
175 if (watchQuery === true) {
176 return true
177 }
178 if (Array.isArray(watchQuery)) {
179 return watchQuery.some(key => this._diffQuery[key])
180 }
181 if (typeof watchQuery === 'function') {
182 return watchQuery.apply(instance, [to.query, from.query])
183 }
184 return false
185 })
186 <% if (loading) { %>
187 if (startLoader && this.$loading.start && !this.$loading.manual) {
188 this.$loading.start()
189 }
190 <% } %>
191 }
192 // Call next()
193 next()
194 } catch (error) {
195 const err = error || {}
196 const statusCode = err.statusCode || err.status || (err.response && err.response.status) || 500
197 const message = err.message || ''
198
199 // Handle chunk loading errors
200 // This may be due to a new deployment or a network problem
201 if (/^Loading( CSS)? chunk (\d)+ failed\./.test(message)) {
202 window.location.reload(true /* skip cache */)
203 return // prevent error page blinking for user
204 }
205
206 this.error({ statusCode, message })
207 this.<%= globals.nuxt %>.$emit('routeChanged', to, from, err)
208 next()
209 }
210}
211
212<% if (features.transitions || features.asyncData || features.fetch) { %>
213function applySSRData (Component, ssrData) {
214 <% if (features.asyncData) { %>
215 if (NUXT.serverRendered && ssrData) {
216 applyAsyncData(Component, ssrData)
217 }
218 <% } %>
219 Component._Ctor = Component
220 return Component
221}
222
223// Get matched components
224function resolveComponents (router) {
225 const path = getLocation(router.options.base, router.options.mode)
226
227 return flatMapComponents(router.match(path), async (Component, _, match, key, index) => {
228 // If component is not resolved yet, resolve it
229 if (typeof Component === 'function' && !Component.options) {
230 Component = await Component()
231 }
232 // Sanitize it and save it
233 const _Component = applySSRData(sanitizeComponent(Component), NUXT.data ? NUXT.data[index] : null)
234 match.components[key] = _Component
235 return _Component
236 })
237}
238<% } %>
239
240<% if (features.middleware) { %>
241function callMiddleware (Components, context, layout) {
242 let midd = <%= devalue(router.middleware) %><%= isTest ? '// eslint-disable-line' : '' %>
243 let unknownMiddleware = false
244
245 <% if (features.layouts) { %>
246 // If layout is undefined, only call global middleware
247 if (typeof layout !== 'undefined') {
248 midd = [] // Exclude global middleware if layout defined (already called before)
249 layout = sanitizeComponent(layout)
250 if (layout.options.middleware) {
251 midd = midd.concat(layout.options.middleware)
252 }
253 Components.forEach((Component) => {
254 if (Component.options.middleware) {
255 midd = midd.concat(Component.options.middleware)
256 }
257 })
258 }
259 <% } %>
260
261 midd = midd.map((name) => {
262 if (typeof name === 'function') {
263 return name
264 }
265 if (typeof middleware[name] !== 'function') {
266 unknownMiddleware = true
267 this.error({ statusCode: 500, message: 'Unknown middleware ' + name })
268 }
269 return middleware[name]
270 })
271
272 if (unknownMiddleware) {
273 return
274 }
275 return middlewareSeries(midd, context)
276}
277<% } else if (isDev) {
278// This is a placeholder function mainly so we dont have to
279// refactor the promise chain in addHotReload()
280%>
281function callMiddleware () {
282 return Promise.resolve(true)
283}
284<% } %>
285async function render (to, from, next) {
286 if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) {
287 return next()
288 }
289 // Handle first render on SPA mode
290 let spaFallback = false
291 if (to === from) {
292 _lastPaths = []
293 spaFallback = true
294 } else {
295 const fromMatches = []
296 _lastPaths = getMatchedComponents(from, fromMatches).map((Component, i) => {
297 return compile(from.matched[fromMatches[i]].path)(from.params)
298 })
299 }
300
301 // nextCalled is true when redirected
302 let nextCalled = false
303 const _next = (path) => {
304 <% if (loading) { %>
305 if (from.path === path.path && this.$loading.finish) {
306 this.$loading.finish()
307 }
308 <% } %>
309 <% if (loading) { %>
310 if (from.path !== path.path && this.$loading.pause) {
311 this.$loading.pause()
312 }
313 <% } %>
314 if (nextCalled) {
315 return
316 }
317
318 nextCalled = true
319 next(path)
320 }
321
322 // Update context
323 await setContext(app, {
324 route: to,
325 from,
326 next: _next.bind(this)
327 })
328 this._dateLastError = app.nuxt.dateErr
329 this._hadError = Boolean(app.nuxt.err)
330
331 // Get route's matched components
332 const matches = []
333 const Components = getMatchedComponents(to, matches)
334
335 // If no Components matched, generate 404
336 if (!Components.length) {
337 <% if (features.middleware) { %>
338 // Default layout
339 await callMiddleware.call(this, Components, app.context)
340 if (nextCalled) {
341 return
342 }
343 <% } %>
344
345 <% if (features.layouts) { %>
346 // Load layout for error page
347 const errorLayout = (NuxtError.options || NuxtError).layout
348 const layout = await this.loadLayout(
349 typeof errorLayout === 'function'
350 ? errorLayout.call(NuxtError, app.context)
351 : errorLayout
352 )
353 <% } %>
354
355 <% if (features.middleware) { %>
356 await callMiddleware.call(this, Components, app.context, layout)
357 if (nextCalled) {
358 return
359 }
360 <% } %>
361
362 // Show error page
363 app.context.error({ statusCode: 404, message: '<%= messages.error_404 %>' })
364 return next()
365 }
366
367 <% if (features.asyncData || features.fetch) { %>
368 // Update ._data and other properties if hot reloaded
369 Components.forEach((Component) => {
370 if (Component._Ctor && Component._Ctor.options) {
371 <% if (features.asyncData) { %>Component.options.asyncData = Component._Ctor.options.asyncData<% } %>
372 <% if (features.fetch) { %>Component.options.fetch = Component._Ctor.options.fetch<% } %>
373 }
374 })
375 <% } %>
376
377 <% if (features.transitions) { %>
378 // Apply transitions
379 this.setTransitions(mapTransitions(Components, to, from))
380 <% } %>
381 try {
382 <% if (features.middleware) { %>
383 // Call middleware
384 await callMiddleware.call(this, Components, app.context)
385 if (nextCalled) {
386 return
387 }
388 if (app.context._errored) {
389 return next()
390 }
391 <% } %>
392
393 <% if (features.layouts) { %>
394 // Set layout
395 let layout = Components[0].options.layout
396 if (typeof layout === 'function') {
397 layout = layout(app.context)
398 }
399 layout = await this.loadLayout(layout)
400 <% } %>
401
402 <% if (features.middleware) { %>
403 // Call middleware for layout
404 await callMiddleware.call(this, Components, app.context, layout)
405 if (nextCalled) {
406 return
407 }
408 if (app.context._errored) {
409 return next()
410 }
411 <% } %>
412
413
414 <% if (features.validate) { %>
415 // Call .validate()
416 let isValid = true
417 try {
418 for (const Component of Components) {
419 if (typeof Component.options.validate !== 'function') {
420 continue
421 }
422
423 isValid = await Component.options.validate(app.context)
424
425 if (!isValid) {
426 break
427 }
428 }
429 } catch (validationError) {
430 // ...If .validate() threw an error
431 this.error({
432 statusCode: validationError.statusCode || '500',
433 message: validationError.message
434 })
435 return next()
436 }
437
438 // ...If .validate() returned false
439 if (!isValid) {
440 this.error({ statusCode: 404, message: '<%= messages.error_404 %>' })
441 return next()
442 }
443 <% } %>
444
445 <% if (features.asyncData || features.fetch) { %>
446 let instances
447 // Call asyncData & fetch hooks on components matched by the route.
448 await Promise.all(Components.map(async (Component, i) => {
449 // Check if only children route changed
450 Component._path = compile(to.matched[matches[i]].path)(to.params)
451 Component._dataRefresh = false
452 const childPathChanged = Component._path !== _lastPaths[i]
453 // Refresh component (call asyncData & fetch) when:
454 // Route path changed part includes current component
455 // Or route param changed part includes current component and watchParam is not `false`
456 // Or route query is changed and watchQuery returns `true`
457 if (this._routeChanged && childPathChanged) {
458 Component._dataRefresh = true
459 } else if (this._paramChanged && childPathChanged) {
460 const watchParam = Component.options.watchParam
461 Component._dataRefresh = watchParam !== false
462 } else if (this._queryChanged) {
463 const watchQuery = Component.options.watchQuery
464 if (watchQuery === true) {
465 Component._dataRefresh = true
466 } else if (Array.isArray(watchQuery)) {
467 Component._dataRefresh = watchQuery.some(key => this._diffQuery[key])
468 } else if (typeof watchQuery === 'function') {
469 if (!instances) {
470 instances = getMatchedComponentsInstances(to)
471 }
472 Component._dataRefresh = watchQuery.apply(instances[i], [to.query, from.query])
473 }
474 }
475 if (!this._hadError && this._isMounted && !Component._dataRefresh) {
476 return
477 }
478
479 const promises = []
480
481 <% if (features.asyncData) { %>
482 const hasAsyncData = (
483 Component.options.asyncData &&
484 typeof Component.options.asyncData === 'function'
485 )
486 <% } else { %>
487 const hasAsyncData = false
488 <% } %>
489
490 <% if (features.fetch) { %>
491 const hasFetch = Boolean(Component.options.fetch) && Component.options.fetch.length
492 <% } else { %>
493 const hasFetch = false
494 <% } %>
495
496 <% if (loading) { %>
497 const loadingIncrease = (hasAsyncData && hasFetch) ? 30 : 45
498 <% } %>
499
500 <% if (features.asyncData) { %>
501 // Call asyncData(context)
502 if (hasAsyncData) {
503 <% if (isFullStatic) { %>
504 let promise
505
506 if (this.isPreview || spaFallback) {
507 promise = promisify(Component.options.asyncData, app.context)
508 } else {
509 promise = this.fetchPayload(to.path)
510 .then(payload => payload.data[i])
511 .catch(_err => promisify(Component.options.asyncData, app.context)) // Fallback
512 }
513 <% } else { %>
514 const promise = promisify(Component.options.asyncData, app.context)
515 <% } %>
516 promise.then((asyncDataResult) => {
517 applyAsyncData(Component, asyncDataResult)
518 <% if (loading) { %>
519 if (this.$loading.increase) {
520 this.$loading.increase(loadingIncrease)
521 }
522 <% } %>
523 })
524 promises.push(promise)
525 }
526 <% } %>
527
528 <% if (isFullStatic && store) { %>
529 if (!this.isPreview && !spaFallback) {
530 // Replay store mutations, catching to avoid error page on SPA fallback
531 promises.push(this.fetchPayload(to.path).then(payload => {
532 payload.mutations.forEach(m => { this.$store.commit(m[0], m[1]) })
533 }).catch(err => null))
534 }
535 <% } %>
536
537 // Check disabled page loading
538 this.$loading.manual = Component.options.loading === false
539
540 <% if (features.fetch) { %>
541 <% if (isFullStatic) { %>
542 if (!this.isPreview && !spaFallback) {
543 // Catching the error here for letting the SPA fallback and normal fetch behaviour
544 promises.push(this.fetchPayload(to.path).catch(err => null))
545 }
546 <% } %>
547 // Call fetch(context)
548 if (hasFetch) {
549 let p = Component.options.fetch(app.context)
550 if (!p || (!(p instanceof Promise) && (typeof p.then !== 'function'))) {
551 p = Promise.resolve(p)
552 }
553 p.then((fetchResult) => {
554 <% if (loading) { %>
555 if (this.$loading.increase) {
556 this.$loading.increase(loadingIncrease)
557 }
558 <% } %>
559 })
560 promises.push(p)
561 }
562 <% } %>
563
564 return Promise.all(promises)
565 }))
566 <% } %>
567
568 // If not redirected
569 if (!nextCalled) {
570 <% if (loading) { %>
571 if (this.$loading.finish && !this.$loading.manual) {
572 this.$loading.finish()
573 }
574 <% } %>
575 next()
576 }
577
578 } catch (err) {
579 const error = err || {}
580 if (error.message === 'ERR_REDIRECT') {
581 return this.<%= globals.nuxt %>.$emit('routeChanged', to, from, error)
582 }
583 _lastPaths = []
584
585 globalHandleError(error)
586
587 <% if (features.layouts) { %>
588 // Load error layout
589 let layout = (NuxtError.options || NuxtError).layout
590 if (typeof layout === 'function') {
591 layout = layout(app.context)
592 }
593 await this.loadLayout(layout)
594 <% } %>
595
596 this.error(error)
597 this.<%= globals.nuxt %>.$emit('routeChanged', to, from, error)
598 next()
599 }
600}
601
602// Fix components format in matched, it's due to code-splitting of vue-router
603function normalizeComponents (to, ___) {
604 flatMapComponents(to, (Component, _, match, key) => {
605 if (typeof Component === 'object' && !Component.options) {
606 // Updated via vue-router resolveAsyncComponents()
607 Component = Vue.extend(Component)
608 Component._Ctor = Component
609 match.components[key] = Component
610 }
611 return Component
612 })
613}
614
615<% if (features.layouts) { %>
616<% if (splitChunks.layouts) { %>async <% } %>function setLayoutForNextPage (to) {
617 // Set layout
618 let hasError = Boolean(this.$options.nuxt.err)
619 if (this._hadError && this._dateLastError === this.$options.nuxt.dateErr) {
620 hasError = false
621 }
622 let layout = hasError
623 ? (NuxtError.options || NuxtError).layout
624 : to.matched[0].components.default.options.layout
625
626 if (typeof layout === 'function') {
627 layout = layout(app.context)
628 }
629 <% if (splitChunks.layouts) { %>
630 await this.loadLayout(layout)
631 <% } %>
632 this.setLayout(layout)
633}
634<% } %>
635
636function checkForErrors (app) {
637 // Hide error component if no error
638 if (app._hadError && app._dateLastError === app.$options.nuxt.dateErr) {
639 app.error()
640 }
641}
642
643// When navigating on a different route but the same component is used, Vue.js
644// Will not update the instance data, so we have to update $data ourselves
645function fixPrepatch (to, ___) {
646 if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) {
647 return
648 }
649
650 const instances = getMatchedComponentsInstances(to)
651 const Components = getMatchedComponents(to)
652
653 Vue.nextTick(() => {
654 instances.forEach((instance, i) => {
655 if (!instance || instance._isDestroyed) {
656 return
657 }
658
659 if (
660 instance.constructor._dataRefresh &&
661 Components[i] === instance.constructor &&
662 instance.$vnode.data.keepAlive !== true &&
663 typeof instance.constructor.options.data === 'function'
664 ) {
665 const newData = instance.constructor.options.data.call(instance)
666 for (const key in newData) {
667 Vue.set(instance.$data, key, newData[key])
668 }
669
670 // Ensure to trigger scroll event after calling scrollBehavior
671 window.<%= globals.nuxt %>.$nextTick(() => {
672 window.<%= globals.nuxt %>.$emit('triggerScroll')
673 })
674 }
675 })
676 checkForErrors(this)
677 <% if (isDev) { %>
678 // Hot reloading
679 setTimeout(() => hotReloadAPI(this), 100)
680 <% } %>
681 })
682}
683
684function nuxtReady (_app) {
685 window.<%= globals.readyCallback %>Cbs.forEach((cb) => {
686 if (typeof cb === 'function') {
687 cb(_app)
688 }
689 })
690 // Special JSDOM
691 if (typeof window.<%= globals.loadedCallback %> === 'function') {
692 window.<%= globals.loadedCallback %>(_app)
693 }
694 // Add router hooks
695 router.afterEach((to, from) => {
696 // Wait for fixPrepatch + $data updates
697 Vue.nextTick(() => _app.<%= globals.nuxt %>.$emit('routeChanged', to, from))
698 })
699}
700
701<% if (isDev) { %>
702const noopData = () => { return {} }
703const noopFetch = () => {}
704
705// Special hot reload with asyncData(context)
706function getNuxtChildComponents ($parent, $components = []) {
707 $parent.$children.forEach(($child) => {
708 if ($child.$vnode && $child.$vnode.data.nuxtChild && !$components.find(c =>(c.$options.__file === $child.$options.__file))) {
709 $components.push($child)
710 }
711 if ($child.$children && $child.$children.length) {
712 getNuxtChildComponents($child, $components)
713 }
714 })
715
716 return $components
717}
718
719function hotReloadAPI(_app) {
720 if (!module.hot) return
721
722 let $components = getNuxtChildComponents(_app.<%= globals.nuxt %>, [])
723
724 $components.forEach(addHotReload.bind(_app))
725}
726
727function addHotReload ($component, depth) {
728 if ($component.$vnode.data._hasHotReload) return
729 $component.$vnode.data._hasHotReload = true
730
731 var _forceUpdate = $component.$forceUpdate.bind($component.$parent)
732
733 $component.$vnode.context.$forceUpdate = async () => {
734 let Components = getMatchedComponents(router.currentRoute)
735 let Component = Components[depth]
736 if (!Component) {
737 return _forceUpdate()
738 }
739 if (typeof Component === 'object' && !Component.options) {
740 // Updated via vue-router resolveAsyncComponents()
741 Component = Vue.extend(Component)
742 Component._Ctor = Component
743 }
744 this.error()
745 let promises = []
746 const next = function (path) {
747 <%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
748 router.push(path)
749 }
750 await setContext(app, {
751 route: router.currentRoute,
752 isHMR: true,
753 next: next.bind(this)
754 })
755 const context = app.context
756
757 <% if (loading) { %>
758 if (this.$loading.start && !this.$loading.manual) {
759 this.$loading.start()
760 }
761 <% } %>
762
763 callMiddleware.call(this, Components, context)
764 .then(() => {
765 <% if (features.layouts) { %>
766 // If layout changed
767 if (depth !== 0) {
768 return
769 }
770
771 let layout = Component.options.layout || 'default'
772 if (typeof layout === 'function') {
773 layout = layout(context)
774 }
775 if (this.layoutName === layout) {
776 return
777 }
778 let promise = this.loadLayout(layout)
779 promise.then(() => {
780 this.setLayout(layout)
781 Vue.nextTick(() => hotReloadAPI(this))
782 })
783 return promise
784 <% } else { %>
785 return
786 <% } %>
787 })
788 <% if (features.layouts) { %>
789 .then(() => {
790 return callMiddleware.call(this, Components, context, this.layout)
791 })
792 <% } %>
793 .then(() => {
794 <% if (features.asyncData) { %>
795 // Call asyncData(context)
796 let pAsyncData = promisify(Component.options.asyncData || noopData, context)
797 pAsyncData.then((asyncDataResult) => {
798 applyAsyncData(Component, asyncDataResult)
799 <%= (loading ? 'this.$loading.increase && this.$loading.increase(30)' : '') %>
800 })
801 promises.push(pAsyncData)
802 <% } %>
803
804 <% if (features.fetch) { %>
805 // Call fetch()
806 Component.options.fetch = Component.options.fetch || noopFetch
807 let pFetch = Component.options.fetch.length && Component.options.fetch(context)
808 if (!pFetch || (!(pFetch instanceof Promise) && (typeof pFetch.then !== 'function'))) { pFetch = Promise.resolve(pFetch) }
809 <%= (loading ? 'pFetch.then(() => this.$loading.increase && this.$loading.increase(30))' : '') %>
810 promises.push(pFetch)
811 <% } %>
812 return Promise.all(promises)
813 })
814 .then(() => {
815 <%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
816 _forceUpdate()
817 setTimeout(() => hotReloadAPI(this), 100)
818 })
819 }
820}
821<% } %>
822
823async function mountApp (__app) {
824 // Set global variables
825 app = __app.app
826 router = __app.router
827 <% if (store) { %>store = __app.store<% } %>
828
829 // Create Vue instance
830 const _app = new Vue(app)
831
832 <% if (isFullStatic) { %>
833 // Load page chunk
834 if (!NUXT.data && NUXT.serverRendered) {
835 try {
836 const payload = await _app.fetchPayload(NUXT.routePath || _app.context.route.path)
837 Object.assign(NUXT, payload)
838 } catch (err) {}
839 }
840 <% } %>
841
842 <% if (features.layouts && mode !== 'spa') { %>
843 // Load layout
844 const layout = NUXT.layout || 'default'
845 await _app.loadLayout(layout)
846 _app.setLayout(layout)
847 <% } %>
848
849 // Mounts Vue app to DOM element
850 const mount = () => {
851 _app.$mount('#<%= globals.id %>')
852
853 // Add afterEach router hooks
854 router.afterEach(normalizeComponents)
855 <% if (features.layouts) { %>
856 router.afterEach(setLayoutForNextPage.bind(_app))
857 <% } %>
858 router.afterEach(fixPrepatch.bind(_app))
859
860 // Listen for first Vue update
861 Vue.nextTick(() => {
862 // Call window.{{globals.readyCallback}} callbacks
863 nuxtReady(_app)
864 <% if (isDev) { %>
865 // Enable hot reloading
866 hotReloadAPI(_app)
867 <% } %>
868 })
869 }
870 <% if (features.transitions) { %>
871 // Resolve route components
872 const Components = await Promise.all(resolveComponents(router))
873
874 // Enable transitions
875 _app.setTransitions = _app.$options.nuxt.setTransitions.bind(_app)
876 if (Components.length) {
877 _app.setTransitions(mapTransitions(Components, router.currentRoute))
878 _lastPaths = router.currentRoute.matched.map(route => compile(route.path)(router.currentRoute.params))
879 }
880 <% } else if (features.asyncData || features.fetch) { %>
881 await Promise.all(resolveComponents(router))
882 <% } %>
883 // Initialize error handler
884 _app.$loading = {} // To avoid error while _app.$nuxt does not exist
885 if (NUXT.error) {
886 _app.error(NUXT.error)
887 }
888
889 // Add beforeEach router hooks
890 router.beforeEach(loadAsyncComponents.bind(_app))
891 router.beforeEach(render.bind(_app))
892
893 // Fix in static: remove trailing slash to force hydration
894 // Full static, if server-rendered: hydrate, to allow custom redirect to generated page
895 <% if (isFullStatic) { %>
896 if (NUXT.serverRendered) {
897 return mount()
898 }
899 <% } else { %>
900 // Fix in static: remove trailing slash to force hydration
901 if (NUXT.serverRendered && isSamePath(NUXT.routePath, _app.context.route.path)) {
902 return mount()
903 }
904 <% } %>
905
906 // First render on client-side
907 const clientFirstMount = () => {
908 normalizeComponents(router.currentRoute, router.currentRoute)
909 setLayoutForNextPage.call(_app, router.currentRoute)
910 checkForErrors(_app)
911 // Don't call fixPrepatch.call(_app, router.currentRoute, router.currentRoute) since it's first render
912 mount()
913 }
914
915 // fix: force next tick to avoid having same timestamp when an error happen on spa fallback
916 await new Promise(resolve => setTimeout(resolve, 0))
917 render.call(_app, router.currentRoute, router.currentRoute, (path) => {
918 // If not redirected
919 if (!path) {
920 clientFirstMount()
921 return
922 }
923
924 // Add a one-time afterEach hook to
925 // mount the app wait for redirect and route gets resolved
926 const unregisterHook = router.afterEach((to, from) => {
927 unregisterHook()
928 clientFirstMount()
929 })
930
931 // Push the path and let route to be resolved
932 router.push(path, undefined, (err) => {
933 if (err) {
934 errorHandler(err)
935 }
936 })
937 })
938}