diff --git a/packages/nuxt/src/app/plugins/router.ts b/packages/nuxt/src/app/plugins/router.ts index b3450d788e..0abf23b81c 100644 --- a/packages/nuxt/src/app/plugins/router.ts +++ b/packages/nuxt/src/app/plugins/router.ts @@ -1,4 +1,4 @@ -import { reactive, h } from 'vue' +import { reactive, h, isReadonly } from 'vue' import { parseURL, stringifyParsedURL, parseQuery, stringifyQuery, withoutBase, isEqual, joinURL } from 'ufo' import { createError } from 'h3' import { defineNuxtPlugin, clearError, navigateTo, showError, useRuntimeConfig, useState } from '..' @@ -222,8 +222,8 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>((nuxtApp) => { nuxtApp.hooks.hookOnce('app:created', async () => { router.beforeEach(async (to, from) => { to.meta = reactive(to.meta || {}) - if (nuxtApp.isHydrating) { - to.meta.layout = initialLayout.value ?? to.meta.layout + if (nuxtApp.isHydrating && initialLayout.value && !isReadonly(to.meta.layout)) { + to.meta.layout = initialLayout.value } nuxtApp._processingMiddleware = true diff --git a/packages/nuxt/src/pages/runtime/router.ts b/packages/nuxt/src/pages/runtime/router.ts index f01ce3b0d2..989849a452 100644 --- a/packages/nuxt/src/pages/runtime/router.ts +++ b/packages/nuxt/src/pages/runtime/router.ts @@ -1,4 +1,4 @@ -import { computed, reactive, shallowRef } from 'vue' +import { computed, isReadonly, reactive, shallowRef } from 'vue' import type { NavigationGuard, RouteLocation @@ -119,8 +119,8 @@ export default defineNuxtPlugin(async (nuxtApp) => { const initialLayout = useState('_layout') router.beforeEach(async (to, from) => { to.meta = reactive(to.meta) - if (nuxtApp.isHydrating) { - to.meta.layout = initialLayout.value ?? to.meta.layout + if (nuxtApp.isHydrating && initialLayout.value && !isReadonly(to.meta.layout)) { + to.meta.layout = initialLayout.value } nuxtApp._processingMiddleware = true diff --git a/test/basic.test.ts b/test/basic.test.ts index 8752d1fc43..48bfd745e5 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -410,6 +410,16 @@ describe('layouts', () => { expect(html).toContain('Custom Layout:') await expectNoClientErrors('/with-dynamic-layout') }) + it('should work with a computed layout', async () => { + const html = await $fetch('/with-computed-layout') + + // Snapshot + // expect(html).toMatchInlineSnapshot() + + expect(html).toContain('with-computed-layout') + expect(html).toContain('Custom Layout') + await expectNoClientErrors('/with-computed-layout') + }) it('should allow passing custom props to a layout', async () => { const html = await $fetch('/layouts/with-props') expect(html).toContain('some prop was passed') diff --git a/test/fixtures/basic/pages/with-computed-layout.vue b/test/fixtures/basic/pages/with-computed-layout.vue new file mode 100644 index 0000000000..49382a05cd --- /dev/null +++ b/test/fixtures/basic/pages/with-computed-layout.vue @@ -0,0 +1,11 @@ + + +