@trieb.work/nextjs-turbo-redis-cache 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +30 -6
- package/.github/workflows/release.yml +6 -3
- package/.next/trace +11 -0
- package/.vscode/settings.json +10 -0
- package/CHANGELOG.md +61 -0
- package/README.md +149 -34
- package/dist/index.d.mts +92 -20
- package/dist/index.d.ts +92 -20
- package/dist/index.js +319 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +315 -60
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -9
- package/scripts/vitest-run-staged.cjs +1 -1
- package/src/CachedHandler.ts +23 -9
- package/src/DeduplicatedRequestHandler.ts +50 -1
- package/src/RedisStringsHandler.ts +330 -89
- package/src/SyncedMap.ts +74 -4
- package/src/index.ts +4 -2
- package/src/utils/debug.ts +30 -0
- package/src/utils/json.ts +26 -0
- package/test/integration/next-app/README.md +36 -0
- package/test/integration/next-app/eslint.config.mjs +16 -0
- package/test/integration/next-app/next.config.js +6 -0
- package/test/integration/next-app/package-lock.json +5833 -0
- package/test/integration/next-app/package.json +29 -0
- package/test/integration/next-app/pnpm-lock.yaml +3679 -0
- package/test/integration/next-app/postcss.config.mjs +5 -0
- package/test/integration/next-app/public/file.svg +1 -0
- package/test/integration/next-app/public/globe.svg +1 -0
- package/test/integration/next-app/public/next.svg +1 -0
- package/test/integration/next-app/public/vercel.svg +1 -0
- package/test/integration/next-app/public/window.svg +1 -0
- package/test/integration/next-app/src/app/api/cached-static-fetch/route.ts +18 -0
- package/test/integration/next-app/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +27 -0
- package/test/integration/next-app/src/app/api/revalidatePath/route.ts +15 -0
- package/test/integration/next-app/src/app/api/revalidateTag/route.ts +15 -0
- package/test/integration/next-app/src/app/api/revalidated-fetch/route.ts +17 -0
- package/test/integration/next-app/src/app/api/uncached-fetch/route.ts +15 -0
- package/test/integration/next-app/src/app/globals.css +26 -0
- package/test/integration/next-app/src/app/layout.tsx +59 -0
- package/test/integration/next-app/src/app/page.tsx +755 -0
- package/test/integration/next-app/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +19 -0
- package/test/integration/next-app/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +34 -0
- package/test/integration/next-app/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +25 -0
- package/test/integration/next-app/src/app/pages/no-fetch/default-page/page.tsx +55 -0
- package/test/integration/next-app/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +19 -0
- package/test/integration/next-app/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +35 -0
- package/test/integration/next-app/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +25 -0
- package/test/integration/next-app/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +19 -0
- package/test/integration/next-app/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +32 -0
- package/test/integration/next-app/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +25 -0
- package/test/integration/next-app/src/app/revalidation-interface.tsx +267 -0
- package/test/integration/next-app/tsconfig.json +27 -0
- package/test/integration/next-app-customized/README.md +36 -0
- package/test/integration/next-app-customized/customized-cache-handler.js +34 -0
- package/test/integration/next-app-customized/eslint.config.mjs +16 -0
- package/test/integration/next-app-customized/next.config.js +6 -0
- package/test/integration/nextjs-cache-handler.integration.test.ts +840 -0
- package/vite.config.ts +23 -8
package/.github/workflows/ci.yml
CHANGED
|
@@ -27,28 +27,52 @@ jobs:
|
|
|
27
27
|
- name: Checkout code
|
|
28
28
|
uses: actions/checkout@v3
|
|
29
29
|
|
|
30
|
+
- name: Install pnpm
|
|
31
|
+
run: corepack enable
|
|
32
|
+
|
|
30
33
|
- name: Setup Node.js
|
|
31
34
|
uses: actions/setup-node@v3
|
|
32
35
|
with:
|
|
33
36
|
node-version: '20'
|
|
37
|
+
cache: 'pnpm'
|
|
34
38
|
|
|
35
39
|
- name: Install dependencies
|
|
36
|
-
run:
|
|
40
|
+
run: pnpm install
|
|
37
41
|
|
|
38
42
|
- name: Run lint
|
|
39
|
-
run:
|
|
43
|
+
run: pnpm lint
|
|
44
|
+
|
|
45
|
+
- name: Build project
|
|
46
|
+
run: pnpm build
|
|
47
|
+
|
|
48
|
+
- name: Start Redis
|
|
49
|
+
uses: supercharge/redis-github-action@1.8.0
|
|
50
|
+
with:
|
|
51
|
+
redis-version: '7'
|
|
52
|
+
redis-port: 6379
|
|
53
|
+
|
|
54
|
+
- name: Install redis-cli
|
|
55
|
+
run: sudo apt-get update && sudo apt-get install -y redis-tools
|
|
56
|
+
|
|
57
|
+
- name: Configure Redis Keyspace Notifications
|
|
58
|
+
run: redis-cli config set notify-keyspace-events Exe
|
|
59
|
+
|
|
60
|
+
- name: Install Integration Test Project
|
|
61
|
+
run: cd test/integration/next-app && pnpm install
|
|
62
|
+
|
|
63
|
+
- name: Build Integration Test Project
|
|
64
|
+
run: cd test/integration/next-app && pnpm build
|
|
40
65
|
|
|
41
66
|
- name: Run tests
|
|
42
|
-
run:
|
|
67
|
+
run: pnpm test
|
|
68
|
+
env:
|
|
69
|
+
SKIP_BUILD: true
|
|
43
70
|
|
|
44
71
|
- name: Code Coverage Comments
|
|
45
72
|
uses: kcjpop/coverage-comments@v2.2
|
|
46
73
|
with:
|
|
47
74
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
48
75
|
coverage-file: './coverage/lcov.info'
|
|
49
|
-
|
|
50
|
-
- name: Build project
|
|
51
|
-
run: npm run build
|
|
52
76
|
|
|
53
77
|
- name: Dry run the release
|
|
54
78
|
env:
|
|
@@ -23,17 +23,20 @@ jobs:
|
|
|
23
23
|
- name: Checkout code
|
|
24
24
|
uses: actions/checkout@v3
|
|
25
25
|
|
|
26
|
+
- name: Install pnpm
|
|
27
|
+
run: corepack enable
|
|
28
|
+
|
|
26
29
|
- name: Setup Node.js
|
|
27
30
|
uses: actions/setup-node@v3
|
|
28
31
|
with:
|
|
29
32
|
node-version: '20'
|
|
30
|
-
cache: '
|
|
33
|
+
cache: 'pnpm'
|
|
31
34
|
|
|
32
35
|
- name: Install dependencies
|
|
33
|
-
run:
|
|
36
|
+
run: pnpm install
|
|
34
37
|
|
|
35
38
|
- name: Build project
|
|
36
|
-
run:
|
|
39
|
+
run: pnpm run build
|
|
37
40
|
|
|
38
41
|
- name: Run Semantic Release
|
|
39
42
|
env:
|
package/.next/trace
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
[{"name":"generate-buildid","duration":140,"timestamp":4515754197453,"id":4,"parentId":1,"tags":{},"startTime":1746464013531,"traceId":"c44ff29d5c06adcb"},{"name":"load-custom-routes","duration":167,"timestamp":4515754197651,"id":5,"parentId":1,"tags":{},"startTime":1746464013531,"traceId":"c44ff29d5c06adcb"},{"name":"next-build","duration":581845,"timestamp":4515753617731,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464012951,"traceId":"c44ff29d5c06adcb"}]
|
|
2
|
+
[{"name":"generate-buildid","duration":217,"timestamp":4515766041037,"id":4,"parentId":1,"tags":{},"startTime":1746464025375,"traceId":"6cf74253dfcd5659"},{"name":"load-custom-routes","duration":199,"timestamp":4515766041361,"id":5,"parentId":1,"tags":{},"startTime":1746464025375,"traceId":"6cf74253dfcd5659"},{"name":"next-build","duration":97220,"timestamp":4515765945991,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464025280,"traceId":"6cf74253dfcd5659"}]
|
|
3
|
+
[{"name":"generate-buildid","duration":131,"timestamp":4515813285753,"id":4,"parentId":1,"tags":{},"startTime":1746464072620,"traceId":"fcfa690a3abfa3ea"},{"name":"load-custom-routes","duration":186,"timestamp":4515813285997,"id":5,"parentId":1,"tags":{},"startTime":1746464072620,"traceId":"fcfa690a3abfa3ea"},{"name":"next-build","duration":60933,"timestamp":4515813226764,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464072561,"traceId":"fcfa690a3abfa3ea"}]
|
|
4
|
+
[{"name":"generate-buildid","duration":120,"timestamp":4515831765983,"id":4,"parentId":1,"tags":{},"startTime":1746464091100,"traceId":"41bfa0fcaa95d6de"},{"name":"load-custom-routes","duration":162,"timestamp":4515831766158,"id":5,"parentId":1,"tags":{},"startTime":1746464091100,"traceId":"41bfa0fcaa95d6de"},{"name":"next-build","duration":64360,"timestamp":4515831703128,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464091037,"traceId":"41bfa0fcaa95d6de"}]
|
|
5
|
+
[{"name":"generate-buildid","duration":138,"timestamp":4515903825041,"id":4,"parentId":1,"tags":{},"startTime":1746464163159,"traceId":"b39fefc0a6cc67ce"},{"name":"load-custom-routes","duration":168,"timestamp":4515903825245,"id":5,"parentId":1,"tags":{},"startTime":1746464163160,"traceId":"b39fefc0a6cc67ce"},{"name":"next-build","duration":62582,"timestamp":4515903763978,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464163098,"traceId":"b39fefc0a6cc67ce"}]
|
|
6
|
+
[{"name":"generate-buildid","duration":131,"timestamp":4515927634537,"id":4,"parentId":1,"tags":{},"startTime":1746464186969,"traceId":"a7e49e03eb857d5c"},{"name":"load-custom-routes","duration":363,"timestamp":4515927634726,"id":5,"parentId":1,"tags":{},"startTime":1746464186969,"traceId":"a7e49e03eb857d5c"},{"name":"next-build","duration":68467,"timestamp":4515927568131,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464186903,"traceId":"a7e49e03eb857d5c"}]
|
|
7
|
+
[{"name":"generate-buildid","duration":109,"timestamp":4516102680149,"id":4,"parentId":1,"tags":{},"startTime":1746464362001,"traceId":"ad1b689177cf0789"},{"name":"load-custom-routes","duration":149,"timestamp":4516102680307,"id":5,"parentId":1,"tags":{},"startTime":1746464362001,"traceId":"ad1b689177cf0789"},{"name":"next-build","duration":56682,"timestamp":4516102625265,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464361946,"traceId":"ad1b689177cf0789"}]
|
|
8
|
+
[{"name":"generate-buildid","duration":108,"timestamp":4516106451659,"id":4,"parentId":1,"tags":{},"startTime":1746464365773,"traceId":"92f2d146f1781280"},{"name":"load-custom-routes","duration":154,"timestamp":4516106451818,"id":5,"parentId":1,"tags":{},"startTime":1746464365773,"traceId":"92f2d146f1781280"},{"name":"next-build","duration":54163,"timestamp":4516106398853,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464365720,"traceId":"92f2d146f1781280"}]
|
|
9
|
+
[{"name":"generate-buildid","duration":196,"timestamp":4516139403659,"id":4,"parentId":1,"tags":{},"startTime":1746464398725,"traceId":"a7a541a7bd9a53a0"},{"name":"load-custom-routes","duration":232,"timestamp":4516139403975,"id":5,"parentId":1,"tags":{},"startTime":1746464398725,"traceId":"a7a541a7bd9a53a0"},{"name":"next-build","duration":58401,"timestamp":4516139349232,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464398670,"traceId":"a7a541a7bd9a53a0"}]
|
|
10
|
+
[{"name":"generate-buildid","duration":103,"timestamp":4516187933744,"id":4,"parentId":1,"tags":{},"startTime":1746464447255,"traceId":"067afd570d8c005a"},{"name":"load-custom-routes","duration":177,"timestamp":4516187933896,"id":5,"parentId":1,"tags":{},"startTime":1746464447255,"traceId":"067afd570d8c005a"},{"name":"next-build","duration":56944,"timestamp":4516187878433,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464447199,"traceId":"067afd570d8c005a"}]
|
|
11
|
+
[{"name":"generate-buildid","duration":114,"timestamp":4516223927765,"id":4,"parentId":1,"tags":{},"startTime":1746464483249,"traceId":"8b53fbabb9360dbf"},{"name":"load-custom-routes","duration":166,"timestamp":4516223927936,"id":5,"parentId":1,"tags":{},"startTime":1746464483249,"traceId":"8b53fbabb9360dbf"},{"name":"next-build","duration":56140,"timestamp":4516223873187,"id":1,"tags":{"buildMode":"default","isTurboBuild":"false","version":"15.0.3"},"startTime":1746464483194,"traceId":"8b53fbabb9360dbf"}]
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,64 @@
|
|
|
1
|
+
# [1.3.0](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.2.1...v1.3.0) (2025-05-08)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* encoding of data in cache entry ([9f0e747](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/9f0e747b224294905427ba3060185f68fee16f0f))
|
|
7
|
+
* escape characte ([dbd9141](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/dbd91413b777b2a4554597f3ca2b7f1de1163a80))
|
|
8
|
+
* readme ([31dcaa4](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/31dcaa40ac19ea42a7f4d6ca33e4642704ad1f6b))
|
|
9
|
+
* readme ([dfb69c8](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/dfb69c861ddaa4a94411d419854e1c2e1e99152e))
|
|
10
|
+
* test ([13b2cb8](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/13b2cb8020ef7457473b208675bf3fce4161f492))
|
|
11
|
+
* tests ([02357e1](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/02357e1a7a29d997c95dce42399fef26530467d4))
|
|
12
|
+
* tests ([a5587dc](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/a5587dc3701a92069da945f548991aeb0d999285))
|
|
13
|
+
* tests + re-add old implementation ([cb6d36d](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/cb6d36d46008d422b4396fd580d35fa97848edb7))
|
|
14
|
+
* tests improvement ([73a3594](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/73a35946cfcd5e4811c2c09201bb02c9cdea5298))
|
|
15
|
+
* tests, make them independent from each other ([35885e3](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/35885e38a58ac0aa976c86dd964549e2d3426a79))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* add files ([d8a2474](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/d8a24747a6a2a12e2709d017dd36c7b80b2ad49f))
|
|
21
|
+
* add more comments ([fb2f105](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/fb2f10588566fad042d2e8da4999cf7bf591555d))
|
|
22
|
+
* add new invalidation logic for fetch requests + new tests ([9d0d1d2](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/9d0d1d2eafb785dbe91b172358a19494c623cc68))
|
|
23
|
+
* add new tests ([836b882](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/836b88249365ea8745ca839a7dc3a3a4a77732e6))
|
|
24
|
+
* add new tests ([d0e6833](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/d0e68335ce13827f74ed1be5b115f7351beebd47))
|
|
25
|
+
* adding a test page ([d4c8a8c](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/d4c8a8caaba7f4e5003606860babd9e50c6ed99a))
|
|
26
|
+
* adding comfortable cache testing tool on homepage ([340d5cb](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/340d5cbc929ea8dcdbef2a949e1656d014d1f3bb))
|
|
27
|
+
* adding nextjs unit tests ([368ec75](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/368ec755a8532a52526e3364cc02f64b7d4245fa))
|
|
28
|
+
* changed ([8501a4e](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/8501a4ee963975f32661789e31281785cf01519a))
|
|
29
|
+
* changed hook ([92f9d3c](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/92f9d3c4b8d9afd6bbbb9cc3a69138823f4d4f87))
|
|
30
|
+
* changed hook ([6b32f0a](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/6b32f0abcda935046e61242ba633728bcf23a460))
|
|
31
|
+
* extend and fix caching + chore: update readme ([7ef38a8](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/7ef38a8ed2a20957cc78ffa213be3cb334736b19))
|
|
32
|
+
* extend tests ([db9bb85](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/db9bb85e398a7d6e1ba522b990de7e5e241b54b6))
|
|
33
|
+
* improve flaky ms sync delay ([6655884](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/665588474a09f1eb4f4683d2e107ec8b5b36b39a))
|
|
34
|
+
* improve readme ([926493a](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/926493a198d15e32e5e4b5c619375df85c646f1c))
|
|
35
|
+
* improve tests ([3fcfadf](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/3fcfadf49389fe8a7218417fb79ec74445e76cb7))
|
|
36
|
+
* remove unnecessary revalidatedTagsMap ([7b5c313](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/7b5c313e91b5157f113085be75dceba8013c0e81))
|
|
37
|
+
* test is running ([6091471](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/6091471a12f954e3da4bd94db0929b0bd2cfd701))
|
|
38
|
+
* tests ([bd6904e](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/bd6904e94a43cfac183a5ec86cbbea0f4e40a816))
|
|
39
|
+
* tests 2 ([974c952](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/974c952587a9d330934f49b26db84c037b3695f5))
|
|
40
|
+
* update CI with pnpm ([c1b0b33](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/c1b0b33417b416bd7755b6b2f43d0b9bea5c7690))
|
|
41
|
+
* update CI with pnpm ([d850377](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/d85037706876dcb036bb6f952a48937c3e96cba3))
|
|
42
|
+
* update CI with pnpm 10 ([c559936](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/c5599361f15c4c82fa999e16a48fcf78e53355a6))
|
|
43
|
+
* update CI with pnpm 11 ([f83708f](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/f83708f76c3924b8b80dd612965dc49a95d7e18c))
|
|
44
|
+
* update CI with pnpm 2 ([235f0fc](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/235f0fc8cb35dbe532091d8f545791b8dd05b6be))
|
|
45
|
+
* update CI with pnpm 2 ([cb9624e](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/cb9624e900f555bc07c734ff152c4f4a93000e54))
|
|
46
|
+
* update CI with pnpm 3 ([72c25ce](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/72c25cefa2aea6767d5a71b5470955a18f9036b9))
|
|
47
|
+
* update CI with pnpm 4 ([fff355a](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/fff355a8e047d766121d255881d891fa7c5a754e))
|
|
48
|
+
* update CI with pnpm 4 ([facd58b](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/facd58bdefd530d70fdbb2f7d48c9962ca2195e5))
|
|
49
|
+
* update CI with pnpm 5 ([03d9d90](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/03d9d906e852927496a58504dd9c7448e31878a1))
|
|
50
|
+
* update CI with pnpm 6 ([b5e7066](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/b5e7066ec840edfa7d6df6c6ab978c61b356c8b5))
|
|
51
|
+
* update CI with pnpm 8 ([20c3a5b](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/20c3a5be9d465537240cce6ac5346554667cda68))
|
|
52
|
+
* update CI with pnpm 9 ([5160fd3](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/5160fd3e1a010a5b52b99d0e2e0de3b9035d1e88))
|
|
53
|
+
* update docs and tests ([7a46c21](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/7a46c21346d878df88283071551f06a34d71eb9a))
|
|
54
|
+
|
|
55
|
+
## [1.2.1](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.2.0...v1.2.1) (2025-03-28)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
### Bug Fixes
|
|
59
|
+
|
|
60
|
+
* imports ([41f0cf9](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/41f0cf97506c134f8dfb37fab746cc9c066c515f))
|
|
61
|
+
|
|
1
62
|
# [1.2.0](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.1.3...v1.2.0) (2025-03-28)
|
|
2
63
|
|
|
3
64
|
|
package/README.md
CHANGED
|
@@ -1,50 +1,125 @@
|
|
|
1
1
|
# nextjs-turbo-redis-cache
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@trieb.work/nextjs-turbo-redis-cache)
|
|
4
|
+
|
|
5
|
+
The ultimate Redis caching solution for Next.js. Built for production-ready, large-scale projects, it delivers unparalleled performance and efficiency with features tailored for high-traffic applications. This package has been created after extensibly testing the @neshca package and finding several major issues with it.
|
|
4
6
|
|
|
5
7
|
Key Features:
|
|
6
8
|
|
|
7
|
-
- _Turbocharged Storage_: Avoids base64 encoding to save ~33% of storage space compared to traditional implementations.
|
|
8
9
|
- _Batch Tag Invalidation_: Groups and optimizes delete operations for minimal Redis stress.
|
|
9
10
|
- _Request Deduplication_: Prevents redundant Redis get calls, ensuring faster response times.
|
|
10
|
-
- _In-Memory Caching_: Includes local caching for Redis get operations to reduce latency further.
|
|
11
|
+
- _In-Memory Caching_: Includes local caching for Redis get operations to reduce latency further. Don't request redis for the same key multiple times.
|
|
11
12
|
- _Efficient Tag Management_: in-memory tags map for lightning-fast revalidate operations with minimal Redis overhead.
|
|
12
13
|
- _Intelligent Key-Space Notifications_: Automatic update of in-memory tags map for expired or evicted keys.
|
|
13
14
|
|
|
14
|
-
##
|
|
15
|
+
## Compatibility
|
|
16
|
+
|
|
17
|
+
This package is compatible with Next.js 15.0.0 and above while using App Router. It is not compatible with Next.js 14.x. or if you are using Pages Router.
|
|
18
|
+
Redis need to have Redis Version 2.8.0 or higher and have to be configured with `notify-keyspace-events` to be able to use the key-space notifications feature.
|
|
19
|
+
|
|
20
|
+
Currently PPR, unstable_cacheLife and unstable_cacheTag are not tested. Use these operations with caution and your own risk.
|
|
21
|
+
|
|
22
|
+
## Available Options (needs Option B of getting started)
|
|
15
23
|
|
|
16
|
-
|
|
24
|
+
| Option | Description | Default Value |
|
|
25
|
+
| ---------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | --- | ----------------- |
|
|
26
|
+
| database | Redis database number to use. Uses DB 0 for production, DB 1 otherwise | `process.env.VERCEL_ENV === 'production' ? 0 : 1` |
|
|
27
|
+
| keyPrefix | Prefix added to all Redis keys | `process.env.VERCEL_URL | | 'UNDEFINED*URL*'` |
|
|
28
|
+
| sharedTagsKey | Key used to store shared tags hash map in Redis | `'__sharedTags__'` |
|
|
29
|
+
| timeoutMs | Timeout in milliseconds for Redis operations | `5000` |
|
|
30
|
+
| revalidateTagQuerySize | Number of entries to query in one batch during full sync of shared tags hash map | `250` |
|
|
31
|
+
| avgResyncIntervalMs | Average interval in milliseconds between tag map full re-syncs | `3600000` (1 hour) |
|
|
32
|
+
| redisGetDeduplication | Enable deduplication of Redis get requests via internal in-memory cache. | `true` |
|
|
33
|
+
| inMemoryCachingTime | Time in milliseconds to cache Redis get results in memory. Set this to 0 to disable in-memory caching completely. | `10000` |
|
|
34
|
+
| defaultStaleAge | Default stale age in seconds for cached items | `1209600` (14 days) |
|
|
35
|
+
| estimateExpireAge | Function to calculate expire age (redis TTL value) from stale age | Production: `staleAge * 2`<br>Other: `staleAge * 1.2` |
|
|
17
36
|
|
|
18
37
|
## Getting started
|
|
19
38
|
|
|
39
|
+
### Enable redis key-space notifications for Expire and Evict events
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
redis-cli -h localhost config set notify-keyspace-events Exe
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Install package
|
|
46
|
+
|
|
20
47
|
```bash
|
|
21
48
|
pnpm install @trieb.work/nextjs-turbo-redis-cache
|
|
22
49
|
```
|
|
23
50
|
|
|
51
|
+
### Setup environment variables in your project/deployment
|
|
52
|
+
|
|
53
|
+
REDISHOST and REDISPORT environment variables are required.
|
|
54
|
+
VERCEL_URL, VERCEL_ENV are optional. VERCEL_URL is used to create a key prefix for the redis keys. VERCEL_ENV is used to determine the database to use. Only VERCEL_ENV=production will show up in DB 0 (redis default db). All other values of VERCEL_ENV will use DB 1, use `redis-cli -n 1` to connect to different DB 1. This is another protection feature to avoid that different environments (e.g. staging and production) will overwrite each other.
|
|
55
|
+
Furthermore there exists the DEBUG_CACHE_HANDLER environment variable to enable debug logging of the caching handler once it is set to true.
|
|
56
|
+
|
|
57
|
+
### Option A: minimum implementation with default options
|
|
58
|
+
|
|
24
59
|
extend `next.config.js` with:
|
|
60
|
+
|
|
25
61
|
```
|
|
26
62
|
const nextConfig = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// maxMemoryCacheSize, // deprecated
|
|
32
|
-
// database = process.env.VERCEL_ENV === 'production' ? 0 : 1,
|
|
33
|
-
// keyPrefix = process.env.VERCEL_URL || 'UNDEFINED_URL_',
|
|
34
|
-
// sharedTagsKey = '__sharedTags__',
|
|
35
|
-
// timeoutMs = 5000,
|
|
36
|
-
// revalidateTagQuerySize = 250,
|
|
37
|
-
// avgResyncIntervalMs = 60 * 60 * 1000,
|
|
38
|
-
// redisGetDeduplication = true,
|
|
39
|
-
// inMemoryCachingTime = 10_000,
|
|
40
|
-
// defaultStaleAge = 60 * 60 * 24 * 14,
|
|
41
|
-
// estimateExpireAge = (staleAge) =>
|
|
42
|
-
// process.env.VERCEL_ENV === 'preview' ? staleAge * 1.2 : staleAge * 2,
|
|
43
|
-
})
|
|
44
|
-
: undefined,
|
|
63
|
+
...
|
|
64
|
+
cacheHandler: require.resolve("@trieb.work/nextjs-turbo-redis-cache")
|
|
65
|
+
...
|
|
66
|
+
}
|
|
45
67
|
```
|
|
46
68
|
|
|
47
|
-
|
|
69
|
+
### Option B: create a wrapper file to change options
|
|
70
|
+
|
|
71
|
+
create new file `customized-cache-handler.js` in your project root and add the following code:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
const { RedisStringsHandler } = require('@trieb.work/nextjs-turbo-redis-cache');
|
|
75
|
+
|
|
76
|
+
let cachedHandler;
|
|
77
|
+
|
|
78
|
+
module.exports = class CustomizedCacheHandler {
|
|
79
|
+
constructor() {
|
|
80
|
+
if (!cachedHandler) {
|
|
81
|
+
cachedHandler = new RedisStringsHandler({
|
|
82
|
+
database: 0,
|
|
83
|
+
keyPrefix: 'test',
|
|
84
|
+
timeoutMs: 2_000,
|
|
85
|
+
revalidateTagQuerySize: 500,
|
|
86
|
+
sharedTagsKey: '__sharedTags__',
|
|
87
|
+
avgResyncIntervalMs: 10_000 * 60,
|
|
88
|
+
redisGetDeduplication: false,
|
|
89
|
+
inMemoryCachingTime: 0,
|
|
90
|
+
defaultStaleAge: 1209600,
|
|
91
|
+
estimateExpireAge: (staleAge) => staleAge * 2,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
get(...args) {
|
|
96
|
+
return cachedHandler.get(...args);
|
|
97
|
+
}
|
|
98
|
+
set(...args) {
|
|
99
|
+
return cachedHandler.set(...args);
|
|
100
|
+
}
|
|
101
|
+
revalidateTag(...args) {
|
|
102
|
+
return cachedHandler.revalidateTag(...args);
|
|
103
|
+
}
|
|
104
|
+
resetRequestCache(...args) {
|
|
105
|
+
return cachedHandler.resetRequestCache(...args);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
extend `next.config.js` with:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
const nextConfig = {
|
|
114
|
+
...
|
|
115
|
+
cacheHandler: require.resolve("./customized-cache-handler")
|
|
116
|
+
...
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
A working example of above can be found in the `test/integration/next-app-customized` folder.
|
|
121
|
+
|
|
122
|
+
## Consistency of Redis and this caching implementation
|
|
48
123
|
|
|
49
124
|
To understand consistency levels of this caching implementation we first have to understand the consistency of redis itself:
|
|
50
125
|
Redis executes commands in a single-threaded manner. This ensures that all operations are processed sequentially, so clients always see a consistent view of the data.
|
|
@@ -72,23 +147,63 @@ If using local in-memory caching (Enabled by RedisStringsHandler option inMemory
|
|
|
72
147
|
|
|
73
148
|
Since all caching calls in one api/page/server action request is always served by the same instance this problem will not occur inside a single request but rather in a combination of multiple parallel requests. The probability that this will occur for a single user during a request sequence is very low, since typically a single user will not make the follow up request during this small time window of typically 50ms. To further mitigate the Problem and increase performance (increase local in-memory cache hit ratio) make sure that your load balancer will always serve one user to the same instance (sticky sessions).
|
|
74
149
|
|
|
150
|
+
By accepting and tolerating this eventual consistency, the performance of the caching handler is significantly increased.
|
|
151
|
+
|
|
75
152
|
## Development
|
|
76
153
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
154
|
+
1. Run `pnpm install` to install the dependencies
|
|
155
|
+
1. Run `pnpm build` to build the project
|
|
156
|
+
1. Run `pnpm lint` to lint the project
|
|
157
|
+
1. Run `pnpm format` to format the project
|
|
158
|
+
1. Run `pnpm run-dev-server` to test and develop the caching handler using the nextjs integration test project
|
|
159
|
+
1. If you make changes to the cache handler, you need to stop `pnpm run-dev-server` and run it again.
|
|
160
|
+
|
|
161
|
+
## Testing
|
|
162
|
+
|
|
163
|
+
To run all tests you can use the following command:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
pnpm test
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Unit tests
|
|
170
|
+
|
|
171
|
+
To run unit tests you can use the following command:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
pnpm test:unit
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Integration tests
|
|
178
|
+
|
|
179
|
+
To run integration tests you can use the following command:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
pnpm test:integration
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The integration tests will start a Next.js server and test the caching handler. You can modify testing behavior by setting the following environment variables:
|
|
186
|
+
|
|
187
|
+
- SKIP_BUILD: If set to true, the integration tests will not build the Next.js app. Therefore the nextjs app needs to be built before running the tests. Or you execute the test once without skip build and the re-execute `pnpm test:integration` with skip build set to true.
|
|
188
|
+
- SKIP_OPTIONAL_LONG_RUNNER_TESTS: If set to true, the integration tests will not run the optional long runner tests.
|
|
189
|
+
- DEBUG_INTEGRATION: If set to true, the integration tests will print debug information of the test itself to the console.
|
|
190
|
+
|
|
191
|
+
Integration tests may have dependencies between test cases, so individual test failures should be evaluated in the context of the full test suite rather than in isolation.
|
|
192
|
+
|
|
193
|
+
## Some words on nextjs caching internals
|
|
194
|
+
|
|
195
|
+
Nextjs will use different caching objects for different pages and api routes. Currently supported are kind: APP_ROUTE and APP_PAGE.
|
|
196
|
+
|
|
197
|
+
app/<segment>/route.ts files will request using the APP_ROUTE kind.
|
|
198
|
+
app/<segment>/page.tsx files will request using the APP_PAGE kind.
|
|
199
|
+
/favicon.ico file will request using the APP_ROUTE kind.
|
|
200
|
+
|
|
201
|
+
Fetch requests (inside app route or page) will request using the FETCH kind.
|
|
85
202
|
|
|
86
203
|
## License
|
|
87
204
|
|
|
88
205
|
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
89
206
|
|
|
90
|
-
|
|
91
207
|
## Sponsor
|
|
92
208
|
|
|
93
209
|
This project is created and maintained by the Next.js & Payload CMS agency [trieb.work](https://trieb.work)
|
|
94
|
-
|
package/dist/index.d.mts
CHANGED
|
@@ -1,21 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
type CacheEntry = {
|
|
2
|
+
value: unknown;
|
|
3
|
+
lastModified: number;
|
|
4
|
+
tags: string[];
|
|
5
|
+
};
|
|
6
6
|
type CreateRedisStringsHandlerOptions = {
|
|
7
|
+
/** Redis database number to use. Uses DB 0 for production, DB 1 otherwise
|
|
8
|
+
* @default process.env.VERCEL_ENV === 'production' ? 0 : 1
|
|
9
|
+
*/
|
|
7
10
|
database?: number;
|
|
11
|
+
/** Prefix added to all Redis keys
|
|
12
|
+
* @default process.env.VERCEL_URL || 'UNDEFINED_URL_'
|
|
13
|
+
*/
|
|
8
14
|
keyPrefix?: string;
|
|
15
|
+
/** Timeout in milliseconds for Redis operations
|
|
16
|
+
* @default 5000
|
|
17
|
+
*/
|
|
9
18
|
timeoutMs?: number;
|
|
19
|
+
/** Number of entries to query in one batch during full sync of shared tags hash map
|
|
20
|
+
* @default 250
|
|
21
|
+
*/
|
|
10
22
|
revalidateTagQuerySize?: number;
|
|
23
|
+
/** Key used to store shared tags hash map in Redis
|
|
24
|
+
* @default '__sharedTags__'
|
|
25
|
+
*/
|
|
11
26
|
sharedTagsKey?: string;
|
|
27
|
+
/** Average interval in milliseconds between tag map full re-syncs
|
|
28
|
+
* @default 3600000 (1 hour)
|
|
29
|
+
*/
|
|
12
30
|
avgResyncIntervalMs?: number;
|
|
31
|
+
/** Enable deduplication of Redis get requests via internal in-memory cache
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
13
34
|
redisGetDeduplication?: boolean;
|
|
35
|
+
/** Time in milliseconds to cache Redis get results in memory. Set this to 0 to disable in-memory caching completely
|
|
36
|
+
* @default 10000
|
|
37
|
+
*/
|
|
14
38
|
inMemoryCachingTime?: number;
|
|
39
|
+
/** Default stale age in seconds for cached items
|
|
40
|
+
* @default 1209600 (14 days)
|
|
41
|
+
*/
|
|
15
42
|
defaultStaleAge?: number;
|
|
43
|
+
/** Function to calculate expire age (redis TTL value) from stale age
|
|
44
|
+
* @default Production: staleAge * 2, Other: staleAge * 1.2
|
|
45
|
+
*/
|
|
16
46
|
estimateExpireAge?: (staleAge: number) => number;
|
|
17
47
|
};
|
|
18
|
-
declare class RedisStringsHandler
|
|
48
|
+
declare class RedisStringsHandler {
|
|
19
49
|
private client;
|
|
20
50
|
private sharedTagsMap;
|
|
21
51
|
private revalidatedTagsMap;
|
|
@@ -30,23 +60,65 @@ declare class RedisStringsHandler implements CacheHandler {
|
|
|
30
60
|
private defaultStaleAge;
|
|
31
61
|
private estimateExpireAge;
|
|
32
62
|
constructor({ database, keyPrefix, sharedTagsKey, timeoutMs, revalidateTagQuerySize, avgResyncIntervalMs, redisGetDeduplication, inMemoryCachingTime, defaultStaleAge, estimateExpireAge, }: CreateRedisStringsHandlerOptions);
|
|
33
|
-
resetRequestCache(
|
|
63
|
+
resetRequestCache(): void;
|
|
34
64
|
private assertClientIsReady;
|
|
35
|
-
get(key:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
65
|
+
get(key: string, ctx: {
|
|
66
|
+
kind: 'APP_ROUTE' | 'APP_PAGE';
|
|
67
|
+
isRoutePPREnabled: boolean;
|
|
68
|
+
isFallback: boolean;
|
|
69
|
+
} | {
|
|
70
|
+
kind: 'FETCH';
|
|
71
|
+
revalidate: number;
|
|
72
|
+
fetchUrl: string;
|
|
73
|
+
fetchIdx: number;
|
|
74
|
+
tags: string[];
|
|
75
|
+
softTags: string[];
|
|
76
|
+
isFallback: boolean;
|
|
77
|
+
}): Promise<CacheEntry | null>;
|
|
78
|
+
set(key: string, data: {
|
|
79
|
+
kind: 'APP_PAGE';
|
|
80
|
+
status: number;
|
|
81
|
+
headers: {
|
|
82
|
+
'x-nextjs-stale-time': string;
|
|
83
|
+
'x-next-cache-tags': string;
|
|
84
|
+
};
|
|
85
|
+
html: string;
|
|
86
|
+
rscData: Buffer;
|
|
87
|
+
segmentData: unknown;
|
|
88
|
+
postboned: unknown;
|
|
89
|
+
} | {
|
|
90
|
+
kind: 'APP_ROUTE';
|
|
91
|
+
status: number;
|
|
92
|
+
headers: {
|
|
93
|
+
'cache-control'?: string;
|
|
94
|
+
'x-nextjs-stale-time': string;
|
|
95
|
+
'x-next-cache-tags': string;
|
|
96
|
+
};
|
|
97
|
+
body: Buffer;
|
|
98
|
+
} | {
|
|
99
|
+
kind: 'FETCH';
|
|
100
|
+
data: {
|
|
101
|
+
headers: Record<string, string>;
|
|
102
|
+
body: string;
|
|
103
|
+
status: number;
|
|
104
|
+
url: string;
|
|
105
|
+
};
|
|
106
|
+
revalidate: number | false;
|
|
107
|
+
}, ctx: {
|
|
108
|
+
revalidate: number | false;
|
|
109
|
+
isRoutePPREnabled: boolean;
|
|
110
|
+
isFallback: boolean;
|
|
111
|
+
tags?: string[];
|
|
112
|
+
}): Promise<void>;
|
|
113
|
+
revalidateTag(tagOrTags: string | string[], ...rest: any[]): Promise<void>;
|
|
42
114
|
}
|
|
43
115
|
|
|
44
|
-
declare class CachedHandler
|
|
116
|
+
declare class CachedHandler {
|
|
45
117
|
constructor(options: CreateRedisStringsHandlerOptions);
|
|
46
|
-
get(...args: Parameters<RedisStringsHandler[
|
|
47
|
-
set(...args: Parameters<RedisStringsHandler[
|
|
48
|
-
revalidateTag(...args: Parameters<RedisStringsHandler[
|
|
49
|
-
resetRequestCache(...args: Parameters<RedisStringsHandler[
|
|
118
|
+
get(...args: Parameters<RedisStringsHandler['get']>): ReturnType<RedisStringsHandler['get']>;
|
|
119
|
+
set(...args: Parameters<RedisStringsHandler['set']>): ReturnType<RedisStringsHandler['set']>;
|
|
120
|
+
revalidateTag(...args: Parameters<RedisStringsHandler['revalidateTag']>): ReturnType<RedisStringsHandler['revalidateTag']>;
|
|
121
|
+
resetRequestCache(...args: Parameters<RedisStringsHandler['resetRequestCache']>): ReturnType<RedisStringsHandler['resetRequestCache']>;
|
|
50
122
|
}
|
|
51
123
|
|
|
52
|
-
export { CachedHandler as default };
|
|
124
|
+
export { RedisStringsHandler, CachedHandler as default };
|