Skip to content

Commit

Permalink
fix(nuxt): provide route component names to KeepAlive cache (#24024)
Browse files Browse the repository at this point in the history
  • Loading branch information
Clarkkkk committed Nov 14, 2023
1 parent b90b631 commit 5493d60
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 10 deletions.
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'
}
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>

0 comments on commit 5493d60

Please sign in to comment.