fix(vue-app): prevent error page mounting twice (#27484)

This commit is contained in:
Dmitriy 2024-06-14 15:57:40 +03:00 committed by GitHub
parent e0ca3d1af8
commit db15c3ab61
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 90 additions and 3 deletions

View File

@ -201,7 +201,7 @@ export default {
// Wait for asyncData & old fetch to finish
await Promise.all(p)
// Cleanup refs
p = []
p = []
if (page.$fetch) {
p.push(page.$fetch())
@ -244,6 +244,7 @@ export default {
<% if (splitChunks.layouts) { %>
await this.loadLayout(errorLayout)
<% } %>
this.nuxt.errPageReady = true
this.setLayout(errorLayout)
}
},

View File

@ -676,6 +676,12 @@ function setLayoutForNextPage(to) {
const layout = routeMap.get(to)
routeMap.delete(to)
const prevPageIsError = this._hadError && this._dateLastError === this.$options.nuxt.dateErr
if (prevPageIsError) {
this.$options.nuxt.err = null
}
this.setLayout(layout)
}
<% } %>
@ -946,6 +952,7 @@ async function mountApp (__app) {
_app.$loading = {} // To avoid error while _app.$nuxt does not exist
if (NUXT.error) {
_app.error(NUXT.error)
_app.nuxt.errPageReady = true
}
// Add beforeEach router hooks

View File

@ -74,8 +74,9 @@ export default {
Vue.util.defineReactive(this, 'nuxt', this.$root.$options.nuxt)
},
render (h) {
// if there is no error
if (!this.nuxt.err) {
// if there is no error or
// error page has not been loaded yet on client
if (!this.nuxt.err || (process.client && !this.nuxt.errPageReady)) {
// Directly return nuxt child
return h('NuxtChild', {
key: this.routerViewKey,

View File

@ -139,6 +139,7 @@ async function createApp(ssrContext, config = {}) {
},
<% } %>
err: null,
errPageReady: false,
dateErr: null,
error (err) {
err = err || null
@ -150,6 +151,7 @@ async function createApp(ssrContext, config = {}) {
}
nuxt.dateErr = Date.now()
nuxt.err = err
nuxt.errPageReady = false
// Used in src/server.js
if (ssrContext) {
ssrContext.nuxt.error = err

View File

@ -57,4 +57,40 @@ describe('page mount times while changing layouts', () => {
expect(await page.evaluate(() => window.mountedCount)).toEqual(4)
})
test('Open 404 error-page and mount 1 times', async () => {
page = await browser.page(url('/404'))
expect(await page.$text('h1')).toBe('Layout error')
expect(await page.$text('h2')).toBe('Error page 404')
expect(await page.evaluate(() => window.mountedCount)).toEqual(1)
})
test('Open another error-page and mount 1 times', async () => {
page = await browser.page(url('/403'))
expect(await page.$text('h1')).toBe('Layout error')
expect(await page.$text('h2')).toBe('Error page 403')
expect(await page.evaluate(() => window.mountedCount)).toEqual(1)
})
test('Change error layout to common', async () => {
page = await browser.page(url('/404'))
await page.nuxt.navigate('/page-1')
expect(await page.$text('h1')).toBe('Layout 1')
expect(await page.$text('h2')).toBe('Page 1')
expect(await page.evaluate(() => window.mountedCount)).toEqual(2)
})
test('Change common layout to error', async () => {
page = await browser.page(url('/page-1'))
await page.nuxt.navigate('/404')
expect(await page.$text('h1')).toBe('Layout error')
expect(await page.$text('h2')).toBe('Error page 404')
expect(await page.evaluate(() => window.mountedCount)).toEqual(2)
})
})

View File

@ -0,0 +1,22 @@
<template>
<div>
<h2>Error page {{ error.statusCode }}</h2>
<NuxtLink
id="link"
to="/page-1"
>
To page 1
</NuxtLink>
</div>
</template>
<script>
export default {
layout: 'layout-error',
props: ['error'],
mounted () {
window.mountedCount = (window.mountedCount || 0) + 1
}
}
</script>

View File

@ -0,0 +1,7 @@
<template>
<div>
<h1>Layout error</h1>
<Nuxt />
</div>
</template>

View File

@ -0,0 +1,11 @@
<template>
<div />
</template>
<script>
export default {
asyncData ({ error }) {
return error({ statusCode: 403 })
}
}
</script>