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 @@ - - - - - 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') -}