From a8713659452914a693b0ab5c4053b4e8d8823157 Mon Sep 17 00:00:00 2001 From: Jan Hug Date: Sun, 21 Sep 2025 06:22:38 +0200 Subject: [PATCH 1/3] test: use faster node environment where possible --- src/runtime/composables/useDataCache.ts | 4 ++-- .../composables/useDataCacheCallback.ts | 4 ++-- ...nuxt.spec.ts => client-bundle.node.spec.ts} | 0 ...nuxt.spec.ts => useCDNHeaders.node.spec.ts} | 13 +++++++++++-- ....nuxt.spec.ts => useDataCache.node.spec.ts} | 0 ...ec.ts => useDataCacheCallback.node.spec.ts} | 0 test/composables/useRouteCache.nuxt.spec.ts | 18 +++++++----------- ...per.nuxt.spec.ts => CDNHelper.node.spec.ts} | 0 ...r.nuxt.spec.ts => CacheHelper.node.spec.ts} | 0 ...pec.ts => CacheTagInvalidator.node.spec.ts} | 0 ...s => InMemoryCacheTagRegistry.node.spec.ts} | 0 ...t.spec.ts => RouteCacheHelper.node.spec.ts} | 0 ...tem.nuxt.spec.ts => cacheItem.node.spec.ts} | 0 ...maxAge.nuxt.spec.ts => maxAge.node.spec.ts} | 0 ...server.nuxt.spec.ts => server.node.spec.ts} | 0 ...uxt.spec.ts => server-options.node.spec.ts} | 0 .../{index.nuxt.spec.ts => index.node.spec.ts} | 0 ...m.nuxt.spec.ts => inspectItem.node.spec.ts} | 0 ...eAll.nuxt.spec.ts => purgeAll.node.spec.ts} | 0 ...tem.nuxt.spec.ts => purgeItem.node.spec.ts} | 0 .../{index.nuxt.spec.ts => index.node.spec.ts} | 0 vitest.config.mts | 3 ++- 22 files changed, 24 insertions(+), 18 deletions(-) rename test/build/{client-bundle.nuxt.spec.ts => client-bundle.node.spec.ts} (100%) rename test/composables/{useCDNHeaders.nuxt.spec.ts => useCDNHeaders.node.spec.ts} (91%) rename test/composables/{useDataCache.nuxt.spec.ts => useDataCache.node.spec.ts} (100%) rename test/composables/{useDataCacheCallback.nuxt.spec.ts => useDataCacheCallback.node.spec.ts} (100%) rename test/helpers/{CDNHelper.nuxt.spec.ts => CDNHelper.node.spec.ts} (100%) rename test/helpers/{CacheHelper.nuxt.spec.ts => CacheHelper.node.spec.ts} (100%) rename test/helpers/{CacheTagInvalidator.nuxt.spec.ts => CacheTagInvalidator.node.spec.ts} (100%) rename test/helpers/{InMemoryCacheTagRegistry.nuxt.spec.ts => InMemoryCacheTagRegistry.node.spec.ts} (100%) rename test/helpers/{RouteCacheHelper.nuxt.spec.ts => RouteCacheHelper.node.spec.ts} (100%) rename test/helpers/{cacheItem.nuxt.spec.ts => cacheItem.node.spec.ts} (100%) rename test/helpers/{maxAge.nuxt.spec.ts => maxAge.node.spec.ts} (100%) rename test/helpers/{server.nuxt.spec.ts => server.node.spec.ts} (100%) rename test/{server-options.nuxt.spec.ts => server-options.node.spec.ts} (100%) rename test/server/api/helpers/{index.nuxt.spec.ts => index.node.spec.ts} (100%) rename test/server/api/{inspectItem.nuxt.spec.ts => inspectItem.node.spec.ts} (100%) rename test/server/api/{purgeAll.nuxt.spec.ts => purgeAll.node.spec.ts} (100%) rename test/server/api/{purgeItem.nuxt.spec.ts => purgeItem.node.spec.ts} (100%) rename test/settings/{index.nuxt.spec.ts => index.node.spec.ts} (100%) diff --git a/src/runtime/composables/useDataCache.ts b/src/runtime/composables/useDataCache.ts index 94a550f..296e891 100644 --- a/src/runtime/composables/useDataCache.ts +++ b/src/runtime/composables/useDataCache.ts @@ -1,7 +1,7 @@ import type { H3Event } from 'h3' import { logger } from '../helpers/multi-cache-logger' import type { DataCacheCallbackContext } from '../types' -import { useNuxtApp } from '#imports' +import { useRequestEvent } from '#imports' import { debug, isServer } from '#nuxt-multi-cache/config' import { useDataCacheImplementation, @@ -25,7 +25,7 @@ export async function useDataCache( return dummy } - const event = providedEvent ?? useNuxtApp().ssrContext?.event + const event = providedEvent ?? useRequestEvent() if (!event) { if (debug) { diff --git a/src/runtime/composables/useDataCacheCallback.ts b/src/runtime/composables/useDataCacheCallback.ts index 5ba875e..ada13a2 100644 --- a/src/runtime/composables/useDataCacheCallback.ts +++ b/src/runtime/composables/useDataCacheCallback.ts @@ -1,6 +1,6 @@ import type { H3Event } from 'h3' import type { UseDataCacheCallbackCallback } from '../server/utils/useDataCacheCallback' -import { useNuxtApp } from '#imports' +import { useRequestEvent } from '#imports' import { logger } from '../helpers/multi-cache-logger' import { debug, isServer } from '#nuxt-multi-cache/config' import type { UseDataCacheOptions } from '../shared/useDataCache' @@ -13,7 +13,7 @@ export async function useDataCacheCallback( options?: UseDataCacheOptions, ): Promise { if (isServer) { - const event = providedEvent || useNuxtApp().ssrContext?.event + const event = providedEvent ?? useRequestEvent() if (event) { return useDataCacheCallbackImplementation(key, cb, event, options) diff --git a/test/build/client-bundle.nuxt.spec.ts b/test/build/client-bundle.node.spec.ts similarity index 100% rename from test/build/client-bundle.nuxt.spec.ts rename to test/build/client-bundle.node.spec.ts diff --git a/test/composables/useCDNHeaders.nuxt.spec.ts b/test/composables/useCDNHeaders.node.spec.ts similarity index 91% rename from test/composables/useCDNHeaders.nuxt.spec.ts rename to test/composables/useCDNHeaders.node.spec.ts index c5c245a..57e628a 100644 --- a/test/composables/useCDNHeaders.nuxt.spec.ts +++ b/test/composables/useCDNHeaders.node.spec.ts @@ -22,10 +22,17 @@ function buildEvent(): H3Event { } as H3Event } +let returnEvent = true + vi.mock('#imports', () => { return { - useRequestEvent: () => { - return buildEvent() + get useRequestEvent() { + return () => { + if (returnEvent) { + return buildEvent() + } + return undefined + } }, useRuntimeConfig: () => { return { @@ -55,6 +62,7 @@ vi.mock('#nuxt-multi-cache/config', () => { describe('useCDNHeaders composable', () => { beforeEach(() => { isServerValue = false + returnEvent = true }) test('Does not call callback in client', () => { const params = { @@ -105,6 +113,7 @@ describe('useCDNHeaders composable', () => { test('Does not call callback if event is missing.', () => { isServerValue = true + returnEvent = false const params = { cb() {}, diff --git a/test/composables/useDataCache.nuxt.spec.ts b/test/composables/useDataCache.node.spec.ts similarity index 100% rename from test/composables/useDataCache.nuxt.spec.ts rename to test/composables/useDataCache.node.spec.ts diff --git a/test/composables/useDataCacheCallback.nuxt.spec.ts b/test/composables/useDataCacheCallback.node.spec.ts similarity index 100% rename from test/composables/useDataCacheCallback.nuxt.spec.ts rename to test/composables/useDataCacheCallback.node.spec.ts diff --git a/test/composables/useRouteCache.nuxt.spec.ts b/test/composables/useRouteCache.nuxt.spec.ts index 91470b8..448ff13 100644 --- a/test/composables/useRouteCache.nuxt.spec.ts +++ b/test/composables/useRouteCache.nuxt.spec.ts @@ -19,6 +19,7 @@ mockNuxtImport('useRuntimeConfig', () => { }) let isServerValue = false +let returnEvent = true vi.mock('#nuxt-multi-cache/config', () => { return { @@ -58,24 +59,18 @@ function buildEvent(): H3Event { } as H3Event } -vi.mock('#imports', () => { - return { - useRequestEvent: () => { +mockNuxtImport('useRequestEvent', () => { + return () => { + if (returnEvent) { return buildEvent() - }, - useRuntimeConfig: () => { - return { - multiCache: { - data: true, - }, - } - }, + } } }) describe('useRouteCache composable', () => { beforeEach(() => { isServerValue = false + returnEvent = true }) test('Does not call callback in client', () => { const params = { @@ -126,6 +121,7 @@ describe('useRouteCache composable', () => { test('Does not call callback if event is missing.', () => { isServerValue = true + returnEvent = false const params = { cb() {}, diff --git a/test/helpers/CDNHelper.nuxt.spec.ts b/test/helpers/CDNHelper.node.spec.ts similarity index 100% rename from test/helpers/CDNHelper.nuxt.spec.ts rename to test/helpers/CDNHelper.node.spec.ts diff --git a/test/helpers/CacheHelper.nuxt.spec.ts b/test/helpers/CacheHelper.node.spec.ts similarity index 100% rename from test/helpers/CacheHelper.nuxt.spec.ts rename to test/helpers/CacheHelper.node.spec.ts diff --git a/test/helpers/CacheTagInvalidator.nuxt.spec.ts b/test/helpers/CacheTagInvalidator.node.spec.ts similarity index 100% rename from test/helpers/CacheTagInvalidator.nuxt.spec.ts rename to test/helpers/CacheTagInvalidator.node.spec.ts diff --git a/test/helpers/InMemoryCacheTagRegistry.nuxt.spec.ts b/test/helpers/InMemoryCacheTagRegistry.node.spec.ts similarity index 100% rename from test/helpers/InMemoryCacheTagRegistry.nuxt.spec.ts rename to test/helpers/InMemoryCacheTagRegistry.node.spec.ts diff --git a/test/helpers/RouteCacheHelper.nuxt.spec.ts b/test/helpers/RouteCacheHelper.node.spec.ts similarity index 100% rename from test/helpers/RouteCacheHelper.nuxt.spec.ts rename to test/helpers/RouteCacheHelper.node.spec.ts diff --git a/test/helpers/cacheItem.nuxt.spec.ts b/test/helpers/cacheItem.node.spec.ts similarity index 100% rename from test/helpers/cacheItem.nuxt.spec.ts rename to test/helpers/cacheItem.node.spec.ts diff --git a/test/helpers/maxAge.nuxt.spec.ts b/test/helpers/maxAge.node.spec.ts similarity index 100% rename from test/helpers/maxAge.nuxt.spec.ts rename to test/helpers/maxAge.node.spec.ts diff --git a/test/helpers/server.nuxt.spec.ts b/test/helpers/server.node.spec.ts similarity index 100% rename from test/helpers/server.nuxt.spec.ts rename to test/helpers/server.node.spec.ts diff --git a/test/server-options.nuxt.spec.ts b/test/server-options.node.spec.ts similarity index 100% rename from test/server-options.nuxt.spec.ts rename to test/server-options.node.spec.ts diff --git a/test/server/api/helpers/index.nuxt.spec.ts b/test/server/api/helpers/index.node.spec.ts similarity index 100% rename from test/server/api/helpers/index.nuxt.spec.ts rename to test/server/api/helpers/index.node.spec.ts diff --git a/test/server/api/inspectItem.nuxt.spec.ts b/test/server/api/inspectItem.node.spec.ts similarity index 100% rename from test/server/api/inspectItem.nuxt.spec.ts rename to test/server/api/inspectItem.node.spec.ts diff --git a/test/server/api/purgeAll.nuxt.spec.ts b/test/server/api/purgeAll.node.spec.ts similarity index 100% rename from test/server/api/purgeAll.nuxt.spec.ts rename to test/server/api/purgeAll.node.spec.ts diff --git a/test/server/api/purgeItem.nuxt.spec.ts b/test/server/api/purgeItem.node.spec.ts similarity index 100% rename from test/server/api/purgeItem.nuxt.spec.ts rename to test/server/api/purgeItem.node.spec.ts diff --git a/test/settings/index.nuxt.spec.ts b/test/settings/index.node.spec.ts similarity index 100% rename from test/settings/index.nuxt.spec.ts rename to test/settings/index.node.spec.ts diff --git a/vitest.config.mts b/vitest.config.mts index de7aff9..71b93be 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -5,7 +5,8 @@ import path from 'path' const alias: Record = { '~': path.resolve(__dirname), '#nuxt-multi-cache/config': path.resolve(__dirname, './.nuxt/nuxt-multi-cache/config.js'), - '#nuxt-multi-cache/server-options': path.resolve(__dirname, './.nuxt/nuxt-multi-cache/server-options.js') + '#nuxt-multi-cache/server-options': path.resolve(__dirname, './.nuxt/nuxt-multi-cache/server-options.js'), + '#imports': path.resolve(__dirname, './.nuxt/imports.mjs') } export default defineConfig({ From 4a5c49b653602a0042360f8f2429e09f252d84f6 Mon Sep 17 00:00:00 2001 From: Jan Hug Date: Sun, 21 Sep 2025 06:23:48 +0200 Subject: [PATCH 2/3] chore: extend prettier to entire repo --- .github/workflows/test.js.yml | 2 -- docs/.vitepress/theme/custom.css | 1 - docs/index.md | 20 +++++++++++++++----- docs/overview/migrating-from-v1.md | 14 ++++++++------ docs/use-cases/short-term-route-caching.md | 4 ++-- docs/use-cases/static-site-generation.md | 10 +++++----- package.json | 4 ++-- playground-disk/nuxt.config.ts | 2 +- playground/app/components/ReactiveTest.vue | 4 +++- playground/app/data/users.json | 1 - scripts/fakeData.js | 5 ++--- vitest.config.mts | 17 +++++++++++------ 12 files changed, 49 insertions(+), 35 deletions(-) diff --git a/.github/workflows/test.js.yml b/.github/workflows/test.js.yml index 314a907..cfbc049 100644 --- a/.github/workflows/test.js.yml +++ b/.github/workflows/test.js.yml @@ -42,5 +42,3 @@ jobs: run: | npm run dev:build npm run test:ci - - diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css index 8b13789..e69de29 100644 --- a/docs/.vitepress/theme/custom.css +++ b/docs/.vitepress/theme/custom.css @@ -1 +0,0 @@ - diff --git a/docs/index.md b/docs/index.md index 0b5ea50..d4f8cb4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,7 +5,10 @@ title: Nuxt Multi Cache for Nuxt 3 hero: name: Advanced Caching for Nuxt 3 - tagline: Seamless caching of components, routes and data. Dynamically define CDN cache control headers. Provides cache management API for purging items by key or using cache tags. + tagline: + Seamless caching of components, routes and data. Dynamically define CDN + cache control headers. Provides cache management API for purging items by + key or using cache tags. image: src: /nuxt-multi-cache.svg alt: nuxt-multi-cache @@ -20,14 +23,21 @@ hero: features: - title: Component Cache icon: ⚡ - details: Cache the rendered markup of components to reduce server render time of pages significantly. + details: + Cache the rendered markup of components to reduce server render time of + pages significantly. - title: Route Cache icon: 📑 - details: Cache the full response of pages or custom API routes, including headers. + details: + Cache the full response of pages or custom API routes, including headers. - title: Data Cache icon: 💾 - details: Generic composable to cache any data like external API responses or performance heavy calculations. + details: + Generic composable to cache any data like external API responses or + performance heavy calculations. - title: CDN Headers icon: 🌎 - details: Manage Cache-Control or Cache-Tag HTTP headers for caches like Cloudflare, Fastly or Varnish. + details: + Manage Cache-Control or Cache-Tag HTTP headers for caches like Cloudflare, + Fastly or Varnish. --- diff --git a/docs/overview/migrating-from-v1.md b/docs/overview/migrating-from-v1.md index 8d7cd43..5415a98 100644 --- a/docs/overview/migrating-from-v1.md +++ b/docs/overview/migrating-from-v1.md @@ -1,8 +1,8 @@ # Migrating from V1 -V2 was implemented from scratch and works completely different than V1. Also -due to the breaking changes introduced in Nuxt 3 migrating the code to support -Nuxt 3 was not possible. +V2 was implemented from scratch and works completely different than V1. Also due +to the breaking changes introduced in Nuxt 3 migrating the code to support Nuxt +3 was not possible. ## $cache Plugin @@ -13,6 +13,7 @@ The injected global `$cache` plugin is replaced by composables for each cache. Use the `useDataCache` composable to access the data cache. ### Nuxt 2 + ```typescript export default { async asyncData({ app }) { @@ -24,11 +25,12 @@ export default { const response = await this.$axios.get('/api/getWeather') await app.$cache.data.set('weather', response) return response - } + }, } ``` ### Nuxt 3 + ```typescript const { data: weather } = await useAsyncData('weather', async () => { const { value, addToCache } = await useDataCache('weather') @@ -57,7 +59,7 @@ export default { async asyncData({ app }) { app.$cache.route.setCacheable() app.$cache.route.addTags(['article:5', 'image:14']) - } + }, } ``` @@ -99,7 +101,7 @@ export default { serverCacheKey(props) { const variant = props.isHighlighted ? 'highlighted' : 'default' return `${props.productId}_${variant}` - } + }, } ``` diff --git a/docs/use-cases/short-term-route-caching.md b/docs/use-cases/short-term-route-caching.md index 6547507..234fd79 100644 --- a/docs/use-cases/short-term-route-caching.md +++ b/docs/use-cases/short-term-route-caching.md @@ -1,4 +1,4 @@ # Short Term Route Caching -For pages that change frequently you can set the max age to a lower value like -5 minutes. +For pages that change frequently you can set the max age to a lower value like 5 +minutes. diff --git a/docs/use-cases/static-site-generation.md b/docs/use-cases/static-site-generation.md index b8eb772..5f6423a 100644 --- a/docs/use-cases/static-site-generation.md +++ b/docs/use-cases/static-site-generation.md @@ -14,12 +14,12 @@ If you use an external cache backend like Redis you can even cache these components across multiple SSG executions. It's also possible to use [``](/features/component-cache) to -cache the markup of entire pages when used inside a layout component. This -means that if you need to regenerate the pages you only have to generate the -ones that have actually changed. +cache the markup of entire pages when used inside a layout component. This means +that if you need to regenerate the pages you only have to generate the ones that +have actually changed. Depending on your project this can significantly improve the time it takes to generate pages. -The benefits are noticeable the more pages and complex components you have. -This means the benefits will be barely noticeable if you only have 50 pages. +The benefits are noticeable the more pages and complex components you have. This +means the benefits will be barely noticeable if you only have 50 pages. diff --git a/package.json b/package.json index 7d8ce63..618f280 100644 --- a/package.json +++ b/package.json @@ -49,8 +49,8 @@ "docs:dev": "vitepress dev docs --port 5000", "docs:build": "vitepress build docs", "docs:serve": "vitepress serve docs --port 5000", - "prettier": "prettier ./src --check", - "prettier:fix": "prettier ./src --write", + "prettier": "prettier --check ./", + "prettier:fix": "prettier --write ./", "lint": "eslint ./src", "lint:fix": "eslint ./src --fix", "fake-data": "node ./scripts/fakeData.js", diff --git a/playground-disk/nuxt.config.ts b/playground-disk/nuxt.config.ts index 37315a1..13cf14e 100644 --- a/playground-disk/nuxt.config.ts +++ b/playground-disk/nuxt.config.ts @@ -32,4 +32,4 @@ export default defineNuxtConfig({ }, compatibilityDate: '2025-04-28', -}) \ No newline at end of file +}) diff --git a/playground/app/components/ReactiveTest.vue b/playground/app/components/ReactiveTest.vue index e1e54d5..ae4cf07 100644 --- a/playground/app/components/ReactiveTest.vue +++ b/playground/app/components/ReactiveTest.vue @@ -1,6 +1,8 @@ diff --git a/playground/app/data/users.json b/playground/app/data/users.json index 0414956..88ac294 100644 --- a/playground/app/data/users.json +++ b/playground/app/data/users.json @@ -1000,4 +1000,3 @@ "registeredAt": "2022-01-28T20:11:44.527Z" } ] - diff --git a/scripts/fakeData.js b/scripts/fakeData.js index 953ab0a..fc7ab4a 100644 --- a/scripts/fakeData.js +++ b/scripts/fakeData.js @@ -12,12 +12,12 @@ function createRandomUser() { birthdate: faker.date.birthdate(), company: faker.company.name(), registeredAt: faker.date.past(), - }; + } } async function generateUsers() { faker.seed(43234) - const users = Array.from({ length: 100 }).map(v => createRandomUser()) + const users = Array.from({ length: 100 }).map((v) => createRandomUser()) const destinationFile = path.resolve('./playground/data/users.json') await fsp.writeFile(destinationFile, JSON.stringify(users)) @@ -28,4 +28,3 @@ async function main() { } main() - diff --git a/vitest.config.mts b/vitest.config.mts index 71b93be..4272a54 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -4,21 +4,26 @@ import path from 'path' const alias: Record = { '~': path.resolve(__dirname), - '#nuxt-multi-cache/config': path.resolve(__dirname, './.nuxt/nuxt-multi-cache/config.js'), - '#nuxt-multi-cache/server-options': path.resolve(__dirname, './.nuxt/nuxt-multi-cache/server-options.js'), - '#imports': path.resolve(__dirname, './.nuxt/imports.mjs') + '#nuxt-multi-cache/config': path.resolve( + __dirname, + './.nuxt/nuxt-multi-cache/config.js', + ), + '#nuxt-multi-cache/server-options': path.resolve( + __dirname, + './.nuxt/nuxt-multi-cache/server-options.js', + ), + '#imports': path.resolve(__dirname, './.nuxt/imports.mjs'), } export default defineConfig({ test: { - projects: [ { test: { name: 'unit', include: ['test/**/*.{e2e,node}.spec.ts'], environment: 'node', - alias + alias, }, }, await defineVitestProject({ @@ -26,7 +31,7 @@ export default defineConfig({ name: 'nuxt', include: ['test/**/*.nuxt.spec.ts'], environment: 'nuxt', - alias + alias, }, }), ], From be0dea63e2a4d3024d48da935c2a7a37820c8351 Mon Sep 17 00:00:00 2001 From: Jan Hug Date: Sun, 21 Sep 2025 06:31:51 +0200 Subject: [PATCH 3/3] test: check presence of more strings in client bundles --- test/build/client-bundle.node.spec.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/build/client-bundle.node.spec.ts b/test/build/client-bundle.node.spec.ts index 3f6aaab..99f1fb1 100644 --- a/test/build/client-bundle.node.spec.ts +++ b/test/build/client-bundle.node.spec.ts @@ -11,7 +11,21 @@ type ClientBundle = { /** * The strings to check. */ -const STRINGS = ['consola'] +const STRINGS = [ + // Must not be included because the build plugin overrides the entire file exporting these. + 'consola', + 'serverOptions', + + // Should never be in the client bundle because it's noop on the client. + 'useCDNHeaders', + 'useRouteCache', + 'bubbleCacheability(', + + // Random strings that only appear in server code. + 'Failed to get component cache item', + 'Failed to get SSR context', + 'No H3Event provided', +] /** * Test that none of the defined strings appears in any of the generated client