diff --git a/docs/content/3.docs/2.directory-structure/15.app.md b/docs/content/3.docs/2.directory-structure/15.app.md
index 82671e9b7c..d8761f9114 100644
--- a/docs/content/3.docs/2.directory-structure/15.app.md
+++ b/docs/content/3.docs/2.directory-structure/15.app.md
@@ -25,7 +25,9 @@ If you have a [`pages/`](/docs/directory-structure/pages) directory, to display
```vue [app.vue]
-
+
+
+
```
diff --git a/packages/nuxt3/src/pages/runtime/app.vue b/packages/nuxt3/src/pages/runtime/app.vue
index 8f62b8bf92..f8eacfa737 100644
--- a/packages/nuxt3/src/pages/runtime/app.vue
+++ b/packages/nuxt3/src/pages/runtime/app.vue
@@ -1,3 +1,5 @@
-
+
+
+
diff --git a/packages/nuxt3/src/pages/runtime/layout.ts b/packages/nuxt3/src/pages/runtime/layout.ts
index 419e682822..4f4781b55a 100644
--- a/packages/nuxt3/src/pages/runtime/layout.ts
+++ b/packages/nuxt3/src/pages/runtime/layout.ts
@@ -1,24 +1,33 @@
-import { defineComponent, h, Ref } from 'vue'
+import { defineComponent, isRef, Ref, Transition } from 'vue'
+import { useRoute } from 'vue-router'
+import { wrapIf } from './utils'
// @ts-ignore
import layouts from '#build/layouts'
+const defaultLayoutTransition = { name: 'layout', mode: 'out-in' }
+
export default defineComponent({
props: {
name: {
type: [String, Boolean, Object] as unknown as () => string | false | Ref,
- default: 'default'
+ default: null
}
},
setup (props, context) {
+ const route = useRoute()
+
return () => {
- const layout = (props.name && typeof props.name === 'object' ? props.name.value : props.name) ?? 'default'
- if (!layouts[layout]) {
- if (process.dev && layout && layout !== 'default') {
- console.warn(`Invalid layout \`${layout}\` selected.`)
- }
- return context.slots.default()
+ const layout = (isRef(props.name) ? props.name.value : props.name) ?? route.meta.layout as string ?? 'default'
+
+ const hasLayout = layout && layout in layouts
+ if (process.dev && layout && !hasLayout && layout !== 'default') {
+ console.warn(`Invalid layout \`${layout}\` selected.`)
}
- return h(layouts[layout], props, context.slots)
+
+ // We avoid rendering layout transition if there is no layout to render
+ return wrapIf(Transition, hasLayout && (route.meta.layoutTransition ?? defaultLayoutTransition),
+ wrapIf(layouts[layout], hasLayout, context.slots)
+ ).default()
}
}
})
diff --git a/packages/nuxt3/src/pages/runtime/page.ts b/packages/nuxt3/src/pages/runtime/page.ts
index 4dad687375..c1b1f8116e 100644
--- a/packages/nuxt3/src/pages/runtime/page.ts
+++ b/packages/nuxt3/src/pages/runtime/page.ts
@@ -1,59 +1,27 @@
-import { Component, defineComponent, KeepAlive, h, Suspense, Transition } from 'vue'
-import { RouterView, useRoute } from 'vue-router'
-import NuxtLayout from './layout'
+import { defineComponent, h, Suspense, Transition } from 'vue'
+import { RouterView } from 'vue-router'
+import { wrapIf, wrapInKeepAlive } from './utils'
import { useNuxtApp } from '#app'
-// @ts-ignore
-import layouts from '#build/layouts'
type InstanceOf = T extends new (...args: any[]) => infer R ? R : never
type RouterViewSlotProps = Parameters['$slots']['default']>[0]
export default defineComponent({
name: 'NuxtPage',
- props: {
- layout: {
- type: String,
- default: null
- }
- },
- setup (props) {
+ setup () {
const nuxtApp = useNuxtApp()
- const route = useRoute()
return () => {
- // We avoid rendering layout transition if there is no layout to render
- const hasLayout = props.layout ?? route.meta.layout ?? 'default' in layouts
-
return h(RouterView, {}, {
- default: ({ Component }: RouterViewSlotProps) => Component &&
- wrapIf(Transition, hasLayout && (route.meta.layoutTransition ?? defaultLayoutTransition),
- wrapIf(NuxtLayout, hasLayout && { name: props.layout ?? route.meta.layout },
+ default: ({ Component, route }: RouterViewSlotProps) => Component &&
wrapIf(Transition, route.meta.pageTransition ?? defaultPageTransition,
wrapInKeepAlive(route.meta.keepalive, h(Suspense, {
onPending: () => nuxtApp.callHook('page:start', Component),
onResolve: () => nuxtApp.callHook('page:finish', Component)
- }, { default: () => h(Component) })
- )
- )
- )).default()
+ }, { default: () => h(Component) }))).default()
})
}
}
})
-const Fragment = {
- setup (props, { slots }) {
- return () => slots.default()
- }
-}
-
-const wrapIf = (component: Component, props: any, slots: any) => {
- return { default: () => props ? h(component, props === true ? {} : props, slots) : h(Fragment, {}, slots) }
-}
-
-const wrapInKeepAlive = (props: any, children: any) => {
- return { default: () => process.client && props ? h(KeepAlive, props === true ? {} : props, children) : children }
-}
-
-const defaultLayoutTransition = { name: 'layout', mode: 'out-in' }
const defaultPageTransition = { name: 'page', mode: 'out-in' }
diff --git a/packages/nuxt3/src/pages/runtime/utils.ts b/packages/nuxt3/src/pages/runtime/utils.ts
new file mode 100644
index 0000000000..3a163e7573
--- /dev/null
+++ b/packages/nuxt3/src/pages/runtime/utils.ts
@@ -0,0 +1,15 @@
+import { Component, KeepAlive, h } from 'vue'
+
+const Fragment = {
+ setup (_props, { slots }) {
+ return () => slots.default()
+ }
+}
+
+export const wrapIf = (component: Component, props: any, slots: any) => {
+ return { default: () => props ? h(component, props === true ? {} : props, slots) : h(Fragment, {}, slots) }
+}
+
+export const wrapInKeepAlive = (props: any, children: any) => {
+ return { default: () => process.client && props ? h(KeepAlive, props === true ? {} : props, children) : children }
+}