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

View File

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

View File

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

View File

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