fix(nuxt3): render nuxt custom error page (#4289)

Co-authored-by: Pooya Parsa <pyapar@gmail.com>
This commit is contained in:
Daniel Roe 2022-04-12 21:37:32 +01:00 committed by GitHub
parent 0b12666d49
commit e43ba6ecd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 44 additions and 41 deletions

View File

@ -44,7 +44,7 @@
"magic-string": "^0.26.1", "magic-string": "^0.26.1",
"mlly": "^0.5.1", "mlly": "^0.5.1",
"murmurhash-es": "^0.1.1", "murmurhash-es": "^0.1.1",
"nitropack": "^0.2.6", "nitropack": "^0.2.7",
"node-fetch": "^3.2.3", "node-fetch": "^3.2.3",
"nuxi": "3.0.0", "nuxi": "3.0.0",
"ohash": "^0.1.0", "ohash": "^0.1.0",

View File

@ -69,6 +69,7 @@ export async function setupNitroBridge () {
buildDir: resolve(nuxt.options.buildDir), buildDir: resolve(nuxt.options.buildDir),
scanDirs: nuxt.options._layers.map(layer => join(layer.config.srcDir, 'server')), scanDirs: nuxt.options._layers.map(layer => join(layer.config.srcDir, 'server')),
renderer: resolve(distDir, 'runtime/nitro/renderer'), renderer: resolve(distDir, 'runtime/nitro/renderer'),
errorHandler: resolve(distDir, 'runtime/nitro/error'),
nodeModulesDirs: nuxt.options.modulesDir, nodeModulesDirs: nuxt.options.modulesDir,
handlers, handlers,
devHandlers: [], devHandlers: [],
@ -116,9 +117,6 @@ export async function setupNitroBridge () {
'#vue-renderer': resolve(distDir, 'runtime/nitro/vue2'), '#vue-renderer': resolve(distDir, 'runtime/nitro/vue2'),
'#vue2-server-renderer': 'vue-server-renderer/' + (nuxt.options.dev ? 'build.dev.js' : 'build.prod.js'), '#vue2-server-renderer': 'vue-server-renderer/' + (nuxt.options.dev ? 'build.dev.js' : 'build.prod.js'),
// Error renderer
'#nitro/error': resolve(distDir, 'runtime/nitro/error'),
// Paths // Paths
'#paths': resolve(distDir, 'runtime/nitro/paths'), '#paths': resolve(distDir, 'runtime/nitro/paths'),

View File

@ -50,7 +50,7 @@
"knitwork": "^0.1.1", "knitwork": "^0.1.1",
"magic-string": "^0.26.1", "magic-string": "^0.26.1",
"mlly": "^0.5.1", "mlly": "^0.5.1",
"nitropack": "^0.2.6", "nitropack": "^0.2.7",
"nuxi": "3.0.0", "nuxi": "3.0.0",
"ohash": "^0.1.0", "ohash": "^0.1.0",
"ohmyfetch": "^0.4.15", "ohmyfetch": "^0.4.15",

View File

@ -25,6 +25,7 @@ export async function initNitro (nuxt: Nuxt) {
buildDir: nuxt.options.buildDir, buildDir: nuxt.options.buildDir,
scanDirs: nuxt.options._layers.map(layer => join(layer.config.srcDir, 'server')), scanDirs: nuxt.options._layers.map(layer => join(layer.config.srcDir, 'server')),
renderer: resolve(distDir, 'core/runtime/nitro/renderer'), renderer: resolve(distDir, 'core/runtime/nitro/renderer'),
errorHandler: resolve(distDir, 'core/runtime/nitro/error'),
nodeModulesDirs: nuxt.options.modulesDir, nodeModulesDirs: nuxt.options.modulesDir,
handlers, handlers,
devHandlers: [], devHandlers: [],
@ -77,9 +78,6 @@ export async function initNitro (nuxt: Nuxt) {
// Renderer // Renderer
'#vue-renderer': resolve(distDir, 'core/runtime/nitro/vue3'), '#vue-renderer': resolve(distDir, 'core/runtime/nitro/vue3'),
// Error renderer
'#nitro/error': resolve(distDir, 'core/runtime/nitro/error'),
// Paths // Paths
'#paths': resolve(distDir, 'core/runtime/nitro/paths'), '#paths': resolve(distDir, 'core/runtime/nitro/paths'),

View File

@ -1,10 +1,13 @@
import type { CompatibilityEvent } from 'h3'
import { withQuery } from 'ufo' import { withQuery } from 'ufo'
import type { NitroErrorHandler } from 'nitropack'
// @ts-ignore TODO
import { normalizeError, isJsonRequest } from '#nitro/utils' import { normalizeError, isJsonRequest } from '#nitro/utils'
export default async function handleError (error: any, event: CompatibilityEvent) { export default <NitroErrorHandler> async function errorhandler (_error, event) {
const { stack, statusCode, statusMessage, message } = normalizeError(error) // Parse and normalize error
const { stack, statusCode, statusMessage, message } = normalizeError(_error)
// Create an error object
const errorObject = { const errorObject = {
url: event.req.url, url: event.req.url,
statusCode, statusCode,
@ -14,24 +17,30 @@ export default async function handleError (error: any, event: CompatibilityEvent
? `<pre>${stack.map(i => `<span class="stack${i.internal ? ' internal' : ''}">${i.text}</span>`).join('\n')}</pre>` ? `<pre>${stack.map(i => `<span class="stack${i.internal ? ' internal' : ''}">${i.text}</span>`).join('\n')}</pre>`
: '' : ''
} }
event.res.statusCode = error.statusCode || 500
event.res.statusMessage = error.statusMessage || 'Internal Server Error' // Set response code and message
event.res.statusCode = errorObject.statusCode
event.res.statusMessage = errorObject.statusMessage
// Console output // Console output
if (error.statusCode !== 404) { if (errorObject.statusCode !== 404) {
console.error('[nuxt] [request error]', error.message + '\n' + stack.map(l => ' ' + l.text).join(' \n')) console.error('[nuxt] [request error]', errorObject.message + '\n' + stack.map(l => ' ' + l.text).join(' \n'))
} }
// JSON response // JSON response
if (isJsonRequest(event)) { if (isJsonRequest(event)) {
event.res.setHeader('Content-Type', 'application/json') event.res.setHeader('Content-Type', 'application/json')
return event.res.end(JSON.stringify(errorObject)) event.res.end(JSON.stringify(errorObject))
return
} }
// HTML response // HTML response
const url = withQuery('/__nuxt_error', errorObject as any) const url = withQuery('/__nuxt_error', errorObject as any)
const html = await $fetch(url).catch(() => errorObject.statusMessage) const html = await $fetch(url).catch((error) => {
console.error('[nitro] Error while generating error response', error)
return errorObject.statusMessage
})
event.res.setHeader('Content-Type', 'text/html;charset=UTF-8') event.res.setHeader('Content-Type', 'text/html;charset=UTF-8')
return event.res.end(html) event.res.end(html)
} }

View File

@ -155,14 +155,13 @@ describe('errors', () => {
expect(res.status).toBe(500) expect(res.status).toBe(500)
const error = await res.json() const error = await res.json()
delete error.stack delete error.stack
expect(error).toMatchInlineSnapshot(` expect(error).toMatchObject({
{ description: process.env.NUXT_TEST_DEV ? expect.stringContaining('<pre>') : '',
"message": "This is a custom error", message: 'This is a custom error',
"statusCode": 500, statusCode: 500,
"statusMessage": "Internal Server Error", statusMessage: 'Internal Server Error',
"url": "/error", url: '/error'
} })
`)
}) })
it('should render a HTML error page', async () => { it('should render a HTML error page', async () => {

View File

@ -35,14 +35,13 @@ describe.skip('fixtures:bridge', async () => {
expect(res.status).toBe(500) expect(res.status).toBe(500)
const error = await res.json() const error = await res.json()
delete error.stack delete error.stack
expect(error).toMatchInlineSnapshot(` expect(error).toMatchObject({
{ description: process.env.NUXT_TEST_DEV ? expect.stringContaining('<pre>') : '',
"message": "This is a custom error", message: 'This is a custom error',
"statusCode": 500, statusCode: 500,
"statusMessage": "Internal Server Error", statusMessage: 'Internal Server Error',
"url": "/error", url: '/error'
} })
`)
}) })
it('should render a HTML error page', async () => { it('should render a HTML error page', async () => {

View File

@ -2620,7 +2620,7 @@ __metadata:
magic-string: ^0.26.1 magic-string: ^0.26.1
mlly: ^0.5.1 mlly: ^0.5.1
murmurhash-es: ^0.1.1 murmurhash-es: ^0.1.1
nitropack: ^0.2.6 nitropack: ^0.2.7
node-fetch: ^3.2.3 node-fetch: ^3.2.3
nuxi: 3.0.0 nuxi: 3.0.0
nuxt: ^2 nuxt: ^2
@ -14547,9 +14547,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"nitropack@npm:^0.2.6": "nitropack@npm:^0.2.7":
version: 0.2.6 version: 0.2.7
resolution: "nitropack@npm:0.2.6" resolution: "nitropack@npm:0.2.7"
dependencies: dependencies:
"@cloudflare/kv-asset-handler": ^0.2.0 "@cloudflare/kv-asset-handler": ^0.2.0
"@netlify/functions": ^1.0.0 "@netlify/functions": ^1.0.0
@ -14603,7 +14603,7 @@ __metadata:
rollup-plugin-terser: ^7.0.2 rollup-plugin-terser: ^7.0.2
rollup-plugin-visualizer: ^5.6.0 rollup-plugin-visualizer: ^5.6.0
scule: ^0.2.1 scule: ^0.2.1
semver: ^7.3.6 semver: ^7.3.7
serve-placeholder: ^2.0.1 serve-placeholder: ^2.0.1
serve-static: ^1.15.0 serve-static: ^1.15.0
std-env: ^3.0.1 std-env: ^3.0.1
@ -14615,7 +14615,7 @@ __metadata:
bin: bin:
nitro: dist/cli.mjs nitro: dist/cli.mjs
nitropack: dist/cli.mjs nitropack: dist/cli.mjs
checksum: f932d6f8e648746f9d9b69aa14fe0231a125ffd0a9f8fb3f911d9ed559daa411b9add68a882f6d525c759fd1924edb054e4977628e4727d0160d2849b3503930 checksum: 99cf3b20325e3ef27c84ad9d991376fb352bad0bf880741b31534c872067c9d39247b9fe4887c151c3b8e3e0001db6abfdc1be7bde159a1d554c6c4c9747fedd
languageName: node languageName: node
linkType: hard linkType: hard
@ -15296,7 +15296,7 @@ __metadata:
knitwork: ^0.1.1 knitwork: ^0.1.1
magic-string: ^0.26.1 magic-string: ^0.26.1
mlly: ^0.5.1 mlly: ^0.5.1
nitropack: ^0.2.6 nitropack: ^0.2.7
nuxi: 3.0.0 nuxi: 3.0.0
ohash: ^0.1.0 ohash: ^0.1.0
ohmyfetch: ^0.4.15 ohmyfetch: ^0.4.15