Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(nuxt): provide route component names to KeepAlive cache #24024

Merged
merged 5 commits into from Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/nuxt/src/app/components/route-provider.ts
Expand Up @@ -4,7 +4,6 @@ import type { RouteLocation, RouteLocationNormalizedLoaded } from '#vue-router'
import { PageRouteSymbol } from './injections'

export const RouteProvider = defineComponent({
name: 'RouteProvider',
props: {
vnode: {
type: Object as () => VNode,
Expand Down
25 changes: 16 additions & 9 deletions packages/nuxt/src/pages/runtime/page.ts
Expand Up @@ -88,20 +88,27 @@ export default defineComponent({
{ onAfterLeave: () => { nuxtApp.callHook('page:transition:finish', routeProps.Component) } }
].filter(Boolean))

const keepaliveConfig = props.keepalive ?? routeProps.route.meta.keepalive ?? (defaultKeepaliveConfig as KeepAliveProps)
vnode = _wrapIf(Transition, hasTransition && transitionProps,
wrapInKeepAlive(props.keepalive ?? routeProps.route.meta.keepalive ?? (defaultKeepaliveConfig as KeepAliveProps), h(Suspense, {
wrapInKeepAlive(keepaliveConfig, h(Suspense, {
suspensible: true,
onPending: () => nuxtApp.callHook('page:start', routeProps.Component),
onResolve: () => { nextTick(() => nuxtApp.callHook('page:finish', routeProps.Component).finally(done)) }
}, {
default: () => h(RouteProvider, {
key: key || undefined,
vnode: routeProps.Component,
route: routeProps.route,
renderKey: key || undefined,
trackRootNodes: hasTransition,
vnodeRef: pageRef
})
default: () => {
const providerVNode = h(RouteProvider, {
key: key || undefined,
vnode: routeProps.Component,
route: routeProps.route,
renderKey: key || undefined,
trackRootNodes: hasTransition,
vnodeRef: pageRef
})
if (import.meta.client && keepaliveConfig) {
(providerVNode.type as any).name = (routeProps.Component.type as any).name || (routeProps.Component.type as any).__name || 'RouteProvider'
danielroe marked this conversation as resolved.
Show resolved Hide resolved
}
return providerVNode
}
})
)).default()

Expand Down
81 changes: 81 additions & 0 deletions test/basic.test.ts
Expand Up @@ -2017,6 +2017,87 @@ describe.runIf(isDev())('component testing', () => {
})
})

describe('keepalive', () => {
it('should not keepalive by default', async () => {
const { page, consoleLogs } = await renderPage('/keepalive')

const pageName = 'not-keepalive'
await page.click(`#${pageName}`)
await page.waitForTimeout(25)

expect(consoleLogs.map(l => l.text).filter(t => t.includes('keepalive'))).toEqual([`${pageName}: onMounted`])

await page.close()
})

it('should not keepalive when included in app config but config in nuxt-page is not undefined', async () => {
const { page, consoleLogs } = await renderPage('/keepalive')

const pageName = 'keepalive-in-config'
await page.click(`#${pageName}`)
await page.waitForTimeout(25)

expect(consoleLogs.map(l => l.text).filter(t => t.includes('keepalive'))).toEqual([`${pageName}: onMounted`])

await page.close()
})

it('should not keepalive when included in app config but exclueded in nuxt-page', async () => {
const { page, consoleLogs } = await renderPage('/keepalive')

const pageName = 'not-keepalive-in-nuxtpage'
await page.click(`#${pageName}`)
await page.waitForTimeout(25)

expect(consoleLogs.map(l => l.text).filter(t => t.includes('keepalive'))).toEqual([`${pageName}: onMounted`])

await page.close()
})

it('should keepalive when included in nuxt-page', async () => {
const { page, consoleLogs } = await renderPage('/keepalive')

const pageName = 'keepalive-in-nuxtpage'
await page.click(`#${pageName}`)
await page.waitForTimeout(25)

expect(consoleLogs.map(l => l.text).filter(t => t.includes('keepalive'))).toEqual([`${pageName}: onMounted`, `${pageName}: onActivated`])

await page.close()
})

it('should preserve keepalive config when navigate routes in nuxt-page', async () => {
const { page, consoleLogs } = await renderPage('/keepalive')

await page.click('#keepalive-in-nuxtpage')
await page.waitForTimeout(25)
await page.click('#keepalive-in-nuxtpage-2')
await page.waitForTimeout(25)
await page.click('#keepalive-in-nuxtpage')
await page.waitForTimeout(25)
await page.click('#not-keepalive')
await page.waitForTimeout(25)
await page.click('#keepalive-in-nuxtpage-2')
await page.waitForTimeout(25)

expect(consoleLogs.map(l => l.text).filter(t => t.includes('keepalive'))).toEqual([
'keepalive-in-nuxtpage: onMounted',
'keepalive-in-nuxtpage: onActivated',
'keepalive-in-nuxtpage: onDeactivated',
'keepalive-in-nuxtpage-2: onMounted',
'keepalive-in-nuxtpage-2: onActivated',
'keepalive-in-nuxtpage: onActivated',
'keepalive-in-nuxtpage-2: onDeactivated',
'keepalive-in-nuxtpage: onDeactivated',
'not-keepalive: onMounted',
'keepalive-in-nuxtpage-2: onActivated',
'not-keepalive: onUnmounted'
])

await page.close()
})
})

function normaliseIslandResult (result: NuxtIslandResponse) {
return {
...result,
Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/basic/composables/keep-alive.ts
@@ -0,0 +1,6 @@
export function useLifecyleLogs (name: string) {
onMounted(() => console.log(`${name}: onMounted`))
onUnmounted(() => console.log(`${name}: onUnmounted`))
onActivated(() => console.log(`${name}: onActivated`))
onDeactivated(() => console.log(`${name}: onDeactivated`))
}
3 changes: 3 additions & 0 deletions test/fixtures/basic/nuxt.config.ts
Expand Up @@ -22,6 +22,9 @@ export default defineNuxtConfig({
{ charset: 'utf-8' },
{ name: 'description', content: 'Nuxt Fixture' }
]
},
keepalive: {
include: ['keepalive-in-config', 'not-keepalive-in-nuxtpage']
}
},
buildDir: process.env.NITRO_BUILD_DIR,
Expand Down
26 changes: 26 additions & 0 deletions test/fixtures/basic/pages/keepalive.vue
@@ -0,0 +1,26 @@
<script setup lang="ts">
const links = ['keepalive-in-config', 'not-keepalive', 'keepalive-in-nuxtpage', 'keepalive-in-nuxtpage-2', 'not-keepalive-in-nuxtpage']
</script>

<template>
<div>
<h1>Keepalive Test</h1>
<NuxtLink
id="keepalive-home"
to="/keepalive"
>
Keepalive Home
</NuxtLink>
<div :style="{ display: 'flex', flexDirection: 'column', marginTop: '10px' }">
<NuxtLink
v-for="link in links"
:id="link"
:key="link"
:to="`/keepalive/${link}`"
>
{{ link }}
</NuxtLink>
</div>
<NuxtPage :keepalive="{ include: ['keepalive-in-nuxtpage', 'keepalive-in-nuxtpage-2'], exclude: ['not-keepalive-in-nuxtpage'] }" />
</div>
</template>
9 changes: 9 additions & 0 deletions test/fixtures/basic/pages/keepalive/keepalive-in-config.vue
@@ -0,0 +1,9 @@
<script setup lang="ts">
useLifecyleLogs('keepalive-in-config')
</script>

<template>
<div>
<h2>Keepalive in Config</h2>
</div>
</template>
@@ -0,0 +1,9 @@
<script setup lang="ts">
useLifecyleLogs('keepalive-in-nuxtpage-2')
</script>

<template>
<div>
<h2>Keepalive in `nuxt-page` 2</h2>
</div>
</template>
9 changes: 9 additions & 0 deletions test/fixtures/basic/pages/keepalive/keepalive-in-nuxtpage.vue
@@ -0,0 +1,9 @@
<script setup lang="ts">
useLifecyleLogs('keepalive-in-nuxtpage')
</script>

<template>
<div>
<h2>Keepalive in `nuxt-page`</h2>
</div>
</template>
@@ -0,0 +1,9 @@
<script setup lang="ts">
useLifecyleLogs('not-keepalive-in-nuxtpage')
</script>

<template>
<div>
<h2>Not Keepalive in `nuxt-page`</h2>
</div>
</template>
9 changes: 9 additions & 0 deletions test/fixtures/basic/pages/keepalive/not-keepalive.vue
@@ -0,0 +1,9 @@
<script setup lang="ts">
useLifecyleLogs('not-keepalive')
</script>

<template>
<div>
<h2>Not Keepalive</h2>
</div>
</template>