diff --git a/demo/server_side_rendering/.gitignore b/demo/server_side_rendering/.gitignore
new file mode 100644
index 0000000..5c0d346
--- /dev/null
+++ b/demo/server_side_rendering/.gitignore
@@ -0,0 +1 @@
+.nuxt
diff --git a/demo/server_side_rendering/.nuxt/App.vue b/demo/server_side_rendering/.nuxt/App.vue
deleted file mode 100644
index a5ffb8b..0000000
--- a/demo/server_side_rendering/.nuxt/App.vue
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/demo/server_side_rendering/.nuxt/client.js b/demo/server_side_rendering/.nuxt/client.js
deleted file mode 100644
index 968d1c1..0000000
--- a/demo/server_side_rendering/.nuxt/client.js
+++ /dev/null
@@ -1,417 +0,0 @@
-'use strict'
-
-import Vue from 'vue'
-import middleware from './middleware'
-import { createApp, NuxtError } from './index'
-import { applyAsyncData, sanitizeComponent, getMatchedComponents, getMatchedComponentsInstances, flatMapComponents, getContext, middlewareSeries, promisify, getLocation, compile } from './utils'
-const noopData = () => { return {} }
-const noopFetch = () => {}
-let _lastPaths = []
-let _lastComponentsFiles = []
-
-let app
-let router
-
-
-function mapTransitions(Components, to, from) {
- return Components.map((Component) => {
- let transition = Component.options.transition
- if (typeof transition === 'function') {
- return transition(to, from)
- }
- return transition
- })
-}
-
-function loadAsyncComponents (to, from, next) {
- const resolveComponents = flatMapComponents(to, (Component, _, match, key) => {
- if (typeof Component === 'function' && !Component.options) {
- return new Promise(function (resolve, reject) {
- const _resolve = (Component) => {
- Component = sanitizeComponent(Component)
- match.components[key] = Component
- resolve(Component)
- }
- Component().then(_resolve).catch(reject)
- })
- }
- Component = sanitizeComponent(Component)
- match.components[key] = Component
- return match.components[key]
- })
- const fromPath = from.fullPath.split('#')[0]
- const toPath = to.fullPath.split('#')[0]
- this._hashChanged = (fromPath === toPath)
- if (!this._hashChanged) {
- this.$loading.start && this.$loading.start()
- }
- Promise.all(resolveComponents)
- .then(() => next())
- .catch((err) => {
- let statusCode = err.statusCode || err.status || (err.response && err.response.status) || 500
- this.error({ statusCode, message: err.message })
- next(false)
- })
-}
-
-function callMiddleware (Components, context, layout) {
- // if layout is undefined, only call global middleware
- let midd = []
- let unknownMiddleware = false
- if (typeof layout !== 'undefined') {
- midd = [] // exclude global middleware if layout defined (already called before)
- if (layout.middleware) {
- midd = midd.concat(layout.middleware)
- }
- Components.forEach((Component) => {
- if (Component.options.middleware) {
- midd = midd.concat(Component.options.middleware)
- }
- })
- }
- midd = midd.map((name) => {
- if (typeof middleware[name] !== 'function') {
- unknownMiddleware = true
- this.error({ statusCode: 500, message: 'Unknown middleware ' + name })
- }
- return middleware[name]
- })
- if (unknownMiddleware) return
- return middlewareSeries(midd, context)
-}
-
-async function render (to, from, next) {
- if (this._hashChanged) return next()
- let layout
- let nextCalled = false
- const _next = function (path) {
- this.$loading.finish && this.$loading.finish()
- if (nextCalled) return
- nextCalled = true
- next(path)
- }
- let context = getContext({ to, isClient: true, next: _next.bind(this), error: this.error.bind(this) }, app)
- let Components = getMatchedComponents(to)
- this._context = context
- this._dateLastError = this.$options._nuxt.dateErr
- this._hadError = !!this.$options._nuxt.err
- if (!Components.length) {
- // Default layout
- await callMiddleware.call(this, Components, context)
- if (context._redirected) return
- layout = await this.loadLayout(typeof NuxtError.layout === 'function' ? NuxtError.layout(context) : NuxtError.layout)
- await callMiddleware.call(this, Components, context, layout)
- if (context._redirected) return
- this.error({ statusCode: 404, message: 'This page could not be found.' })
- return next()
- }
- // Update ._data and other properties if hot reloaded
- Components.forEach(function (Component) {
- if (Component._Ctor && Component._Ctor.options) {
- Component.options.asyncData = Component._Ctor.options.asyncData
- Component.options.fetch = Component._Ctor.options.fetch
- }
- })
- this.setTransitions(mapTransitions(Components, to, from))
- try {
- // Set layout
- await callMiddleware.call(this, Components, context)
- if (context._redirected) return
- layout = Components[0].options.layout
- if (typeof layout === 'function') {
- layout = layout(context)
- }
- layout = await this.loadLayout(layout)
- await callMiddleware.call(this, Components, context, layout)
- if (context._redirected) return
- // Pass validation?
- let isValid = true
- Components.forEach((Component) => {
- if (!isValid) return
- if (typeof Component.options.validate !== 'function') return
- isValid = Component.options.validate({
- params: to.params || {},
- query : to.query || {}
- })
- })
- if (!isValid) {
- this.error({ statusCode: 404, message: 'This page could not be found.' })
- return next()
- }
- await Promise.all(Components.map((Component, i) => {
- // Check if only children route changed
- Component._path = compile(to.matched[i].path)(to.params)
- if (!this._hadError && Component._path === _lastPaths[i] && (i + 1) !== Components.length) {
- return Promise.resolve()
- }
- let promises = []
- // asyncData method
- if (Component.options.asyncData && typeof Component.options.asyncData === 'function') {
- var promise = promisify(Component.options.asyncData, context)
- promise.then((asyncDataResult) => {
- applyAsyncData(Component, asyncDataResult)
- this.$loading.increase && this.$loading.increase(30)
- })
- promises.push(promise)
- }
- if (Component.options.fetch) {
- var p = Component.options.fetch(context)
- if (!p || (!(p instanceof Promise) && (typeof p.then !== 'function'))) { p = Promise.resolve(p) }
- p.then(() => this.$loading.increase && this.$loading.increase(30))
- promises.push(p)
- }
- return Promise.all(promises)
- }))
- _lastPaths = Components.map((Component, i) => compile(to.matched[i].path)(to.params))
- this.$loading.finish && this.$loading.finish()
- // If not redirected
- if (!nextCalled) {
- next()
- }
- } catch (error) {
- _lastPaths = []
- error.statusCode = error.statusCode || error.status || (error.response && error.response.status) || 500
- let layout = NuxtError.layout
- if (typeof layout === 'function') {
- layout = layout(context)
- }
- this.loadLayout(layout)
- .then(() => {
- this.error(error)
- next(false)
- })
- }
-}
-
-// Fix components format in matched, it's due to code-splitting of vue-router
-function normalizeComponents (to, ___) {
- flatMapComponents(to, (Component, _, match, key) => {
- if (typeof Component === 'object' && !Component.options) {
- // Updated via vue-router resolveAsyncComponents()
- Component = Vue.extend(Component)
- Component._Ctor = Component
- match.components[key] = Component
- }
- return Component
- })
-}
-
-// When navigating on a different route but the same component is used, Vue.js
-// will not update the instance data, so we have to update $data ourselves
-function fixPrepatch (to, ___) {
- if (this._hashChanged) return
- Vue.nextTick(() => {
- let instances = getMatchedComponentsInstances(to)
- _lastComponentsFiles = instances.map((instance, i) => {
- if (!instance) return '';
- if (_lastPaths[i] === instance.constructor._path && typeof instance.constructor.options.data === 'function') {
- let newData = instance.constructor.options.data.call(instance)
- for (let key in newData) {
- Vue.set(instance.$data, key, newData[key])
- }
- }
- return instance.constructor.options.__file
- })
- // hide error component if no error
- if (this._hadError && this._dateLastError === this.$options._nuxt.dateErr) {
- this.error()
- }
- // Set layout
- let layout = this.$options._nuxt.err ? NuxtError.layout : to.matched[0].components.default.options.layout
- if (typeof layout === 'function') {
- layout = layout(this._context)
- }
- this.setLayout(layout)
- // hot reloading
- setTimeout(() => hotReloadAPI(this), 100)
- })
-}
-
-// Special hot reload with asyncData(context)
-function hotReloadAPI (_app) {
- if (!module.hot) return
- let $components = []
- let $nuxt = _app.$nuxt
- while ($nuxt && $nuxt.$children && $nuxt.$children.length) {
- $nuxt.$children.forEach(function (child, i) {
- if (child.$vnode.data.nuxtChild) {
- let hasAlready = false
- $components.forEach(function (component) {
- if (component.$options.__file === child.$options.__file) {
- hasAlready = true
- }
- })
- if (!hasAlready) {
- $components.push(child)
- }
- }
- $nuxt = child
- })
- }
- $components.forEach(addHotReload.bind(_app))
-}
-
-function addHotReload ($component, depth) {
- if ($component.$vnode.data._hasHotReload) return
- $component.$vnode.data._hasHotReload = true
- var _forceUpdate = $component.$forceUpdate.bind($component.$parent)
- $component.$vnode.context.$forceUpdate = () => {
- let Components = getMatchedComponents(router.currentRoute)
- let Component = Components[depth]
- if (!Component) return _forceUpdate()
- if (typeof Component === 'object' && !Component.options) {
- // Updated via vue-router resolveAsyncComponents()
- Component = Vue.extend(Component)
- Component._Ctor = Component
- }
- this.error()
- let promises = []
- const next = function (path) {
- this.$loading.finish && this.$loading.finish()
- router.push(path)
- }
- let context = getContext({ route: router.currentRoute, isClient: true, hotReload: true, next: next.bind(this), error: this.error }, app)
- this.$loading.start && this.$loading.start()
- callMiddleware.call(this, Components, context)
- .then(() => {
- // If layout changed
- if (depth !== 0) return Promise.resolve()
- let layout = Component.options.layout || 'default'
- if (typeof layout === 'function') {
- layout = layout(context)
- }
- if (this.layoutName === layout) return Promise.resolve()
- let promise = this.loadLayout(layout)
- promise.then(() => {
- this.setLayout(layout)
- Vue.nextTick(() => hotReloadAPI(this))
- })
- return promise
- })
- .then(() => {
- return callMiddleware.call(this, Components, context, this.layout)
- })
- .then(() => {
- // Call asyncData(context)
- let pAsyncData = promisify(Component.options.asyncData || noopData, context)
- pAsyncData.then((asyncDataResult) => {
- applyAsyncData(Component, asyncDataResult)
- this.$loading.increase && this.$loading.increase(30)
- })
- promises.push(pAsyncData)
- // Call fetch()
- Component.options.fetch = Component.options.fetch || noopFetch
- let pFetch = Component.options.fetch(context)
- if (!pFetch || (!(pFetch instanceof Promise) && (typeof pFetch.then !== 'function'))) { pFetch = Promise.resolve(pFetch) }
- pFetch.then(() => this.$loading.increase && this.$loading.increase(30))
- promises.push(pFetch)
- return Promise.all(promises)
- })
- .then(() => {
- this.$loading.finish && this.$loading.finish()
- _forceUpdate()
- setTimeout(() => hotReloadAPI(this), 100)
- })
- }
-}
-
-// Load vue app
-const NUXT = window.__NUXT__ || {}
-if (!NUXT) {
- throw new Error('[nuxt.js] cannot find the global variable __NUXT__, make sure the server is working.')
-}
-// Get matched components
-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)
- }
- Component().then(_resolve).catch(reject)
- })
- }
- Component = sanitizeComponent(Component)
- match.components[key] = Component
- return Component
- })
-}
-
-function nuxtReady (app) {
- window._nuxtReadyCbs.forEach((cb) => {
- if (typeof cb === 'function') {
- cb(app)
- }
- })
- // Special JSDOM
- if (typeof window._onNuxtLoaded === 'function') {
- window._onNuxtLoaded(app)
- }
- // Add router hooks
- router.afterEach(function (to, from) {
- app.$nuxt.$emit('routeChanged', to, from)
- })
-}
-
-createApp()
-.then(async (__app) => {
- app = __app.app
- router = __app.router
-
- const Components = await Promise.all(resolveComponents(router))
- const _app = new Vue(app)
- const layout = NUXT.layout || 'default'
- await _app.loadLayout(layout)
- _app.setLayout(layout)
- const mountApp = () => {
- _app.$mount('#__nuxt')
- Vue.nextTick(() => {
- // Hot reloading
- hotReloadAPI(_app)
- // Call window.onNuxtReady callbacks
- nuxtReady(_app)
- })
- }
- _app.setTransitions = _app.$options._nuxt.setTransitions.bind(_app)
- if (Components.length) {
- _app.setTransitions(mapTransitions(Components, router.currentRoute))
- _lastPaths = router.currentRoute.matched.map((route) => compile(route.path)(router.currentRoute.params))
- _lastComponentsFiles = Components.map((Component) => Component.options.__file)
- }
- _app.error = _app.$options._nuxt.error.bind(_app)
- _app.$loading = {} // to avoid error while _app.$nuxt does not exist
- if (NUXT.error) _app.error(NUXT.error)
- // Add router hooks
- router.beforeEach(loadAsyncComponents.bind(_app))
- router.beforeEach(render.bind(_app))
- router.afterEach(normalizeComponents)
- router.afterEach(fixPrepatch.bind(_app))
- if (NUXT.serverRendered) {
- mountApp()
- return
- }
- render.call(_app, router.currentRoute, router.currentRoute, function (path) {
- if (path) {
- let mounted = false
- router.afterEach(function () {
- if (mounted) return
- mounted = true
- mountApp()
- })
- router.push(path)
- return
- }
- normalizeComponents(router.currentRoute, router.currentRoute)
- fixPrepatch.call(_app, router.currentRoute, router.currentRoute)
- mountApp()
- })
-})
-.catch((err) => {
- console.error('[nuxt.js] Cannot load components', err) // eslint-disable-line no-console
-})
diff --git a/demo/server_side_rendering/.nuxt/components/nuxt-child.js b/demo/server_side_rendering/.nuxt/components/nuxt-child.js
deleted file mode 100644
index becc3b8..0000000
--- a/demo/server_side_rendering/.nuxt/components/nuxt-child.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import Vue from 'vue'
-
-const transitionsKeys = [
- 'name',
- 'mode',
- 'css',
- 'type',
- 'duration',
- 'enterClass',
- 'leaveClass',
- 'enterActiveClass',
- 'enterActiveClass',
- 'leaveActiveClass',
- 'enterToClass',
- 'leaveToClass'
-]
-const listenersKeys = [
- 'beforeEnter',
- 'enter',
- 'afterEnter',
- 'enterCancelled',
- 'beforeLeave',
- 'leave',
- 'afterLeave',
- 'leaveCancelled'
-]
-
-export default {
- name: 'nuxt-child',
- functional: true,
- render (h, { parent, data }) {
- data.nuxtChild = true
-
- const transitions = parent.$nuxt.nuxt.transitions
- const defaultTransition = parent.$nuxt.nuxt.defaultTransition
- let depth = 0
- while (parent) {
- if (parent.$vnode && parent.$vnode.data.nuxtChild) {
- depth++
- }
- parent = parent.$parent
- }
- data.nuxtChildDepth = depth
- const transition = transitions[depth] || defaultTransition
- let transitionProps = {}
- transitionsKeys.forEach((key) => {
- if (typeof transition[key] !== 'undefined') {
- transitionProps[key] = transition[key]
- }
- })
- let listeners = {}
- listenersKeys.forEach((key) => {
- if (typeof transition[key] === 'function') {
- listeners[key] = transition[key]
- }
- })
- return h('transition', {
- props: transitionProps,
- on: listeners
- }, [
- h('router-view', data)
- ])
- }
-}
diff --git a/demo/server_side_rendering/.nuxt/components/nuxt-error.vue b/demo/server_side_rendering/.nuxt/components/nuxt-error.vue
deleted file mode 100644
index 476d67d..0000000
--- a/demo/server_side_rendering/.nuxt/components/nuxt-error.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
{{ error.statusCode }}
-
-
{{ error.message }}
-
-
Back to the home page
-
-
-
-
-
-
-
diff --git a/demo/server_side_rendering/.nuxt/components/nuxt-link.js b/demo/server_side_rendering/.nuxt/components/nuxt-link.js
deleted file mode 100644
index c23fdd7..0000000
--- a/demo/server_side_rendering/.nuxt/components/nuxt-link.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import Vue from 'vue'
-
-export default {
- name: 'nuxt-link',
- functional: true,
- render (h, { data, children }) {
- return h('router-link', data, children)
- }
-}
diff --git a/demo/server_side_rendering/.nuxt/components/nuxt-loading.vue b/demo/server_side_rendering/.nuxt/components/nuxt-loading.vue
deleted file mode 100644
index 781da5a..0000000
--- a/demo/server_side_rendering/.nuxt/components/nuxt-loading.vue
+++ /dev/null
@@ -1,103 +0,0 @@
-
-
-
-
-
-
-
diff --git a/demo/server_side_rendering/.nuxt/components/nuxt.vue b/demo/server_side_rendering/.nuxt/components/nuxt.vue
deleted file mode 100644
index e7b57af..0000000
--- a/demo/server_side_rendering/.nuxt/components/nuxt.vue
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
diff --git a/demo/server_side_rendering/.nuxt/index.js b/demo/server_side_rendering/.nuxt/index.js
deleted file mode 100644
index fffe080..0000000
--- a/demo/server_side_rendering/.nuxt/index.js
+++ /dev/null
@@ -1,123 +0,0 @@
-'use strict'
-
-import Vue from 'vue'
-import Meta from 'vue-meta'
-import { createRouter } from './router.js'
-
-import NuxtChild from './components/nuxt-child.js'
-import NuxtLink from './components/nuxt-link.js'
-import NuxtError from './components/nuxt-error.vue'
-import Nuxt from './components/nuxt.vue'
-import App from './App.vue'
-
-import { getContext } from './utils'
-
-if (process.browser) {
- // window.onNuxtReady(() => console.log('Ready')) hook
- // Useful for jsdom testing or plugins (https://github.com/tmpvar/jsdom#dealing-with-asynchronous-script-loading)
- window._nuxtReadyCbs = []
- window.onNuxtReady = function (cb) {
- window._nuxtReadyCbs.push(cb)
- }
-}
-
-// Import SSR plugins
-let plugin0 = require('~plugins/vue-js-modal')
-plugin0 = plugin0.default || plugin0
-
-
-// Component:
-Vue.component(NuxtChild.name, NuxtChild)
-// Component:
-Vue.component(NuxtLink.name, NuxtLink)
-// Component:
-Vue.component(Nuxt.name, Nuxt)
-
-// vue-meta configuration
-Vue.use(Meta, {
- keyName: 'head', // the component option name that vue-meta looks for meta info on.
- attribute: 'data-n-head', // the attribute name vue-meta adds to the tags it observes
- ssrAttribute: 'data-n-head-ssr', // the attribute name that lets vue-meta know that meta info has already been server-rendered
- tagIDKeyName: 'hid' // the property name that vue-meta uses to determine whether to overwrite or append a tag
-})
-
-const defaultTransition = {"name":"page","mode":"out-in"}
-
-async function createApp (ssrContext) {
-
- const router = createRouter()
-
- if (process.server && ssrContext && ssrContext.url) {
- await new Promise((resolve, reject) => {
- router.push(ssrContext.url, resolve, reject)
- })
- }
-
- if (process.browser) {
-
- }
-
- // root instance
- // here we inject the router and store to all child components,
- // making them available everywhere as `this.$router` and `this.$store`.
- let app = {
- router,
-
- _nuxt: {
- defaultTransition: defaultTransition,
- transitions: [ defaultTransition ],
- setTransitions (transitions) {
- if (!Array.isArray(transitions)) {
- transitions = [ transitions ]
- }
- transitions = transitions.map((transition) => {
- if (!transition) {
- transition = defaultTransition
- } else if (typeof transition === 'string') {
- transition = Object.assign({}, defaultTransition, { name: transition })
- } else {
- transition = Object.assign({}, defaultTransition, transition)
- }
- return transition
- })
- this.$options._nuxt.transitions = transitions
- return transitions
- },
- err: null,
- dateErr: null,
- error (err) {
- err = err || null
- if (typeof err === 'string') {
- err = { statusCode: 500, message: err }
- }
- this.$options._nuxt.dateErr = Date.now()
- this.$options._nuxt.err = err;
- return err
- }
- },
- ...App
- }
-
- const next = ssrContext ? ssrContext.next : (location) => app.router.push(location)
- const ctx = getContext({
- isServer: !!ssrContext,
- isClient: !ssrContext,
- route: router.currentRoute,
- next,
-
- req: ssrContext ? ssrContext.req : undefined,
- res: ssrContext ? ssrContext.res : undefined,
- }, app)
- delete ctx.error
-
- // Inject external plugins
-
- if (typeof plugin0 === 'function') {
- await plugin0(ctx)
- }
-
-
- return { app, router }
-}
-
-export { createApp, NuxtError }
diff --git a/demo/server_side_rendering/.nuxt/layouts/default.vue b/demo/server_side_rendering/.nuxt/layouts/default.vue
deleted file mode 100644
index 2cc8469..0000000
--- a/demo/server_side_rendering/.nuxt/layouts/default.vue
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/demo/server_side_rendering/.nuxt/middleware.js b/demo/server_side_rendering/.nuxt/middleware.js
deleted file mode 100644
index b1c6ea4..0000000
--- a/demo/server_side_rendering/.nuxt/middleware.js
+++ /dev/null
@@ -1 +0,0 @@
-export default {}
diff --git a/demo/server_side_rendering/.nuxt/router.js b/demo/server_side_rendering/.nuxt/router.js
deleted file mode 100644
index d5607ee..0000000
--- a/demo/server_side_rendering/.nuxt/router.js
+++ /dev/null
@@ -1,52 +0,0 @@
-'use strict'
-
-import Vue from 'vue'
-import Router from 'vue-router'
-
-Vue.use(Router)
-
-
-const _ddfbdcce = () => import('/Users/yev/Projects/vue/vue-js-modal/demo/server/pages/index.vue' /* webpackChunkName: "pages/index" */)
-
-
-
-const scrollBehavior = (to, from, savedPosition) => {
- // savedPosition is only available for popstate navigations.
- if (savedPosition) {
- return savedPosition
- } else {
- let position = {}
- // if no children detected
- if (to.matched.length < 2) {
- // scroll to the top of the page
- position = { x: 0, y: 0 }
- }
- else if (to.matched.some((r) => r.components.default.options.scrollToTop)) {
- // if one of the children has scrollToTop option set to true
- position = { x: 0, y: 0 }
- }
- // if link has anchor, scroll to anchor by returning the selector
- if (to.hash) {
- position = { selector: to.hash }
- }
- return position
- }
-}
-
-
-export function createRouter () {
- return new Router({
- mode: 'history',
- base: '/',
- linkActiveClass: 'nuxt-link-active',
- linkExactActiveClass: 'nuxt-link-exact-active',
- scrollBehavior,
- routes: [
- {
- path: "/",
- component: _ddfbdcce,
- name: "index"
- }
- ]
- })
-}
diff --git a/demo/server_side_rendering/.nuxt/server.js b/demo/server_side_rendering/.nuxt/server.js
deleted file mode 100644
index a7c0fae..0000000
--- a/demo/server_side_rendering/.nuxt/server.js
+++ /dev/null
@@ -1,178 +0,0 @@
-'use strict'
-
-import Vue from 'vue'
-import { stringify } from 'querystring'
-import { omit } from 'lodash'
-import middleware from './middleware'
-import { createApp, NuxtError } from './index'
-import { applyAsyncData, sanitizeComponent, getMatchedComponents, getContext, middlewareSeries, promisify, urlJoin } from './utils'
-const debug = require('debug')('nuxt:render')
-debug.color = 4 // force blue color
-
-const isDev = true
-
-// This exported function will be called by `bundleRenderer`.
-// This is where we perform data-prefetching to determine the
-// state of our application before actually rendering it.
-// Since data fetching is async, this function is expected to
-// return a Promise that resolves to the app instance.
-export default async (context) => {
- // create context.next for simulate next() of beforeEach() when wanted to redirect
- context.redirected = false
- context.next = function (opts) {
- context.redirected = opts
- // if nuxt generate
- if (!context.res) {
- context.nuxt.serverRendered = false
- return
- }
- opts.query = stringify(opts.query)
- opts.path = opts.path + (opts.query ? '?' + opts.query : '')
- if (opts.path.indexOf('http') !== 0 && ('/' !== '/' && opts.path.indexOf('/') !== 0)) {
- opts.path = urlJoin('/', opts.path)
- }
- context.res.writeHead(opts.status, {
- 'Location': opts.path
- })
- context.res.end()
- }
- const { app, router } = await createApp(context)
- const _app = new Vue(app)
- const _noopApp = new Vue({ render: (h) => h('div') })
- // Add store to the context
-
- // Add route to the context
- context.route = router.currentRoute
- // Nuxt object
- context.nuxt = { layout: 'default', data: [], error: null, serverRendered: true }
- // Add meta infos
- context.meta = _app.$meta()
- // Error function
- context.error = _app.$options._nuxt.error.bind(_app)
-
- const s = isDev && Date.now()
- let ctx = getContext(context, app)
- let Components = []
- let promises = getMatchedComponents(router.match(context.url)).map((Component) => {
- return new Promise((resolve, reject) => {
- if (typeof Component !== 'function' || Component.super === Vue) return resolve(sanitizeComponent(Component))
- const _resolve = (Component) => resolve(sanitizeComponent(Component))
- Component().then(_resolve).catch(reject)
- })
- })
- try {
- Components = await Promise.all(promises)
- } catch (err) {
- // Throw back error to renderRoute()
- throw err
- }
- // nuxtServerInit
-
- let promise = Promise.resolve()
-
- await promise
- // Call global middleware (nuxt.config.js)
- let midd = []
- midd = midd.map((name) => {
- if (typeof middleware[name] !== 'function') {
- context.nuxt.error = context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
- }
- return middleware[name]
- })
- if (!context.nuxt.error) {
- await middlewareSeries(midd, ctx)
- }
- if (context.redirected) return _noopApp
- // Set layout
- let layout = Components.length ? Components[0].options.layout : NuxtError.layout
- if (typeof layout === 'function') layout = layout(ctx)
- await _app.loadLayout(layout)
- layout = _app.setLayout(layout)
- // Set layout to __NUXT__
- context.nuxt.layout = _app.layoutName
- // Call middleware (layout + pages)
- midd = []
- if (layout.middleware) midd = midd.concat(layout.middleware)
- Components.forEach((Component) => {
- if (Component.options.middleware) {
- midd = midd.concat(Component.options.middleware)
- }
- })
- midd = midd.map((name) => {
- if (typeof middleware[name] !== 'function') {
- context.nuxt.error = context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
- }
- return middleware[name]
- })
- if (!context.nuxt.error) {
- await middlewareSeries(midd, ctx)
- }
- if (context.redirected) return _noopApp
- // Call .validate()
- let isValid = true
- Components.forEach((Component) => {
- if (!isValid) return
- if (typeof Component.options.validate !== 'function') return
- isValid = Component.options.validate({
- params: context.route.params || {},
- query: context.route.query || {}
- })
- })
- // If .validate() returned false
- if (!isValid) {
- // Don't server-render the page in generate mode
- if (context._generate) {
- context.nuxt.serverRendered = false
- }
- // Call the 404 error by making the Components array empty
- Components = []
- }
- // Call asyncData & fetch hooks on components matched by the route.
- let asyncDatas = await Promise.all(Components.map((Component) => {
- let promises = []
- if (Component.options.asyncData && typeof Component.options.asyncData === 'function') {
- let promise = promisify(Component.options.asyncData, ctx)
- // Call asyncData(context)
- promise.then((asyncDataResult) => {
- applyAsyncData(Component, asyncDataResult)
- return asyncDataResult
- })
- promises.push(promise)
- } else promises.push(null)
- // call fetch(context)
- if (Component.options.fetch) promises.push(Component.options.fetch(ctx))
- else promises.push(null)
- return Promise.all(promises)
- }))
- // If no Components found, returns 404
- if (!Components.length) {
- context.nuxt.error = context.error({ statusCode: 404, message: 'This page could not be found.' })
- }
-
- if (asyncDatas.length) debug('Data fetching ' + context.url + ': ' + (Date.now() - s) + 'ms')
-
- // datas are the first row of each
- context.nuxt.data = asyncDatas.map((r) => (r[0] || {}))
- // If an error occured in the execution
- if (_app.$options._nuxt.err) {
- context.nuxt.error = _app.$options._nuxt.err
- }
-
-
- // 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
- // if (typeof error === 'string') {
- // error = { statusCode: 500, message: error }
- // }
- // context.nuxt.error = context.error(error)
- //
- // return _app
-}
diff --git a/demo/server_side_rendering/.nuxt/utils.js b/demo/server_side_rendering/.nuxt/utils.js
deleted file mode 100644
index 9daf7a2..0000000
--- a/demo/server_side_rendering/.nuxt/utils.js
+++ /dev/null
@@ -1,368 +0,0 @@
-'use strict'
-import Vue from 'vue'
-
-const noopData = () => ({})
-
-export function applyAsyncData (Component, asyncData = {}) {
- const ComponentData = Component.options.data || noopData
- Component.options.data = function () {
- const data = ComponentData.call(this)
- return { ...data, ...asyncData }
- }
- if (Component._Ctor && Component._Ctor.options) {
- Component._Ctor.options.data = Component.options.data
- }
-}
-
-export function sanitizeComponent (Component) {
- if (!Component.options) {
- Component = Vue.extend(Component) // fix issue #6
- Component._Ctor = Component
- } else {
- Component._Ctor = Component
- Component.extendOptions = Component.options
- }
- // For debugging purpose
- if (!Component.options.name && Component.options.__file) {
- Component.options.name = Component.options.__file
- }
- return Component
-}
-
-export function getMatchedComponents (route) {
- return [].concat.apply([], route.matched.map(function (m) {
- return Object.keys(m.components).map(function (key) {
- return m.components[key]
- })
- }))
-}
-
-export function getMatchedComponentsInstances (route) {
- return [].concat.apply([], route.matched.map(function (m) {
- return Object.keys(m.instances).map(function (key) {
- return m.instances[key]
- })
- }))
-}
-
-export function flatMapComponents (route, fn) {
- return Array.prototype.concat.apply([], route.matched.map(function (m, index) {
- return Object.keys(m.components).map(function (key) {
- return fn(m.components[key], m.instances[key], m, key, index)
- })
- }))
-}
-
-export function getContext (context, app) {
- let ctx = {
- isServer: !!context.isServer,
- isClient: !!context.isClient,
- isDev: true,
- app: app,
-
- route: (context.to ? context.to : context.route),
- payload: context.payload,
- error: context.error,
- base: '/',
- env: {},
- hotReload: context.hotReload || false
- }
- const next = context.next
- ctx.params = ctx.route.params || {}
- ctx.query = ctx.route.query || {}
- ctx.redirect = function (status, path, query) {
- if (!status) return
- ctx._redirected = true // Used in middleware
- // if only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' })
- if (typeof status === 'string' && (typeof path === 'undefined' || typeof path === 'object')) {
- query = path || {}
- path = status
- status = 302
- }
- next({
- path: path,
- query: query,
- status: status
- })
- }
- if (context.req) ctx.req = context.req
- if (context.res) ctx.res = context.res
- return ctx
-}
-
-export function middlewareSeries (promises, context) {
- if (!promises.length || context._redirected) {
- return Promise.resolve()
- }
- return promisify(promises[0], context)
- .then(() => {
- return middlewareSeries(promises.slice(1), context)
- })
-}
-
-export function promisify (fn, context) {
- let promise
- if (fn.length === 2) {
- // fn(context, callback)
- promise = new Promise((resolve) => {
- fn(context, function (err, data) {
- if (err) {
- context.error(err)
- }
- data = data || {}
- resolve(data)
- })
- })
- } else {
- promise = fn(context)
- }
- if (!promise || (!(promise instanceof Promise) && (typeof promise.then !== 'function'))) {
- promise = Promise.resolve(promise)
- }
- return promise
-}
-
-// Imported from vue-router
-export function getLocation (base) {
- var path = window.location.pathname
- if (base && path.indexOf(base) === 0) {
- path = path.slice(base.length)
- }
- return (path || '/') + window.location.search + window.location.hash
-}
-
-export function urlJoin () {
- return [].slice.call(arguments).join('/').replace(/\/+/g, '/')
-}
-
-// Imported from path-to-regexp
-
-/**
- * Compile a string to a template function for the path.
- *
- * @param {string} str
- * @param {Object=} options
- * @return {!function(Object=, Object=)}
- */
-export function compile (str, options) {
- return tokensToFunction(parse(str, options))
-}
-
-/**
- * The main path matching regexp utility.
- *
- * @type {RegExp}
- */
-const PATH_REGEXP = new RegExp([
- // Match escaped characters that would otherwise appear in future matches.
- // This allows the user to escape special characters that won't transform.
- '(\\\\.)',
- // Match Express-style parameters and un-named parameters with a prefix
- // and optional suffixes. Matches appear as:
- //
- // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
- // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
- // "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
- '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
-].join('|'), 'g')
-
-/**
- * Parse a string for the raw tokens.
- *
- * @param {string} str
- * @param {Object=} options
- * @return {!Array}
- */
-function parse (str, options) {
- var tokens = []
- var key = 0
- var index = 0
- var path = ''
- var defaultDelimiter = options && options.delimiter || '/'
- var res
-
- while ((res = PATH_REGEXP.exec(str)) != null) {
- var m = res[0]
- var escaped = res[1]
- var offset = res.index
- path += str.slice(index, offset)
- index = offset + m.length
-
- // Ignore already escaped sequences.
- if (escaped) {
- path += escaped[1]
- continue
- }
-
- var next = str[index]
- var prefix = res[2]
- var name = res[3]
- var capture = res[4]
- var group = res[5]
- var modifier = res[6]
- var asterisk = res[7]
-
- // Push the current path onto the tokens.
- if (path) {
- tokens.push(path)
- path = ''
- }
-
- var partial = prefix != null && next != null && next !== prefix
- var repeat = modifier === '+' || modifier === '*'
- var optional = modifier === '?' || modifier === '*'
- var delimiter = res[2] || defaultDelimiter
- var pattern = capture || group
-
- tokens.push({
- name: name || key++,
- prefix: prefix || '',
- delimiter: delimiter,
- optional: optional,
- repeat: repeat,
- partial: partial,
- asterisk: !!asterisk,
- pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
- })
- }
-
- // Match any characters still remaining.
- if (index < str.length) {
- path += str.substr(index)
- }
-
- // If the path exists, push it onto the end.
- if (path) {
- tokens.push(path)
- }
-
- return tokens
-}
-
-/**
- * Prettier encoding of URI path segments.
- *
- * @param {string}
- * @return {string}
- */
-function encodeURIComponentPretty (str) {
- return encodeURI(str).replace(/[\/?#]/g, function (c) {
- return '%' + c.charCodeAt(0).toString(16).toUpperCase()
- })
-}
-
-/**
- * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
- *
- * @param {string}
- * @return {string}
- */
-function encodeAsterisk (str) {
- return encodeURI(str).replace(/[?#]/g, function (c) {
- return '%' + c.charCodeAt(0).toString(16).toUpperCase()
- })
-}
-
-/**
- * Expose a method for transforming tokens into the path function.
- */
-function tokensToFunction (tokens) {
- // Compile all the tokens into regexps.
- var matches = new Array(tokens.length)
-
- // Compile all the patterns before compilation.
- for (var i = 0; i < tokens.length; i++) {
- if (typeof tokens[i] === 'object') {
- matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$')
- }
- }
-
- return function (obj, opts) {
- var path = ''
- var data = obj || {}
- var options = opts || {}
- var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent
-
- for (var i = 0; i < tokens.length; i++) {
- var token = tokens[i]
-
- if (typeof token === 'string') {
- path += token
-
- continue
- }
-
- var value = data[token.name]
- var segment
-
- if (value == null) {
- if (token.optional) {
- // Prepend partial segment prefixes.
- if (token.partial) {
- path += token.prefix
- }
-
- continue
- } else {
- throw new TypeError('Expected "' + token.name + '" to be defined')
- }
- }
-
- if (Array.isArray(value)) {
- if (!token.repeat) {
- throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
- }
-
- if (value.length === 0) {
- if (token.optional) {
- continue
- } else {
- throw new TypeError('Expected "' + token.name + '" to not be empty')
- }
- }
-
- for (var j = 0; j < value.length; j++) {
- segment = encode(value[j])
-
- if (!matches[i].test(segment)) {
- throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
- }
-
- path += (j === 0 ? token.prefix : token.delimiter) + segment
- }
-
- continue
- }
-
- segment = token.asterisk ? encodeAsterisk(value) : encode(value)
-
- if (!matches[i].test(segment)) {
- throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
- }
-
- path += token.prefix + segment
- }
-
- return path
- }
-}
-
-/**
- * Escape a regular expression string.
- *
- * @param {string} str
- * @return {string}
- */
-function escapeString (str) {
- return str.replace(/([.+*?=^!:()[\]|\/\\])/g, '\\$1')
-}
-
-/**
- * Escape the capturing group by escaping special characters and meaning.
- *
- * @param {string} group
- * @return {string}
- */
-function escapeGroup (group) {
- return group.replace(/([=!:$\/()])/g, '\\$1')
-}