Skip to content

Commit

Permalink
fix(vue-app): handle missing payloads on full static (#8314)
Browse files Browse the repository at this point in the history
* fix(vue-app): handle missing payloads on full static

Fixes #7717

* chore: rename routesManifest to manifest

* chore: remove console.log

* chore(vue-app): don't have staticAssetsBase if undefined

* chore: add manifest option

* test: update snapshot

* chore: use foundRoute to avoid multiple vars name

Co-authored-by: Pooya Parsa <pyapar@gmail.com>
Co-authored-by: Daniel Roe <daniel@roe.dev>
  • Loading branch information
3 people committed Nov 25, 2020
1 parent e635cc5 commit 691f21c
Show file tree
Hide file tree
Showing 19 changed files with 191 additions and 179 deletions.
2 changes: 1 addition & 1 deletion distributions/nuxt-start/package.json
Expand Up @@ -63,7 +63,7 @@
"vue-client-only": "^2.0.0",
"vue-meta": "^2.4.0",
"vue-no-ssr": "^1.1.1",
"vue-router": "3.4.9",
"vue-router": "3.4.8",
"vuex": "^3.5.1"
},
"engines": {
Expand Down
4 changes: 2 additions & 2 deletions distributions/nuxt/package.json
Expand Up @@ -60,10 +60,10 @@
"dependencies": {
"@nuxt/builder": "2.14.7",
"@nuxt/cli": "2.14.7",
"@nuxt/components": "^1.2.0",
"@nuxt/components": "^1.1.1",
"@nuxt/core": "2.14.7",
"@nuxt/generator": "2.14.7",
"@nuxt/loading-screen": "^2.0.3",
"@nuxt/loading-screen": "^2.0.2",
"@nuxt/opencollective": "^0.3.2",
"@nuxt/static": "^1.0.0",
"@nuxt/telemetry": "^1.2.3",
Expand Down
18 changes: 9 additions & 9 deletions package.json
Expand Up @@ -33,8 +33,8 @@
"test:unit": "jest packages --forceExit"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/preset-env": "^7.12.7",
"@babel/core": "^7.12.3",
"@babel/preset-env": "^7.12.1",
"@ls-lint/ls-lint": "^1.9.2",
"@nuxtjs/eslint-config": "^5.0.0",
"@rollup/plugin-alias": "^3.1.1",
Expand All @@ -47,9 +47,9 @@
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.3",
"consola": "^2.15.0",
"create-require": "^1.1.0",
"create-require": "^1.0.2",
"cross-spawn": "^7.0.3",
"eslint": "^7.14.0",
"eslint": "^7.13.0",
"eslint-multiplexer": "^2.0.0",
"esm": "^3.2.25",
"execa": "^3.4.0",
Expand All @@ -62,21 +62,21 @@
"improved-yarn-audit": "^2.3.1",
"is-wsl": "^2.2.0",
"jest": "^26.6.3",
"jiti": "^0.1.16",
"jiti": "^0.1.12",
"jsdom": "^16.4.0",
"klaw-sync": "^6.0.0",
"lerna": "^3.22.1",
"lodash": "^4.17.20",
"node-fetch": "^2.6.1",
"node-sass": "^4.14.1",
"puppeteer-core": "^5.5.0",
"puppeteer-core": "^5.4.1",
"request": "^2.88.2",
"rimraf": "^3.0.2",
"rollup": "2.33.3",
"rollup": "2.33.1",
"rollup-plugin-license": "^2.2.0",
"sass-loader": "^8.0.2",
"sort-package-json": "^1.48.0",
"typescript": "~4.1",
"sort-package-json": "^1.46.1",
"typescript": "~4.0",
"vue-jest": "^4.0.0-rc.0"
}
}
6 changes: 3 additions & 3 deletions packages/babel-preset-app/package.json
Expand Up @@ -10,14 +10,14 @@
],
"main": "src/index.js",
"dependencies": {
"@babel/core": "^7.12.9",
"@babel/core": "^7.12.3",
"@babel/helper-compilation-targets": "^7.12.5",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-decorators": "^7.12.1",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
"@babel/plugin-proposal-optional-chaining": "^7.12.7",
"@babel/plugin-proposal-optional-chaining": "^7.12.1",
"@babel/plugin-transform-runtime": "^7.12.1",
"@babel/preset-env": "^7.12.7",
"@babel/preset-env": "^7.12.1",
"@babel/runtime": "^7.12.5",
"@vue/babel-preset-jsx": "^1.2.4",
"core-js": "^2.6.5"
Expand Down
6 changes: 3 additions & 3 deletions packages/config/package.json
Expand Up @@ -12,13 +12,13 @@
"dependencies": {
"@nuxt/utils": "2.14.7",
"consola": "^2.15.0",
"create-require": "^1.1.0",
"create-require": "^1.0.2",
"defu": "^2.0.4",
"destr": "^1.0.1",
"dotenv": "^8.2.0",
"esm": "^3.2.25",
"jiti": "^0.1.16",
"rc9": "^1.2.0",
"jiti": "^0.1.12",
"rc9": "^1.1.0",
"std-env": "^2.2.1"
},
"publishConfig": {
Expand Down
1 change: 1 addition & 0 deletions packages/config/src/config/generate.js
Expand Up @@ -7,6 +7,7 @@ export default () => ({
subFolders: true,
fallback: '200.html',
crawler: true,
manifest: true,
cache: {
ignore: [],
globbyOptions: {
Expand Down
1 change: 1 addition & 0 deletions packages/config/test/__snapshots__/options.test.js.snap
Expand Up @@ -205,6 +205,7 @@ Object {
"exclude": Array [],
"fallback": "200.html",
"interval": 0,
"manifest": true,
"routes": Array [],
"staticAssets": Object {
"base": "/_nuxt/static",
Expand Down
2 changes: 2 additions & 0 deletions packages/config/test/config/__snapshots__/index.test.js.snap
Expand Up @@ -184,6 +184,7 @@ Object {
"exclude": Array [],
"fallback": "200.html",
"interval": 0,
"manifest": true,
"routes": Array [],
"staticAssets": Object {
"base": undefined,
Expand Down Expand Up @@ -560,6 +561,7 @@ Object {
"exclude": Array [],
"fallback": "200.html",
"interval": 0,
"manifest": true,
"routes": Array [],
"staticAssets": Object {
"base": undefined,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Expand Up @@ -14,7 +14,7 @@
"@nuxt/utils": "2.14.7",
"@nuxt/vue-renderer": "2.14.7",
"consola": "^2.15.0",
"debug": "^4.3.1",
"debug": "^4.2.0",
"esm": "^3.2.25",
"fs-extra": "^8.1.0",
"hable": "^3.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/generator/package.json
Expand Up @@ -11,6 +11,7 @@
"@nuxt/utils": "2.14.7",
"chalk": "^3.0.0",
"consola": "^2.15.0",
"devalue": "^2.0.1",
"fs-extra": "^8.1.0",
"html-minifier": "^4.0.0",
"node-html-parser": "^2.0.0"
Expand Down
31 changes: 25 additions & 6 deletions packages/generator/src/generator.js
@@ -1,6 +1,7 @@
import path from 'path'
import chalk from 'chalk'
import consola from 'consola'
import devalue from 'devalue'
import fsExtra from 'fs-extra'
import defu from 'defu'
import htmlMinifier from 'html-minifier'
Expand Down Expand Up @@ -30,9 +31,14 @@ export default class Generator {
if (this.isFullStatic) {
const { build: { publicPath: _publicPath }, router: { base } } = this.options
const publicPath = isUrl(_publicPath) ? _publicPath : base
const { staticAssets } = this.options.generate
const { staticAssets, manifest } = this.options.generate
this.staticAssetsDir = path.resolve(this.distNuxtPath, staticAssets.dir, staticAssets.version)
this.staticAssetsBase = urlJoin(publicPath, this.options.generate.staticAssets.versionBase)
if (manifest) {
this.manifest = defu(manifest, {
routes: []
})
}
}

// Shared payload
Expand All @@ -54,6 +60,14 @@ export default class Generator {

await this.afterGenerate()

// Save routes manifest for full static
if (this.manifest) {
await this.nuxt.callHook('generate:manifest', this.manifest, this)
const manifestPath = path.join(this.staticAssetsDir, 'manifest.js')
await fsExtra.writeFile(manifestPath, `__NUXT_JSONP__("manifest.js", ${devalue(this.manifest)})`, 'utf-8')
consola.success('Static manifest generated')
}

// Done hook
await this.nuxt.callHook('generate:done', this, errors)
await this.nuxt.callHook('export:done', this, { errors })
Expand Down Expand Up @@ -254,7 +268,7 @@ export default class Generator {
// Add .nojekyll file to let GitHub Pages add the _nuxt/ folder
// https://help.github.com/articles/files-that-start-with-an-underscore-are-missing/
const nojekyllPath = path.resolve(this.distPath, '.nojekyll')
fsExtra.writeFile(nojekyllPath, '')
await fsExtra.writeFile(nojekyllPath, '')

await this.nuxt.callHook('generate:distCopied', this)
await this.nuxt.callHook('export:distCopied', this)
Expand Down Expand Up @@ -313,11 +327,11 @@ export default class Generator {
.replace(/\/+$/, '')
.trim()

const route = decodeURI(sanitizedHref + possibleTrailingSlash)
const foundRoute = decodeURI(sanitizedHref + possibleTrailingSlash)

if (route.startsWith('/') && !route.startsWith('//') && !path.extname(route) && this.shouldGenerateRoute(route) && !this.generatedRoutes.has(route)) {
this.generatedRoutes.add(route)
this.routes.push({ route })
if (foundRoute.startsWith('/') && !foundRoute.startsWith('//') && !path.extname(foundRoute) && this.shouldGenerateRoute(foundRoute) && !this.generatedRoutes.has(foundRoute)) {
this.generatedRoutes.add(foundRoute)
this.routes.push({ route: foundRoute })
}
return null
})
Expand All @@ -330,8 +344,13 @@ export default class Generator {
await fsExtra.ensureDir(path.dirname(assetPath))
await fsExtra.writeFile(assetPath, asset.src, 'utf-8')
}
// Add route to manifest (only if no error and redirect)
if (this.manifest && (!res.error && !res.redirected)) {
this.manifest.routes.push(route)
}
}

// SPA fallback
if (res.error) {
pageErrors.push({ type: 'handled', route, error: res.error })
}
Expand Down
6 changes: 3 additions & 3 deletions packages/types/package.json
Expand Up @@ -17,13 +17,13 @@
"@types/file-loader": "^4.2.0",
"@types/html-minifier": "^4.0.0",
"@types/less": "^3.0.1",
"@types/node": "^12.19.7",
"@types/node": "^12.19.3",
"@types/node-sass": "^4.11.1",
"@types/optimize-css-assets-webpack-plugin": "^5.0.1",
"@types/pug": "^2.0.4",
"@types/serve-static": "^1.13.8",
"@types/serve-static": "^1.13.6",
"@types/terser-webpack-plugin": "^2.2.0",
"@types/webpack": "^4.41.25",
"@types/webpack": "^4.41.24",
"@types/webpack-bundle-analyzer": "^3.9.0",
"@types/webpack-dev-middleware": "^3.7.2",
"@types/webpack-hot-middleware": "^2.25.3"
Expand Down
2 changes: 1 addition & 1 deletion packages/vue-app/package.json
Expand Up @@ -19,7 +19,7 @@
"vue-client-only": "^2.0.0",
"vue-meta": "^2.4.0",
"vue-no-ssr": "^1.1.1",
"vue-router": "3.4.9",
"vue-router": "3.4.8",
"vue-template-compiler": "^2.6.12",
"vuex": "^3.5.1"
},
Expand Down
34 changes: 28 additions & 6 deletions packages/vue-app/template/App.js
Expand Up @@ -295,18 +295,40 @@ export default {
<% } /* splitChunks.layouts */ %>
<% } /* features.layouts */ %>
<% if (isFullStatic) { %>
getRouterBase() {
return (this.$router.options.base || '').replace(/\/+$/, '')
},
getRoutePath(route = '/') {
const base = this.getRouterBase()
if (base && route.startsWith(base)) {
route = route.substr(base.length)
}
return (route.replace(/\/+$/, '') || '/').split('?')[0].split('#')[0]
},
getStaticAssetsPath(route = '/') {
const { staticAssetsBase } = window.<%= globals.context %>
return urlJoin(staticAssetsBase, this.getRoutePath(route))
},
<% if (nuxtOptions.generate.manifest) { %>
async fetchStaticManifest() {
return window.__NUXT_IMPORT__('manifest.js', encodeURI(urlJoin(this.getStaticAssetsPath(), 'manifest.js')))
},
<% } %>
setPagePayload(payload) {
this._pagePayload = payload
this._payloadFetchIndex = 0
},
async fetchPayload(route) {
const { staticAssetsBase } = window.<%= globals.context %>
const base = (this.$router.options.base || '').replace(/\/+$/, '')
if (base && route.startsWith(base)) {
route = route.substr(base.length)
<% if (nuxtOptions.generate.manifest) { %>
const manifest = await this.fetchStaticManifest()
const path = this.getRoutePath(route)
if (!manifest.routes.includes(path)) {
this.setPagePayload(false)
throw new Error(`Route ${path} is not pre-rendered`)
}
route = (route.replace(/\/+$/, '') || '/').split('?')[0].split('#')[0]
const src = urlJoin(staticAssetsBase, route, 'payload.js')
<% } %>
const src = urlJoin(this.getStaticAssetsPath(route), 'payload.js')
try {
const payload = await window.__NUXT_IMPORT__(decodeURI(route), encodeURI(src))
this.setPagePayload(payload)
Expand Down
11 changes: 7 additions & 4 deletions packages/vue-renderer/src/renderers/spa.js
Expand Up @@ -154,10 +154,13 @@ export default class SPARenderer extends BaseRenderer {
// Serialize state (runtime config)
let APP = `${meta.BODY_SCRIPTS_PREPEND}<div id="${this.serverContext.globals.id}">${this.serverContext.resources.loadingHTML}</div>${meta.BODY_SCRIPTS}`

APP += `<script>window.${this.serverContext.globals.context}=${devalue({
config: renderContext.runtimeConfig.public,
staticAssetsBase: renderContext.staticAssetsBase
})}</script>`
const payload = {
config: renderContext.runtimeConfig.public
}
if (renderContext.staticAssetsBase) {
payload.staticAssetsBase = renderContext.staticAssetsBase
}
APP += `<script>window.${this.serverContext.globals.context}=${devalue(payload)}</script>`

// Prepare template params
const templateParams = {
Expand Down
22 changes: 15 additions & 7 deletions packages/vue-renderer/src/renderers/ssr.js
Expand Up @@ -196,13 +196,21 @@ export default class SSRRenderer extends BaseRenderer {
APP += `<script>${stateScript}</script>`
}

// Page level payload.js (async loaded for CSR)
const payloadPath = urlJoin(url, 'payload.js')
const payloadUrl = urlJoin(staticAssetsBase, payloadPath)
const routePath = (url.replace(/\/+$/, '') || '/').split('?')[0] // remove trailing slah and query params
const payloadScript = `__NUXT_JSONP__("${routePath}", ${devalue({ data, fetch, mutations })});`
staticAssets.push({ path: payloadPath, src: payloadScript })
preloadScripts.push(payloadUrl)
// Save payload only if no error or redirection were made
if (!renderContext.nuxt.error && !renderContext.redirected) {
// Page level payload.js (async loaded for CSR)
const payloadPath = urlJoin(url, 'payload.js')
const payloadUrl = urlJoin(staticAssetsBase, payloadPath)
const routePath = (url.replace(/\/+$/, '') || '/').split('?')[0] // remove trailing slah and query params
const payloadScript = `__NUXT_JSONP__("${routePath}", ${devalue({ data, fetch, mutations })});`
staticAssets.push({ path: payloadPath, src: payloadScript })
preloadScripts.push(payloadUrl)
// Add manifest preload
if (this.options.generate.manifest) {
const manifestUrl = urlJoin(staticAssetsBase, 'manifest.js')
preloadScripts.push(manifestUrl)
}
}

// Preload links
for (const href of preloadScripts) {
Expand Down
10 changes: 5 additions & 5 deletions packages/webpack/package.json
Expand Up @@ -8,16 +8,16 @@
"dist"
],
"dependencies": {
"@babel/core": "^7.12.9",
"@babel/core": "^7.12.3",
"@nuxt/babel-preset-app": "2.14.7",
"@nuxt/friendly-errors-webpack-plugin": "^2.5.0",
"@nuxt/utils": "2.14.7",
"babel-loader": "^8.2.1",
"babel-loader": "^8.1.0",
"cache-loader": "^4.1.0",
"caniuse-lite": "^1.0.30001161",
"caniuse-lite": "^1.0.30001157",
"chalk": "^3.0.0",
"consola": "^2.15.0",
"create-require": "^1.1.0",
"create-require": "^1.0.2",
"css-loader": "^3.6.0",
"cssnano": "^4.1.10",
"eventsource-polyfill": "^0.9.6",
Expand All @@ -38,7 +38,7 @@
"postcss-url": "^8.0.0",
"semver": "^7.3.2",
"std-env": "^2.2.1",
"style-resources-loader": "^1.4.1",
"style-resources-loader": "^1.3.3",
"terser-webpack-plugin": "^2.3.5",
"thread-loader": "^2.1.3",
"time-fix-plugin": "^2.0.7",
Expand Down
3 changes: 1 addition & 2 deletions renovate.json
Expand Up @@ -25,8 +25,7 @@
"wrap-ansi",
"terser-webpack-plugin",
"@types/terser-webpack-plugin",
"defu",
"vue-loader"
"defu"
],
"lockFileMaintenance": {
"enabled": true
Expand Down

0 comments on commit 691f21c

Please sign in to comment.