mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-27 08:02:01 +00:00
feat(server): fallback option (#4323)
This commit is contained in:
parent
9fbd581557
commit
68523b95bc
@ -1,3 +1,5 @@
|
|||||||
|
// TODO: Refactor @nuxt/server related options into `server.js`
|
||||||
|
|
||||||
export default () => ({
|
export default () => ({
|
||||||
bundleRenderer: {
|
bundleRenderer: {
|
||||||
shouldPrefetch: () => false
|
shouldPrefetch: () => false
|
||||||
@ -23,5 +25,16 @@ export default () => ({
|
|||||||
index: false,
|
index: false,
|
||||||
// 1 year in production
|
// 1 year in production
|
||||||
maxAge: '1y'
|
maxAge: '1y'
|
||||||
|
},
|
||||||
|
// https://github.com/nuxt/serve-placeholder
|
||||||
|
fallback: {
|
||||||
|
dist: {},
|
||||||
|
static: {
|
||||||
|
skipUnknown: true,
|
||||||
|
handlers: {
|
||||||
|
'.htm': false,
|
||||||
|
'.html': false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"ip": "^1.1.5",
|
"ip": "^1.1.5",
|
||||||
"launch-editor-middleware": "^2.2.1",
|
"launch-editor-middleware": "^2.2.1",
|
||||||
"pify": "^4.0.1",
|
"pify": "^4.0.1",
|
||||||
|
"serve-placeholder": "^1.1.0",
|
||||||
"serve-static": "^1.13.2",
|
"serve-static": "^1.13.2",
|
||||||
"server-destroy": "^1.0.1"
|
"server-destroy": "^1.0.1"
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import launchMiddleware from 'launch-editor-middleware'
|
import launchMiddleware from 'launch-editor-middleware'
|
||||||
import serveStatic from 'serve-static'
|
import serveStatic from 'serve-static'
|
||||||
|
import servePlaceholder from 'serve-placeholder'
|
||||||
import connect from 'connect'
|
import connect from 'connect'
|
||||||
import { determineGlobals, isUrl } from '@nuxt/common'
|
import { determineGlobals, isUrl } from '@nuxt/common'
|
||||||
|
|
||||||
@ -125,11 +126,30 @@ export default class Server {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add User provided middleware
|
// Add user provided middleware
|
||||||
this.options.serverMiddleware.forEach((m) => {
|
this.options.serverMiddleware.forEach((m) => {
|
||||||
this.useMiddleware(m)
|
this.useMiddleware(m)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { fallback } = this.options.render
|
||||||
|
if (fallback) {
|
||||||
|
// Graceful 404 errors for dist files
|
||||||
|
if (fallback.dist) {
|
||||||
|
this.useMiddleware({
|
||||||
|
path: this.publicPath,
|
||||||
|
handler: servePlaceholder(fallback.dist)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graceful 404 errors for other paths
|
||||||
|
if (fallback.static) {
|
||||||
|
this.useMiddleware({
|
||||||
|
path: '/',
|
||||||
|
handler: servePlaceholder(fallback.static)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Finally use nuxtMiddleware
|
// Finally use nuxtMiddleware
|
||||||
this.useMiddleware(nuxtMiddleware({
|
this.useMiddleware(nuxtMiddleware({
|
||||||
options: this.options,
|
options: this.options,
|
||||||
|
@ -254,19 +254,6 @@ export default class VueRenderer {
|
|||||||
const APP =
|
const APP =
|
||||||
`<div id="${this.context.globals.id}">${this.context.resources.loadingHTML}</div>` + BODY_SCRIPTS
|
`<div id="${this.context.globals.id}">${this.context.resources.loadingHTML}</div>` + BODY_SCRIPTS
|
||||||
|
|
||||||
// Detect 404 errors
|
|
||||||
if (
|
|
||||||
url.includes(this.context.options.build.publicPath) ||
|
|
||||||
url.includes('__webpack')
|
|
||||||
) {
|
|
||||||
const err = {
|
|
||||||
statusCode: 404,
|
|
||||||
message: this.context.options.messages.error_404,
|
|
||||||
name: 'ResourceNotFound'
|
|
||||||
}
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
|
|
||||||
const html = this.renderTemplate(false, {
|
const html = this.renderTemplate(false, {
|
||||||
HTML_ATTRS,
|
HTML_ATTRS,
|
||||||
BODY_ATTRS,
|
BODY_ATTRS,
|
||||||
|
44
test/unit/fallback.test.js
Normal file
44
test/unit/fallback.test.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { getPort, loadFixture, Nuxt, rp } from '../utils'
|
||||||
|
|
||||||
|
let port
|
||||||
|
const url = route => 'http://localhost:' + port + route
|
||||||
|
|
||||||
|
let nuxt = null
|
||||||
|
|
||||||
|
describe('fallback', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
const config = await loadFixture('with-config')
|
||||||
|
nuxt = new Nuxt(config)
|
||||||
|
port = await getPort()
|
||||||
|
await nuxt.server.listen(port, 'localhost')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('robots.txt handled', async () => {
|
||||||
|
await expect(rp(url('/test/robots.txt')))
|
||||||
|
.rejects.toMatchObject({
|
||||||
|
statusCode: 404,
|
||||||
|
response: { body: '' }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('normal html routes should be rendered using SSR', async () => {
|
||||||
|
await expect(rp(url('/test/index.html')))
|
||||||
|
.rejects.toMatchObject({
|
||||||
|
statusCode: 404,
|
||||||
|
response: { body: expect.stringContaining('data-n-head-ssr') }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('uknown assets handled in dist', async () => {
|
||||||
|
await expect(rp(url('/test/orion/foo.xyz')))
|
||||||
|
.rejects.toMatchObject({
|
||||||
|
statusCode: 404,
|
||||||
|
response: { body: '' }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Close server and ask nuxt to stop listening to file changes
|
||||||
|
afterAll(async () => {
|
||||||
|
await nuxt.close()
|
||||||
|
})
|
||||||
|
})
|
@ -60,15 +60,6 @@ describe('spa', () => {
|
|||||||
expect(html).toMatch('error handler triggered: asyncData error!')
|
expect(html).toMatch('error handler triggered: asyncData error!')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('/_nuxt/ (access publicPath in spa mode)', async () => {
|
|
||||||
await expect(renderRoute('/_nuxt/')).rejects.toMatchObject({
|
|
||||||
response: {
|
|
||||||
statusCode: 404,
|
|
||||||
statusMessage: 'ResourceNotFound'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Close server and ask nuxt to stop listening to file changes
|
// Close server and ask nuxt to stop listening to file changes
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await nuxt.close()
|
await nuxt.close()
|
||||||
|
23
yarn.lock
23
yarn.lock
@ -3597,6 +3597,15 @@ default-require-extensions@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
strip-bom "^2.0.0"
|
strip-bom "^2.0.0"
|
||||||
|
|
||||||
|
defaults-deep@^0.2.4:
|
||||||
|
version "0.2.4"
|
||||||
|
resolved "https://registry.npmjs.org/defaults-deep/-/defaults-deep-0.2.4.tgz#a479cfeafce025810fb93aa8d2dde0ee2d677cc6"
|
||||||
|
integrity sha512-V6BtqzcMvn0EPOy7f+SfMhfmTawq+7UQdt9yZH0EBK89+IHo5f+Hse/qzTorAXOBrQpxpwb6cB/8OgtaMrT+Fg==
|
||||||
|
dependencies:
|
||||||
|
for-own "^0.1.3"
|
||||||
|
is-extendable "^0.1.1"
|
||||||
|
lazy-cache "^0.2.3"
|
||||||
|
|
||||||
defaults@^1.0.3:
|
defaults@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
|
resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
|
||||||
@ -4676,7 +4685,7 @@ for-in@^1.0.1, for-in@^1.0.2:
|
|||||||
resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||||
integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
|
integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
|
||||||
|
|
||||||
for-own@^0.1.4:
|
for-own@^0.1.3, for-own@^0.1.4:
|
||||||
version "0.1.5"
|
version "0.1.5"
|
||||||
resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
|
resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
|
||||||
integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=
|
integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=
|
||||||
@ -6468,6 +6477,11 @@ launch-editor@^2.2.1:
|
|||||||
chalk "^2.3.0"
|
chalk "^2.3.0"
|
||||||
shell-quote "^1.6.1"
|
shell-quote "^1.6.1"
|
||||||
|
|
||||||
|
lazy-cache@^0.2.3:
|
||||||
|
version "0.2.7"
|
||||||
|
resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65"
|
||||||
|
integrity sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=
|
||||||
|
|
||||||
lazy-cache@^1.0.3:
|
lazy-cache@^1.0.3:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
|
resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
|
||||||
@ -9650,6 +9664,13 @@ serialize-javascript@^1.3.0, serialize-javascript@^1.4.0, serialize-javascript@^
|
|||||||
resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe"
|
resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe"
|
||||||
integrity sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==
|
integrity sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==
|
||||||
|
|
||||||
|
serve-placeholder@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/serve-placeholder/-/serve-placeholder-1.1.0.tgz#3c0930b311a9896c3d90903bb8ea60fff12101b2"
|
||||||
|
integrity sha512-kMYOLX8hwcyQ/8nLuyPcOhGhi4c29sJLsfz3i1vOFQnYMtZdPSsJLxxblTU+5wf6CPHh/g3EYo/V/SQ6eVEO5Q==
|
||||||
|
dependencies:
|
||||||
|
defaults-deep "^0.2.4"
|
||||||
|
|
||||||
serve-static@1.13.2, serve-static@^1.13.2:
|
serve-static@1.13.2, serve-static@^1.13.2:
|
||||||
version "1.13.2"
|
version "1.13.2"
|
||||||
resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
|
resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
|
||||||
|
Loading…
Reference in New Issue
Block a user