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 3 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 { layoutTransition as defaultLayoutTransition } from '#build/app.config.mjs'

export default defineComponent({
props: {
Expand Down
28 changes: 28 additions & 0 deletions packages/nuxt/src/core/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,34 @@ export const serverPluginTemplate = {
}
}

// Add app configuration
export const appConfigTemplate = {
filename: 'app.config.mjs',
getContents: (ctx: TemplateContext) => {
return Object.entries(ctx.nuxt.options.app).map(([k, v]) => `export const ${k} = ${JSON.stringify(v)}`).join('\n\n')
}
}

export const appViewTemplate = {
filename: 'views/document.template.mjs',
write: true,
getContents () {
return `export default (params) => \`<!DOCTYPE html>
<html \${params.HTML_ATTRS}>

<head \${params.HEAD_ATTRS}>
\${params.HEAD}
</head>

<body \${params.BODY_ATTRS}>\${params.BODY_PREPEND}
\${params.APP}
</body>

</html>\`
`
}
}

pi0 marked this conversation as resolved.
Show resolved Hide resolved
export const pluginsDeclaration = {
filename: 'types/plugins.d.ts',
getContents: (ctx: TemplateContext) => {
Expand Down
21 changes: 1 addition & 20 deletions packages/nuxt/src/head/module.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
import { resolve } from 'pathe'
import { addPlugin, addTemplate, defineNuxtModule } from '@nuxt/kit'
import defu from 'defu'
import { addPlugin, defineNuxtModule } from '@nuxt/kit'
import { distDir } from '../dirs'
import type { MetaObject } from './runtime'

export default defineNuxtModule({
meta: {
name: 'meta'
},
defaults: {
charset: 'utf-8',
viewport: 'width=device-width, initial-scale=1'
},
setup (options, nuxt) {
const runtimeDir = nuxt.options.alias['#head'] || resolve(distDir, 'head/runtime')

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

// Global meta -for Bridge, this is necessary to repeat here
// and in packages/schema/src/config/_app.ts
const globalMeta: MetaObject = defu(nuxt.options.app.head, {
charset: options.charset,
viewport: options.viewport
})

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

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

Expand Down
4 changes: 2 additions & 2 deletions packages/nuxt/src/head/runtime/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as Components from './components'
import { useHead } from './composables'
import { defineNuxtPlugin, useNuxtApp } from '#app'
// @ts-ignore
import metaConfig from '#build/meta.config.mjs'
import { head as globalMeta } from '#build/app.config.mjs'

type MetaComponents = typeof Components
declare module 'vue' {
Expand All @@ -28,7 +28,7 @@ const metaMixin = {
}

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

nuxtApp.vueApp.mixin(metaMixin)

Expand Down
6 changes: 3 additions & 3 deletions packages/nuxt/src/pages/runtime/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { RouteLocationNormalized, RouteLocationNormalizedLoaded, RouterView } fr
import { generateRouteKey, RouterViewSlotProps, wrapInKeepAlive } from './utils'
import { useNuxtApp } from '#app'
import { _wrapIf } from '#app/components/utils'
// @ts-ignore
import { pageTransition as defaultPageTransition, keepalive as defaultKeepaliveConfig } from '#build/app.config.mjs'

const isNestedKey = Symbol('isNested')

Expand Down Expand Up @@ -32,7 +34,7 @@ export default defineComponent({
return h(RouterView, { name: props.name, route: props.route, ...attrs }, {
default: (routeProps: RouterViewSlotProps) => routeProps.Component &&
_wrapIf(Transition, routeProps.route.meta.pageTransition ?? defaultPageTransition,
wrapInKeepAlive(routeProps.route.meta.keepalive,
wrapInKeepAlive(routeProps.route.meta.keepalive ?? defaultKeepaliveConfig,
isNested && nuxtApp.isHydrating
// Include route children in parent suspense
? h(routeProps.Component, { key: generateRouteKey(props.pageKey, routeProps) } as {})
Expand All @@ -50,5 +52,3 @@ export default defineComponent({
pageKey?: string | ((route: RouteLocationNormalizedLoaded) => string)
[key: string]: any
}>

const defaultPageTransition = { name: 'page', mode: 'out-in' }
35 changes: 34 additions & 1 deletion packages/schema/src/config/_app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,37 @@ export default {
})
}
},

/**
* 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 {boolean | typeof import('vue').TransitionProps}
*/
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 {boolean | typeof import('vue').TransitionProps}
*/
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 {boolean | typeof import('vue').KeepAliveProps}
*/
keepalive: false,
},
/**
* The path to a templated HTML file for rendering Nuxt responses.
Expand Down Expand Up @@ -184,7 +215,9 @@ export default {
/** Each item in the array maps to a newly-created `<style>` element, where object properties map to attributes. */
style: [],
/** Each item in the array maps to a newly-created `<script>` element, where object properties map to attributes. */
script: []
script: [],
charset: 'utf-8',
viewport: 'width=device-width, initial-scale=1'
},

/**
Expand Down