From db15c3ab613ce62f1ebb6e8076624a0b75a0f6bf Mon Sep 17 00:00:00 2001 From: Dmitriy <32272181+Kolobok12309@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:57:40 +0300 Subject: [PATCH] fix(vue-app): prevent error page mounting twice (#27484) --- packages/vue-app/template/App.js | 3 +- packages/vue-app/template/client.js | 7 ++++ packages/vue-app/template/components/nuxt.js | 5 +-- packages/vue-app/template/index.js | 2 ++ test/e2e/page-mount-with-layouts.test.js | 36 +++++++++++++++++++ .../page-mount-with-layouts/layouts/error.vue | 22 ++++++++++++ .../layouts/layout-error.vue | 7 ++++ .../page-mount-with-layouts/pages/403.vue | 11 ++++++ 8 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/page-mount-with-layouts/layouts/error.vue create mode 100644 test/fixtures/page-mount-with-layouts/layouts/layout-error.vue create mode 100644 test/fixtures/page-mount-with-layouts/pages/403.vue diff --git a/packages/vue-app/template/App.js b/packages/vue-app/template/App.js index c101bdf2a1..870d2eb7e1 100644 --- a/packages/vue-app/template/App.js +++ b/packages/vue-app/template/App.js @@ -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) } }, diff --git a/packages/vue-app/template/client.js b/packages/vue-app/template/client.js index 148bf92cbb..d18def5d6c 100644 --- a/packages/vue-app/template/client.js +++ b/packages/vue-app/template/client.js @@ -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 diff --git a/packages/vue-app/template/components/nuxt.js b/packages/vue-app/template/components/nuxt.js index 7f3ab77898..1d03179f82 100644 --- a/packages/vue-app/template/components/nuxt.js +++ b/packages/vue-app/template/components/nuxt.js @@ -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, diff --git a/packages/vue-app/template/index.js b/packages/vue-app/template/index.js index a82d4c5af7..0846a07269 100644 --- a/packages/vue-app/template/index.js +++ b/packages/vue-app/template/index.js @@ -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 diff --git a/test/e2e/page-mount-with-layouts.test.js b/test/e2e/page-mount-with-layouts.test.js index b89f1d2dac..15d42d8748 100644 --- a/test/e2e/page-mount-with-layouts.test.js +++ b/test/e2e/page-mount-with-layouts.test.js @@ -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) + }) }) diff --git a/test/fixtures/page-mount-with-layouts/layouts/error.vue b/test/fixtures/page-mount-with-layouts/layouts/error.vue new file mode 100644 index 0000000000..cf512eb5ad --- /dev/null +++ b/test/fixtures/page-mount-with-layouts/layouts/error.vue @@ -0,0 +1,22 @@ + + + diff --git a/test/fixtures/page-mount-with-layouts/layouts/layout-error.vue b/test/fixtures/page-mount-with-layouts/layouts/layout-error.vue new file mode 100644 index 0000000000..18dbe29dee --- /dev/null +++ b/test/fixtures/page-mount-with-layouts/layouts/layout-error.vue @@ -0,0 +1,7 @@ + diff --git a/test/fixtures/page-mount-with-layouts/pages/403.vue b/test/fixtures/page-mount-with-layouts/pages/403.vue new file mode 100644 index 0000000000..01f90db5c1 --- /dev/null +++ b/test/fixtures/page-mount-with-layouts/pages/403.vue @@ -0,0 +1,11 @@ + + +