From 6ab65fbf4f2b0d2348363c43f5c2fe81ef47cbc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Thu, 16 Jul 2020 19:32:09 +0200 Subject: [PATCH] fix(vue-app): handle fallback on generated page (#7718) * fix(vue-app): handle fallback on generated page * chore: improvements and small refactor * fix: lint Co-authored-by: pooya parsa * chore: add force-build option to nuxt generate Co-authored-by: pooya parsa [release] --- packages/cli/src/commands/generate.js | 5 +++++ packages/cli/src/commands/start.js | 2 -- packages/cli/src/utils/generate.js | 4 ++-- packages/cli/src/utils/serve.js | 8 ++++++-- packages/vue-app/template/client.js | 20 ++++++++++++-------- packages/vue-app/template/utils.js | 10 +++++++++- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/packages/cli/src/commands/generate.js b/packages/cli/src/commands/generate.js index 68f248c1d0..47f27ab055 100644 --- a/packages/cli/src/commands/generate.js +++ b/packages/cli/src/commands/generate.js @@ -48,6 +48,11 @@ export default { } } }, + 'force-build': { + type: 'boolean', + default: false, + description: 'Force to build the application with webpack' + }, 'fail-on-error': { type: 'boolean', default: false, diff --git a/packages/cli/src/commands/start.js b/packages/cli/src/commands/start.js index a120a405b1..17677b208c 100644 --- a/packages/cli/src/commands/start.js +++ b/packages/cli/src/commands/start.js @@ -1,5 +1,4 @@ import { TARGETS } from '@nuxt/utils' -import consola from 'consola' import { common, server } from '../options' import { showBanner } from '../utils/banner' import { serve } from '../utils/serve' @@ -16,7 +15,6 @@ export default { const config = await cmd.getNuxtConfig({ dev: false, _start: true }) if (config.target === TARGETS.static) { - consola.info('Serving static dist') return serve(cmd) } diff --git a/packages/cli/src/utils/generate.js b/packages/cli/src/utils/generate.js index 830cee85da..084351f090 100644 --- a/packages/cli/src/utils/generate.js +++ b/packages/cli/src/utils/generate.js @@ -1,5 +1,5 @@ -import fs from 'fs' import path, { relative } from 'path' +import fs from 'fs-extra' import crc32 from 'crc/lib/crc32' import consola from 'consola' import globby from 'globby' @@ -19,7 +19,7 @@ export async function ensureBuild (cmd) { const nuxt = await getNuxt({ _build: true, server: false }, cmd) const { options } = nuxt - if (options.generate.cache === false || process.env.NUXT_BUILD) { + if (options.generate.cache === false || destr(process.env.NUXT_BUILD) || cmd.argv['force-build']) { const builder = await cmd.getBuilder(nuxt) await builder.build() await nuxt.close() diff --git a/packages/cli/src/utils/serve.js b/packages/cli/src/utils/serve.js index c272d7f4a4..7db03a7b62 100644 --- a/packages/cli/src/utils/serve.js +++ b/packages/cli/src/utils/serve.js @@ -1,5 +1,6 @@ import { promises as fs } from 'fs' -import { join, extname, basename } from 'path' +import { join, extname, sep } from 'path' +import consola from 'consola' import connect from 'connect' import serveStatic from 'serve-static' import compression from 'compression' @@ -20,8 +21,9 @@ export async function serve (cmd) { } catch (err) { } const distStat = await fs.stat(options.generate.dir).catch(err => null) // eslint-disable-line handle-callback-err + const distPath = join(options.generate.dir.replace(process.cwd() + sep, ''), sep) if (!distStat || !distStat.isDirectory()) { - throw new Error('Output directory `' + basename(options.generate.dir) + '/` does not exists, please use `nuxt generate` before `nuxt start` for static target.') + throw new Error('Output directory `' + distPath + '` does not exists, please use `nuxt generate` before `nuxt start` for static target.') } const app = connect() app.use(compression({ threshold: 0 })) @@ -70,4 +72,6 @@ export async function serve (cmd) { listeners: [listener] } }, false) + + consola.info(`Serving static application from \`${distPath}\``) } diff --git a/packages/vue-app/template/client.js b/packages/vue-app/template/client.js index b3f37b9d97..51c1c366b6 100644 --- a/packages/vue-app/template/client.js +++ b/packages/vue-app/template/client.js @@ -14,7 +14,8 @@ import { <% if (features.transitions || features.asyncData || features.fetch) { %>getLocation,<% } %> compile, getQueryDiff, - globalHandleError + globalHandleError, + isSamePath } from './utils.js' import { createApp<% if (features.layouts) { %>, NuxtError<% } %> } from './index.js' <% if (features.fetch) { %>import fetchMixin from './mixins/fetch.client'<% } %> @@ -829,7 +830,7 @@ async function mountApp (__app) { // Load page chunk if (!NUXT.data && NUXT.serverRendered) { try { - const payload = await _app.fetchPayload(_app.context.route.path) + const payload = await _app.fetchPayload(NUXT.routePath || _app.context.route.path) Object.assign(NUXT, payload) } catch (err) {} } @@ -887,14 +888,17 @@ async function mountApp (__app) { router.beforeEach(render.bind(_app)) // Fix in static: remove trailing slash to force hydration - if (process.static && NUXT.serverRendered && NUXT.routePath !== '/' && NUXT.routePath.slice(-1) !== '/' && _app.context.route.path.slice(-1) === '/') { - _app.context.route.path = _app.context.route.path.replace(/\/+$/, '') + // Full static, if server-rendered: hydrate, to allow custom redirect to generated page + <% if (isFullStatic) { %> + if (NUXT.serverRendered) { + return mount() } - // If page already is server rendered and it was done on the same route path as client side render - if (NUXT.serverRendered && NUXT.routePath === _app.context.route.path) { - mount() - return + <% } else { %> + // Fix in static: remove trailing slash to force hydration + if (NUXT.serverRendered && isSamePath(NUXT.routePath, _app.context.route.path)) { + return mount() } + <% } %> // First render on client-side const clientFirstMount = () => { diff --git a/packages/vue-app/template/utils.js b/packages/vue-app/template/utils.js index 126b584dca..2b2d568d74 100644 --- a/packages/vue-app/template/utils.js +++ b/packages/vue-app/template/utils.js @@ -648,10 +648,18 @@ export function addLifecycleHook(vm, hook, fn) { } } -export const urlJoin = function urlJoin () { +export function urlJoin () { return [].slice .call(arguments) .join('/') .replace(/\/+/g, '/') .replace(':/', '://') } + +export function stripTrailingSlash (path) { + return path.replace(/\/+$/, '') || '/' +} + +export function isSamePath (p1, p2) { + return stripTrailingSlash(p1) === stripTrailingSlash(p2) +}