Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

feat(nuxt): config options for default keepalive, page & layout transitions #5859

Merged
merged 20 commits into from
Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/content/2.guide/3.directory-structure/10.pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ Of course, you are welcome to define metadata for your own use throughout your a

Nuxt will automatically wrap your page in [the Vue `<KeepAlive>` component](https://vuejs.org/guide/built-ins/keep-alive.html#keepalive) if you set `keepalive: true` in your `definePageMeta`. This might be useful to do, for example, in a parent route that has dynamic child routes, if you want to preserve page state across route changes. You can also set props to be passed to `<KeepAlive>` (see a full list [here](https://vuejs.org/api/built-in-components.html#keepalive)).

You can set a default value for this property [in your `nuxt.config`](/api/configuration/nuxt.config#keepalive).

#### `key`

[See above](#child-route-keys).
Expand All @@ -283,6 +285,8 @@ You can define middleware to apply before loading this page. It will be merged w

You can define transition properties for the `<transition>` component that wraps your pages and layouts, or pass `false` to disable the `<transition>` wrapper for that route. You can see a list of options that can be passed [here](https://vuejs.org/api/built-in-components.html#transition) or read [more about how transitions work](https://vuejs.org/guide/built-ins/transition.html#transition).

You can set default values for these properties [in your `nuxt.config`](/api/configuration/nuxt.config#layouttransition).

#### `alias`

You can define page aliases. They allow you to access the same page from different paths. It can be either a string or an array of strings as defined [here](https://router.vuejs.org/guide/essentials/redirect-and-alias.html#alias) on vue-router documentation.
Expand Down
7 changes: 3 additions & 4 deletions packages/nuxt/src/app/components/layout.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { defineComponent, isRef, Ref, Transition } from 'vue'
import { _wrapIf } from './utils'
import { useRoute } from '#app'
import { useAppConfig, useRoute } from '#app'
// @ts-ignore
import layouts from '#build/layouts'

const defaultLayoutTransition = { name: 'layout', mode: 'out-in' }

export default defineComponent({
props: {
name: {
Expand All @@ -15,6 +13,7 @@ export default defineComponent({
},
setup (props, context) {
const route = useRoute()
const appConfig = useAppConfig()

return () => {
const layout = (isRef(props.name) ? props.name.value : props.name) ?? route.meta.layout as string ?? 'default'
Expand All @@ -25,7 +24,7 @@ export default defineComponent({
}

// We avoid rendering layout transition if there is no layout to render
return _wrapIf(Transition, hasLayout && (route.meta.layoutTransition ?? defaultLayoutTransition),
return _wrapIf(Transition, hasLayout && (route.meta.layoutTransition ?? appConfig.nuxt.layoutTransition),
_wrapIf(layouts[layout], hasLayout, context.slots)
).default()
}
Expand Down
6 changes: 5 additions & 1 deletion packages/nuxt/src/core/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,17 @@ export const appConfigTemplate: NuxtTemplate = {
filename: 'app.config.mjs',
write: true,
getContents: ({ app, nuxt }) => {
const nuxtKeysToOmit = ['baseURL', 'buildAssetsDir', 'assetsPath', 'cdnURL']
return `
import defu from 'defu'

const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)}
const nuxtConfig = {
nuxt: ${JSON.stringify({ ...nuxt.options.app, ...Object.fromEntries(nuxtKeysToOmit.map(k => [k])) }, null, 2)},
}

${app.configs.map((id: string, index: number) => `import ${`cfg${index}`} from ${JSON.stringify(id)}`).join('\n')}
export default defu(${app.configs.map((_id: string, index: number) => `cfg${index}`).concat(['inlineConfig']).join(', ')})
export default defu(${app.configs.map((_id: string, index: number) => `cfg${index}`).concat(['inlineConfig', 'nuxtConfig']).join(', ')})
`
}
}
Expand Down
8 changes: 1 addition & 7 deletions packages/nuxt/src/head/module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { resolve } from 'pathe'
import { addPlugin, addTemplate, defineNuxtModule } from '@nuxt/kit'
import { addPlugin, defineNuxtModule } from '@nuxt/kit'
import { distDir } from '../dirs'

export default defineNuxtModule({
Expand All @@ -15,12 +15,6 @@ export default defineNuxtModule({
// Add #head alias
nuxt.options.alias['#head'] = runtimeDir

// Add global meta configuration
addTemplate({
filename: 'meta.config.mjs',
getContents: () => 'export default ' + JSON.stringify({ globalMeta: nuxt.options.app.head })
})

// Add generic plugin
addPlugin({ src: resolve(runtimeDir, 'plugin') })

Expand Down
8 changes: 3 additions & 5 deletions packages/nuxt/src/head/runtime/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { computed, getCurrentInstance, markRaw } from 'vue'
import * as Components from './components'
import { useHead } from './composables'
import { defineNuxtPlugin, useNuxtApp } from '#app'
// @ts-ignore
import metaConfig from '#build/meta.config.mjs'
import { defineNuxtPlugin, useAppConfig, useNuxtApp } from '#app'

type MetaComponents = typeof Components
declare module 'vue' {
export interface GlobalComponents extends MetaComponents {}
export interface GlobalComponents extends MetaComponents { }
}

const metaMixin = {
Expand All @@ -28,7 +26,7 @@ const metaMixin = {
}

export default defineNuxtPlugin((nuxtApp) => {
useHead(markRaw({ title: '', ...metaConfig.globalMeta }))
useHead(markRaw({ title: '', ...useAppConfig().nuxt.head }))

nuxtApp.vueApp.mixin(metaMixin)

Expand Down
11 changes: 5 additions & 6 deletions packages/nuxt/src/pages/runtime/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { computed, DefineComponent, defineComponent, h, inject, provide, reactiv
import { RouteLocation, RouteLocationNormalized, RouteLocationNormalizedLoaded, RouterView } from 'vue-router'

import { generateRouteKey, RouterViewSlotProps, wrapInKeepAlive } from './utils'
import { useNuxtApp } from '#app'
import { useAppConfig, useNuxtApp } from '#app'
import { _wrapIf } from '#app/components/utils'

const isNestedKey = Symbol('isNested')
Expand All @@ -24,6 +24,7 @@ export default defineComponent({
},
setup (props, { attrs }) {
const nuxtApp = useNuxtApp()
const appConfig = useAppConfig()

const isNested = inject(isNestedKey, false)
provide(isNestedKey, true)
Expand All @@ -35,9 +36,9 @@ export default defineComponent({

const key = generateRouteKey(props.pageKey, routeProps)

return _wrapIf(Transition, routeProps.route.meta.pageTransition ?? defaultPageTransition,
wrapInKeepAlive(routeProps.route.meta.keepalive, isNested && nuxtApp.isHydrating
// Include route children in parent suspense
return _wrapIf(Transition, routeProps.route.meta.pageTransition ?? appConfig.nuxt.pageTransition,
wrapInKeepAlive(routeProps.route.meta.keepalive ?? appConfig.nuxt.keepalive, isNested && nuxtApp.isHydrating
// Include route children in parent suspense
? h(Component, { key, routeProps, pageKey: key } as {})
: h(Suspense, {
onPending: () => nuxtApp.callHook('page:start', routeProps.Component),
Expand All @@ -55,8 +56,6 @@ export default defineComponent({
[key: string]: any
}>

const defaultPageTransition = { name: 'page', mode: 'out-in' }

const Component = defineComponent({
// TODO: Type props
// eslint-disable-next-line vue/require-prop-types
Expand Down
34 changes: 32 additions & 2 deletions packages/schema/src/config/_app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export default {
* }
* }
* ```
* @type {typeof import('../src/types/meta').MetaObject}
* @type {typeof import('../src/types/config').NuxtAppConfig['head']}
* @version 3
*/
head: {
Expand All @@ -123,7 +123,37 @@ export default {

return resolved
}
}
},
/**
* Default values for layout transitions.
*
* This can be overridden with `definePageMeta` on an individual page.
* Only JSON-serializable values are allowed.
*
* @see https://vuejs.org/api/built-in-components.html#transition
* @type {typeof import('../src/types/config').NuxtAppConfig['layoutTransition']}
*/
layoutTransition: { name: 'layout', mode: 'out-in' },
/**
* Default values for page transitions.
*
* This can be overridden with `definePageMeta` on an individual page.
* Only JSON-serializable values are allowed.
*
* @see https://vuejs.org/api/built-in-components.html#transition
* @type {typeof import('../src/types/config').NuxtAppConfig['pageTransition']}
*/
pageTransition: { name: 'page', mode: 'out-in' },
/**
* Default values for KeepAlive configuration between pages.
*
* This can be overridden with `definePageMeta` on an individual page.
* Only JSON-serializable values are allowed.
*
* @see https://vuejs.org/api/built-in-components.html#keepalive
* @type {typeof import('../src/types/config').NuxtAppConfig['keepalive']}
*/
keepalive: false,
},
/**
* The path to an HTML template file for rendering Nuxt responses.
Expand Down
17 changes: 14 additions & 3 deletions packages/schema/src/types/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { KeepAliveProps, TransitionProps } from 'vue'
import { ConfigSchema } from '../../schema/config'
import type { UserConfig as ViteUserConfig } from 'vite'
import type { Options as VuePluginOptions } from '@vitejs/plugin-vue'
import type { MetaObject } from './meta'

type DeepPartial<T> = T extends Function ? T : T extends Record<string, any> ? { [P in keyof T]?: DeepPartial<T[P]> } : T

Expand All @@ -13,8 +15,8 @@ export interface NuxtConfig extends DeepPartial<Omit<ConfigSchema, 'vite'>> {

// TODO: Expose ConfigLayer<T> from c12
interface ConfigLayer<T> {
config: T;
cwd: string;
config: T
cwd: string
configFile: string
}
export type NuxtConfigLayer = ConfigLayer<NuxtConfig & {
Expand Down Expand Up @@ -71,4 +73,13 @@ export interface AppConfigInput extends Record<string, any> {
nitro?: never
}

export interface AppConfig { }
export interface NuxtAppConfig {
head: MetaObject
layoutTransition: boolean | TransitionProps
pageTransition: boolean | TransitionProps
keepalive: boolean | KeepAliveProps
}

export interface AppConfig {
nuxt: NuxtAppConfig
pi0 marked this conversation as resolved.
Show resolved Hide resolved
}
6 changes: 6 additions & 0 deletions test/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,12 @@ describe('app config', () => {
const html = await $fetch('/app-config')

const expectedAppConfig = {
nuxt: {
head: { meta: [], link: [], style: [], script: [], noscript: [], charset: 'utf-8', viewport: 'width=1024, initial-scale=1' },
layoutTransition: { name: 'layout', mode: 'out-in' },
pageTransition: { name: 'page', mode: 'out-in' },
keepalive: false
},
fromNuxtConfig: true,
nested: {
val: 2
Expand Down