Skip to content

Commit

Permalink
fix: don't set cache context on event.context (#65)
Browse files Browse the repository at this point in the history
Because this is shared for the duration of the entire SSR request, including calls made from components to API handlers
  • Loading branch information
dulnan authored Jul 29, 2024
1 parent 7a49c01 commit 83a35c0
Show file tree
Hide file tree
Showing 22 changed files with 183 additions and 144 deletions.
9 changes: 4 additions & 5 deletions docs/advanced/storage-instance.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Using the Storage Instance

The cache storage singleton is not exported directly, but you can access it
from the current request event. The singleton is only attached if the caches
are enabled.
The cache storage singleton is not exported directly, but you can access it from
the current request event. The singleton is only attached if the caches are
enabled.

```typescript
export default defineEventHandler(async (event) => {
const multiCache = event.context.__MULTI_CACHE
const multiCache = event.__MULTI_CACHE

await multiCache.component.clear()
await data = multiCache.data.getItem('foobar')
Expand All @@ -16,4 +16,3 @@ export default defineEventHandler(async (event) => {
}
})
```

2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions playground/pages/cachedPageWithUncacheableApi.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<div>
<h1>Cacheable Page using uncacheable API data</h1>
<div id="api-data">{{ data?.data }}</div>
</div>
</template>

<script lang="ts" setup>
import { useFetch, useRouteCache } from '#imports'

useRouteCache((v) => {
v.setCacheable()
})

const { data } = await useFetch('/api/uncacheableApi')
</script>
11 changes: 11 additions & 0 deletions playground/server/api/uncacheableApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineEventHandler } from 'h3'
import { useRouteCache } from '#nuxt-multi-cache/composables'

export default defineEventHandler<{ data: number }>((event) => {
useRouteCache((v) => {
v.setUncacheable()
}, event)
return {
data: Date.now(),
}
})
8 changes: 4 additions & 4 deletions src/runtime/helpers/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ export const MULTI_CACHE_PREFIX_KEY = '__MULTI_CACHE_PREFIX'
export function getMultiCacheContext(
event: H3Event,
): NuxtMultiCacheSSRContext | undefined {
return event?.context?.[MULTI_CACHE_CONTEXT_KEY]
return event?.[MULTI_CACHE_CONTEXT_KEY]
}

export function getMultiCacheRouteHelper(
event: H3Event,
): NuxtMultiCacheRouteCacheHelper | undefined {
return event?.context?.[MULTI_CACHE_ROUTE_CONTEXT_KEY]
return event?.[MULTI_CACHE_ROUTE_CONTEXT_KEY]
}

export function getMultiCacheCDNHelper(
event: H3Event,
): NuxtMultiCacheCDNHelper | undefined {
return event?.context?.[MULTI_CACHE_CDN_CONTEXT_KEY]
return event?.[MULTI_CACHE_CDN_CONTEXT_KEY]
}

