diff --git a/lib/app/client.js b/lib/app/client.js index 246fe06431..4d1c3ef6bc 100644 --- a/lib/app/client.js +++ b/lib/app/client.js @@ -56,9 +56,15 @@ function render (to, from, next) { } }) this.error() + let nextCalled = false Promise.all(Components.map((Component) => { let promises = [] - const context = getContext({ to<%= (store ? ', store' : '') %>, isClient: true }) + const _next = function (path) { + <%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %> + nextCalled = true + next(path) + } + const context = getContext({ to<%= (store ? ', store' : '') %>, isClient: true, next: _next.bind(this) }) if (Component._data && typeof Component._data === 'function') { var promise = Component._data(context) if (!(promise instanceof Promise)) promise = Promise.resolve(promise) @@ -81,7 +87,10 @@ function render (to, from, next) { })) .then(() => { <%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %> - next() + // If not redirected + if (!nextCalled) { + next() + } }) .catch((error) => { this.error(error) @@ -97,7 +106,11 @@ function hotReloadAPI (_app) { if (!Component) return _forceUpdate() <%= (loading ? 'this.$loading.start && this.$loading.start()' : '') %> let promises = [] - const context = getContext({ route: router.currentRoute<%= (store ? ', store' : '') %>, isClient: true }) + const next = function (path) { + <%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %> + router.push(path) + } + const context = getContext({ route: router.currentRoute<%= (store ? ', store' : '') %>, isClient: true, next: next.bind(this) }) // Check if data has been updated const originalDataFn = (Component._data || noopData).toString().replace(/\s/g, '') const newDataFn = (Component._Ctor.options.data || noopData).toString().replace(/\s/g, '') @@ -124,7 +137,7 @@ function hotReloadAPI (_app) { promises.push(p) } return Promise.all(promises).then(() => { - <%= (loading ? 'this.$loading.finish && this.$loading.finish(30)' : '') %> + <%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %> _forceUpdate() }) } diff --git a/lib/app/server.js b/lib/app/server.js index 1198882244..65ea565c72 100644 --- a/lib/app/server.js +++ b/lib/app/server.js @@ -2,9 +2,10 @@ const debug = require('debug')('nuxt:render') import Vue from 'vue' +import { stringify } from 'querystring' import { pick } from 'lodash' import { app, router<%= (store ? ', store' : '') %> } from './index' -import { getMatchedComponents, getContext } from './utils' +import { getMatchedComponents, getContext, urlJoin } from './utils' const isDev = <%= isDev %> const _app = new Vue(app) @@ -18,9 +19,25 @@ router.history.base = '<%= router.base %>' // Since data fetching is async, this function is expected to // return a Promise that resolves to the app instance. export default context => { + // create context.next for simulate next() of beforeEach() when wanted to redirect + context.redirected = false + context.next = function (path) { + if (!path) return; + if (typeof path === 'string') path = { path } + path.query = stringify(path.query || {}) + path.path = path.path + (path.query ? '?' + path.query : '') + path.path = urlJoin('<%= router.base %>', path.path) + if (!context.res) { + context.redirected = path.path + return + } + context.res.writeHead(302, { + 'Location': path.path + }) + context.res.end() + } // set router's location router.push(context.url) - // Add route to the context context.route = router.currentRoute // Add meta infos diff --git a/lib/app/utils.js b/lib/app/utils.js index c58f0a3986..58aabee886 100644 --- a/lib/app/utils.js +++ b/lib/app/utils.js @@ -25,6 +25,10 @@ export function getContext (context) { } ctx.params = ctx.route.params || {} ctx.query = ctx.route.query || {} + ctx.redirect = function (path) { + if (!path) return + context.next(path) + } if (context.req) ctx.req = context.req if (context.res) ctx.res = context.res return ctx @@ -38,3 +42,7 @@ export function getLocation (base) { } return (path || '/') + window.location.search + window.location.hash } + +exports.urlJoin = function () { + return [].slice.call(arguments).join('/').replace(/\/+/g, '/') +} diff --git a/lib/nuxt.js b/lib/nuxt.js index 0e0c243133..4418743335 100644 --- a/lib/nuxt.js +++ b/lib/nuxt.js @@ -145,6 +145,7 @@ class Nuxt { dev: self.dev, // Use to add the extracted CSS in production baseUrl: (self.options.router.base !== '/' ? self.options.router.base : null), APP: app, + redirected: context.redirected, context: context, files: { css: urlJoin(self.options.router.base, '/_nuxt/', self.options.build.filenames.css), @@ -152,7 +153,11 @@ class Nuxt { app: urlJoin(self.options.router.base, '/_nuxt/', self.options.build.filenames.app) } }) - return { html, error: context.nuxt.error } + return { + html, + error: context.nuxt.error, + redirected: context.redirected + } }) } diff --git a/lib/views/app.html b/lib/views/app.html index ed052bcc17..d20fe936c8 100644 --- a/lib/views/app.html +++ b/lib/views/app.html @@ -10,11 +10,19 @@ ${title.toString()} <% if (baseUrl) { %><% } %> <% if (!dev) { %><% } %> + <% if (redirected) { %> + + + <% } %> + <% if (!redirected) { %> <%= APP %> + <% } %> diff --git a/package.json b/package.json index 84017aef7a..0ce6a4522c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nuxt", - "version": "0.3.5", + "version": "0.3.6", "description": "A minimalistic framework for server-rendered Vue.js applications (inspired by Next.js)", "main": "index.js", "license": "MIT",