fix(vue-app): prevent double page mount (#10874)

This commit is contained in:
Dmitriy 2024-06-14 15:08:41 +03:00 committed by GitHub
parent 5441c062fa
commit 1f663e7f27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 153 additions and 4 deletions

View File

@ -649,7 +649,8 @@ function normalizeComponents (to, ___) {
}
<% if (features.layouts) { %>
<% if (splitChunks.layouts) { %>async <% } %>function setLayoutForNextPage (to) {
const routeMap = new WeakMap()
<% if (splitChunks.layouts) { %>async <% } %>function getLayoutForNextPage (to, from, next) {
// Set layout
let hasError = Boolean(this.$options.nuxt.err)
if (this._hadError && this._dateLastError === this.$options.nuxt.dateErr) {
@ -662,9 +663,19 @@ function normalizeComponents (to, ___) {
if (typeof layout === 'function') {
layout = layout(app.context)
}
routeMap.set(to, layout);
<% if (splitChunks.layouts) { %>
await this.loadLayout(layout)
<% } %>
if (next) next();
}
function setLayoutForNextPage(to) {
const layout = routeMap.get(to)
routeMap.delete(to)
this.setLayout(layout)
}
<% } %>
@ -903,6 +914,7 @@ async function mountApp (__app) {
// Add afterEach router hooks
router.afterEach(normalizeComponents)
<% if (features.layouts) { %>
router.beforeResolve(getLayoutForNextPage.bind(_app))
router.afterEach(setLayoutForNextPage.bind(_app))
<% } %>
router.afterEach(fixPrepatch.bind(_app))
@ -963,10 +975,15 @@ async function mountApp (__app) {
}
<% } %>
const clientFirstLayoutSet = <% if (splitChunks.layouts) { %>async<% } %> () => {
<% if (splitChunks.layouts) { %>await<% } %> getLayoutForNextPage.call(_app, router.currentRoute)
setLayoutForNextPage.call(_app, router.currentRoute)
}
// First render on client-side
const clientFirstMount = () => {
normalizeComponents(router.currentRoute, router.currentRoute)
setLayoutForNextPage.call(_app, router.currentRoute)
clientFirstLayoutSet()
checkForErrors(_app)
// Don't call fixPrepatch.call(_app, router.currentRoute, router.currentRoute) since it's first render
mount()

View File

@ -26,14 +26,14 @@ describe('nuxt basic resources size limit', () => {
const LEGACY_JS_RESOURCES_GZIP_KB_SIZE = 88
expect(legacyResourcesSize.gzip).toBeWithinSize(LEGACY_JS_RESOURCES_GZIP_KB_SIZE)
const LEGACY_JS_RESOURCES_BROTLI_KB_SIZE = 73
const LEGACY_JS_RESOURCES_BROTLI_KB_SIZE = 76
expect(legacyResourcesSize.brotli).toBeWithinSize(LEGACY_JS_RESOURCES_BROTLI_KB_SIZE)
})
it('should stay within the size limit range in modern mode', async () => {
const modernResourcesSize = await getResourcesSize(distDir, 'modern', { gzip: true, brotli: true })
const MODERN_JS_RESOURCES_KB_SIZE = 215
const MODERN_JS_RESOURCES_KB_SIZE = 225
expect(modernResourcesSize.uncompressed).toBeWithinSize(MODERN_JS_RESOURCES_KB_SIZE)
const MODERN_JS_RESOURCES_GZIP_KB_SIZE = 77

View File

@ -0,0 +1,60 @@
import Browser from '../utils/browser'
import { loadFixture, getPort, Nuxt } from '../utils'
let port
const browser = new Browser()
const url = route => 'http://localhost:' + port + route
let nuxt = null
let page = null
describe('page mount times while changing layouts', () => {
beforeAll(async () => {
const config = await loadFixture('page-mount-with-layouts')
nuxt = new Nuxt(config)
await nuxt.ready()
port = await getPort()
await nuxt.server.listen(port, 'localhost')
await browser.start()
page = await browser.page(url('/page-1'))
})
test('Open /page-1 and mount 1 times', async () => {
expect(await page.$text('h1')).toBe('Layout 1')
expect(await page.$text('h2')).toBe('Page 1')
expect(await page.evaluate(() => window.mountedCount)).toEqual(1)
})
test('Change layout and mount 2 times', async () => {
page = await browser.page(url('/page-1'))
await page.nuxt.navigate('/page-2')
expect(await page.$text('h1')).toBe('Layout 2')
expect(await page.$text('h2')).toBe('Page 2')
expect(await page.evaluate(() => window.mountedCount)).toEqual(2)
})
test('Change layout multiple times', async () => {
page = await browser.page(url('/page-2'))
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)
await page.nuxt.navigate('/page-2')
expect(await page.evaluate(() => window.mountedCount)).toEqual(3)
await page.nuxt.navigate('/page-1')
expect(await page.evaluate(() => window.mountedCount)).toEqual(4)
await page.nuxt.navigate('/page-1', false)
expect(await page.evaluate(() => window.mountedCount)).toEqual(4)
})
})

View File

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

View File

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

View File

@ -0,0 +1,11 @@
export default {
features: {
transitions: false
},
build: {
splitChunks: {
layouts: true
}
}
}

View File

@ -0,0 +1,3 @@
import { buildFixture } from '../../utils/build'
buildFixture('page-mount-with-layouts')

View File

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

View File

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