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 all 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
4 changes: 2 additions & 2 deletions packages/nuxt/src/app/components/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { _wrapIf } from './utils'
import { useRoute } from '#app'
// @ts-ignore
import layouts from '#build/layouts'

const defaultLayoutTransition = { name: 'layout', mode: 'out-in' }
// @ts-ignore
import { appLayoutTransition as defaultLayoutTransition } from '#build/nuxt.config.mjs'

export default defineComponent({
props: {
Expand Down
9 changes: 9 additions & 0 deletions packages/nuxt/src/core/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { isAbsolute, join, relative } from 'pathe'
import { resolveSchema, generateTypes } from 'untyped'
import escapeRE from 'escape-string-regexp'
import { hash } from 'ohash'
import { camelCase } from 'scule'

export interface TemplateContext {
nuxt: Nuxt
Expand Down Expand Up @@ -242,3 +243,11 @@ export const publicPathTemplate: NuxtTemplate = {
].filter(Boolean).join('\n')
}
}

// Allow direct access to specific exposed nuxt.config
export const nuxtConfigTemplate = {
filename: 'nuxt.config.mjs',
getContents: (ctx: TemplateContext) => {
return Object.entries(ctx.nuxt.options.app).map(([k, v]) => `export const ${camelCase('app-' + k)} = ${JSON.stringify(v)}`).join('\n\n')
}
}
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
6 changes: 3 additions & 3 deletions packages/nuxt/src/head/runtime/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import * as Components from './components'
import { useHead } from './composables'
import { defineNuxtPlugin, useNuxtApp } from '#app'
// @ts-ignore
import metaConfig from '#build/meta.config.mjs'
import { appHead } from '#build/nuxt.config.mjs'

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

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

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

nuxtApp.vueApp.mixin(metaMixin)

Expand Down
8 changes: 4 additions & 4 deletions packages/nuxt/src/pages/runtime/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import type { RouteLocation } from 'vue-router'
import { generateRouteKey, RouterViewSlotProps, wrapInKeepAlive } from './utils'
import { useNuxtApp } from '#app'
import { _wrapIf } from '#app/components/utils'
// @ts-ignore
import { appPageTransition as defaultPageTransition, appKeepalive as defaultKeepaliveConfig } from '#build/nuxt.config.mjs'

const isNestedKey = Symbol('isNested')

Expand Down Expand Up @@ -39,8 +41,8 @@ export default defineComponent({
const transitionProps = routeProps.route.meta.pageTransition ?? defaultPageTransition

return _wrapIf(Transition, transitionProps,
wrapInKeepAlive(routeProps.route.meta.keepalive, isNested && nuxtApp.isHydrating
// Include route children in parent suspense
wrapInKeepAlive(routeProps.route.meta.keepalive ?? defaultKeepaliveConfig, isNested && nuxtApp.isHydrating
// Include route children in parent suspense
? h(Component, { key, routeProps, pageKey: key, hasTransition: !!transitionProps } as {})
: h(Suspense, {
onPending: () => nuxtApp.callHook('page:start', routeProps.Component),
Expand All @@ -58,8 +60,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
13 changes: 11 additions & 2 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,11 @@ export interface AppConfigInput extends Record<string, any> {
nitro?: never
}

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

export interface AppConfig { }