export function getExpiresValue(maxAge: number) {
Expand All @@ -38,7 +38,7 @@ export function getCacheKeyWithPrefix(
cacheKey: string,
event: H3Event,
): string {
const prefix = event.context[MULTI_CACHE_PREFIX_KEY]
const prefix = event[MULTI_CACHE_PREFIX_KEY]
return prefix ? `${prefix}--${cacheKey}` : cacheKey
}

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/server/api/purgeTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import {
decodeRouteCacheItem,
} from '../../helpers/cacheItem'
import { useMultiCacheApp } from '../utils/useMultiCacheApp'
import { onlyUnique } from '../../helpers/server'
import { DEFAULT_CACHE_TAG_INVALIDATION_DELAY } from './../../settings'
import type { NuxtMultiCacheSSRContext } from './../../types'
import { checkAuth } from './helpers'
import { onlyUnique } from '../../helpers/server'

/**
* Get the tags to be purged from the request.
Expand Down
6 changes: 2 additions & 4 deletions src/runtime/server/hooks/afterResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,7 @@ export async function onAfterResponse(
ttl: routeHelper.maxAge,
})

if (event.context.__MULTI_CACHE_REVALIDATION_KEY) {
state.removeKeyBeingRevalidated(
event.context.__MULTI_CACHE_REVALIDATION_KEY,
)
if (event.__MULTI_CACHE_REVALIDATION_KEY) {
state.removeKeyBeingRevalidated(event.__MULTI_CACHE_REVALIDATION_KEY)
}
}
2 changes: 1 addition & 1 deletion src/runtime/server/hooks/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function onError(_error: Error, ctx: CapturedErrorContext) {
return
}
// Get the decoded route cache item. The "request" handler may have already fetched this, so we can reuse it.
const decoded = ctx.event.context.__MULTI_CACHE_DECODED_CACHED_ROUTE
const decoded = ctx.event.__MULTI_CACHE_DECODED_CACHED_ROUTE

if (!decoded) {
return
Expand Down
18 changes: 8 additions & 10 deletions src/runtime/server/hooks/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import { logger } from '../../helpers/logger'
import { useMultiCacheApp } from '../utils/useMultiCacheApp'
import { NuxtMultiCacheCDNHelper } from '../../helpers/CDNHelper'
import { serveCachedRoute } from '../../helpers/routeCache'
import { useRuntimeConfig } from '#imports'
import type { MultiCacheState } from '../../helpers/MultiCacheState'
import { useRuntimeConfig } from '#imports'

/**
* Add the cache context singleton to the current request.
Expand All @@ -33,27 +33,25 @@ async function addCacheContext(
// for example based on cookie or request headers.
if (serverOptions.cacheKeyPrefix) {
if (typeof serverOptions.cacheKeyPrefix === 'string') {
event.context[MULTI_CACHE_PREFIX_KEY] = serverOptions.cacheKeyPrefix
event[MULTI_CACHE_PREFIX_KEY] = serverOptions.cacheKeyPrefix
} else {
event.context[MULTI_CACHE_PREFIX_KEY] =
await serverOptions.cacheKeyPrefix(event)
event[MULTI_CACHE_PREFIX_KEY] = await serverOptions.cacheKeyPrefix(event)
}
}

// Add the cache context object to the SSR context object.
event.context[MULTI_CACHE_CONTEXT_KEY] = cache
event[MULTI_CACHE_CONTEXT_KEY] = cache

if (cache.route) {
// Add the route cache helper.
event.context[MULTI_CACHE_ROUTE_CONTEXT_KEY] =
new NuxtMultiCacheRouteCacheHelper()
event[MULTI_CACHE_ROUTE_CONTEXT_KEY] = new NuxtMultiCacheRouteCacheHelper()
}

if (config.cdn.enabled) {
const helper = new NuxtMultiCacheCDNHelper()

// Add the instances to the H3 event context.
event.context[MULTI_CACHE_CDN_CONTEXT_KEY] = helper
event[MULTI_CACHE_CDN_CONTEXT_KEY] = helper
}

return cache
Expand Down Expand Up @@ -180,13 +178,13 @@ export async function onRequest(event: H3Event) {
// Mark the key as being revalidated.
if (decoded.staleWhileRevalidate) {
state.addKeyBeingRevalidated(fullKey)
event.context.__MULTI_CACHE_REVALIDATION_KEY = fullKey
event.__MULTI_CACHE_REVALIDATION_KEY = fullKey
}

if (decoded.staleIfErrorExpires) {
// Store the decoded cache item in the event context.
// May be used by the error hook handler to serve a stale route on error.
event.context.__MULTI_CACHE_DECODED_CACHED_ROUTE = decoded
event.__MULTI_CACHE_DECODED_CACHED_ROUTE = decoded
}

// Returning, so the route is revalidated.
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ declare module 'nitropack' {
}

declare module 'h3' {
export interface H3EventContext {
export interface H3Event {
/**
* The nuxt-multi-cache cache context.
*/
Expand Down
28 changes: 13 additions & 15 deletions test/components/RenderCacheable/__helpers__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,19 @@ export function createTestApp(

const ssrContext = {
event: {
context: {
__MULTI_CACHE: {
component: {
setItemRaw: (key: string, data: any) => {
if (key === 'InnerComponent::set_error') {
throw new Error('Failed to set item.')
}
storage[key] = data
},
getItemRaw(key: string) {
if (key === 'InnerComponent::get_error') {
throw new Error('Failed to get item.')
}
return storage[key]
},
__MULTI_CACHE: {
component: {
setItemRaw: (key: string, data: any) => {
if (key === 'InnerComponent::set_error') {
throw new Error('Failed to set item.')
}
storage[key] = data
},
getItemRaw(key: string) {
if (key === 'InnerComponent::get_error') {
throw new Error('Failed to get item.')
}
return storage[key]
},
},
},
Expand Down
8 changes: 2 additions & 6 deletions test/composables/useCDNHeaders.nuxt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ vi.mock('vue', async (importOriginal) => {
useSSRContext: () => {
return {
event: {
context: {
__MULTI_CACHE_CDN: new NuxtMultiCacheCDNHelper(),
},
__MULTI_CACHE_CDN: new NuxtMultiCacheCDNHelper(),
},
}
},
Expand Down Expand Up @@ -64,9 +62,7 @@ describe('useCDNHeaders composable', () => {
expect(helper).toEqual(dummyHelper)
},
{
context: {
__MULTI_CACHE_CDN: dummyHelper,
},
__MULTI_CACHE_CDN: dummyHelper,
} as any,
)
})
Expand Down
46 changes: 20 additions & 26 deletions test/composables/useDataCache.nuxt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,14 @@ vi.mock('vue', async (importOriginal) => {
useSSRContext: () => {
return {
event: {
context: {
__MULTI_CACHE: {
data: {
getItem: (key: string) => {
return Promise.resolve(storage[key])
},
setItem: (key: string, data: any) => {
storage[key] = data
return Promise.resolve()
},
__MULTI_CACHE: {
data: {
getItem: (key: string) => {
return Promise.resolve(storage[key])
},
setItem: (key: string, data: any) => {
storage[key] = data
return Promise.resolve()
},
},
},
Expand Down Expand Up @@ -156,16 +154,14 @@ describe('useDataCache composable', () => {
foobar: { data: 'More cached data.' },
}
const event = {
context: {
__MULTI_CACHE: {
data: {
getItem: (key: string) => {
return Promise.resolve(storage[key])
},
setItem: (key: string, data: any) => {
storage[key] = data
return Promise.resolve()
},
__MULTI_CACHE: {
data: {
getItem: (key: string) => {
return Promise.resolve(storage[key])
},
setItem: (key: string, data: any) => {
storage[key] = data
return Promise.resolve()
},
},
},
Expand All @@ -180,12 +176,10 @@ describe('useDataCache composable', () => {
const consoleSpy = vi.spyOn(global.console, 'debug')

const event = {
context: {
__MULTI_CACHE: {
data: {
getItem: () => {
throw new Error('Failed to get item from cache.')
},
__MULTI_CACHE: {
data: {
getItem: () => {
throw new Error('Failed to get item from cache.')
},
},
},
Expand Down
24 changes: 10 additions & 14 deletions test/composables/useRouteCache.nuxt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,18 @@ vi.mock('vue', async (importOriginal) => {
useSSRContext: () => {
return {
event: {
context: {
__MULTI_CACHE: {
data: {
getItem: (key: string) => {
return Promise.resolve(storage[key])
},
setItem: (key: string, data: any) => {
storage[key] = data
return Promise.resolve()
},
__MULTI_CACHE: {
data: {
getItem: (key: string) => {
return Promise.resolve(storage[key])
},
setItem: (key: string, data: any) => {
storage[key] = data
return Promise.resolve()
},
},
__MULTI_CACHE_ROUTE: new NuxtMultiCacheRouteCacheHelper(),
},
__MULTI_CACHE_ROUTE: new NuxtMultiCacheRouteCacheHelper(),
},
}
},
Expand Down Expand Up @@ -78,9 +76,7 @@ describe('useRouteCache composable', () => {
expect(helper).toEqual(dummyHelper)
},
{
context: {
__MULTI_CACHE_ROUTE: dummyHelper,
},
__MULTI_CACHE_ROUTE: dummyHelper,
} as any,
)
})
Expand Down
16 changes: 6 additions & 10 deletions test/helpers/server.nuxt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,22 @@ import {
} from './../../src/runtime/helpers/server'

const EVENT: any = {
context: {
__MULTI_CACHE: {
component: {
getItem: () => {},
},
__MULTI_CACHE: {
component: {
getItem: () => {},
},
__MULTI_CACHE_ROUTE: new NuxtMultiCacheRouteCacheHelper(),
},
__MULTI_CACHE_ROUTE: new NuxtMultiCacheRouteCacheHelper(),
}

describe('Server helpers', () => {
test('getMultiCacheContext', () => {
expect(getMultiCacheContext({} as any)).toBeUndefined()
expect(getMultiCacheContext(EVENT)).toEqual(EVENT.context.__MULTI_CACHE)
expect(getMultiCacheContext(EVENT)).toEqual(EVENT.__MULTI_CACHE)
})

test('getMultiCacheRouteContext', () => {
expect(getMultiCacheRouteHelper({} as any)).toBeUndefined()
expect(getMultiCacheRouteHelper(EVENT)).toEqual(
EVENT.context.__MULTI_CACHE_ROUTE,
)
expect(getMultiCacheRouteHelper(EVENT)).toEqual(EVENT.__MULTI_CACHE_ROUTE)
})
})
Loading

0 comments on commit 83a35c0

Please sign in to comment.