cdk-nextjs 0.6.2 → 0.7.1
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/.jsii +2404 -2723
- package/.jsii.tabl.json +1 -1
- package/API.md +1681 -1930
- package/CLAUDE.md +2 -1
- package/README.md +429 -130
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
- package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
- package/docs/adapter-runtime.md +185 -0
- package/docs/breaking-changes.md +667 -4
- package/docs/caching-guide.md +156 -112
- package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
- package/docs/development-guide.md +1 -1
- package/docs/harness-coverage.md +598 -0
- package/docs/init-cache-deployment.md +32 -1
- package/docs/next-build-output-guide.md +30 -20
- package/examples/README.md +5 -1
- package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
- package/lib/adapter/__fixtures__/app-playground.json +4917 -0
- package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
- package/lib/adapter/adapter.mjs +1551 -185
- package/lib/adapter/adapter.test.js +106 -0
- package/lib/adapter/aws-cache-store.d.ts +489 -0
- package/lib/adapter/aws-cache-store.js +1004 -0
- package/lib/adapter/aws-cache-store.test.d.ts +1 -0
- package/lib/adapter/aws-cache-store.test.js +361 -0
- package/lib/adapter/build-outputs.d.ts +80 -0
- package/lib/adapter/build-outputs.js +857 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +863 -0
- package/lib/adapter/cache-handler.d.ts +9 -2
- package/lib/adapter/cache-handler.js +72 -96
- package/lib/adapter/cache-handler.mjs +18956 -17774
- package/lib/adapter/cache-handler.test.js +263 -31
- package/lib/adapter/cache-kinds.d.ts +32 -0
- package/lib/adapter/cache-kinds.js +35 -0
- package/lib/adapter/cache-kinds.test.d.ts +1 -0
- package/lib/adapter/cache-kinds.test.js +69 -0
- package/lib/adapter/cache-utils.d.ts +90 -0
- package/lib/adapter/cache-utils.js +199 -4
- package/lib/adapter/cache-utils.test.d.ts +1 -0
- package/lib/adapter/cache-utils.test.js +179 -0
- package/lib/adapter/function-groups.d.ts +215 -0
- package/lib/adapter/function-groups.js +1099 -0
- package/lib/adapter/function-groups.test.d.ts +1 -0
- package/lib/adapter/function-groups.test.js +743 -0
- package/lib/adapter/init-cache.d.ts +6 -0
- package/lib/adapter/init-cache.js +245 -0
- package/lib/adapter/init-cache.test.d.ts +1 -0
- package/lib/adapter/init-cache.test.js +137 -0
- package/lib/adapter/local-file-cache-handler.d.ts +23 -0
- package/lib/adapter/local-file-cache-handler.js +52 -1
- package/lib/adapter/memory-cache-handler.d.ts +26 -17
- package/lib/adapter/memory-cache-handler.js +32 -50
- package/lib/adapter/memory-cache-handler.test.js +105 -85
- package/lib/adapter/s3-cache-handler.d.ts +179 -40
- package/lib/adapter/s3-cache-handler.js +807 -277
- package/lib/adapter/s3-cache-handler.test.js +1186 -31
- package/lib/adapter/use-cache-common.d.ts +90 -0
- package/lib/adapter/use-cache-common.js +250 -0
- package/lib/adapter/use-cache-common.test.d.ts +1 -0
- package/lib/adapter/use-cache-common.test.js +646 -0
- package/lib/adapter/use-cache-default-handler.d.ts +24 -0
- package/lib/adapter/use-cache-default-handler.js +90 -0
- package/lib/adapter/use-cache-default-handler.mjs +38645 -0
- package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
- package/lib/adapter/use-cache-handlers.test.js +349 -0
- package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
- package/lib/adapter/use-cache-remote-handler.js +186 -0
- package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
- package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
- package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
- package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
- package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
- package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +8 -0
- package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
- package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
- package/lib/index.d.ts +6 -7
- package/lib/index.js +2 -4
- package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
- package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
- package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
- package/lib/lambdas/post-deploy/prune-s3.js +41 -12
- package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
- package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
- package/lib/nextjs-api.d.ts +102 -18
- package/lib/nextjs-api.js +338 -38
- package/lib/nextjs-api.test.js +537 -1
- package/lib/nextjs-build/global-containers.Dockerfile +15 -10
- package/lib/nextjs-build/nextjs-build.d.ts +339 -63
- package/lib/nextjs-build/nextjs-build.js +684 -327
- package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
- package/lib/nextjs-build/nextjs-build.test.js +412 -0
- package/lib/nextjs-build/patch-fetch.js +1 -1
- package/lib/nextjs-build/patch-fetch.test.js +166 -11
- package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
- package/lib/nextjs-cache.d.ts +82 -4
- package/lib/nextjs-cache.js +186 -10
- package/lib/nextjs-cache.test.js +176 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
- package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
- package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
- package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
- package/lib/nextjs-compute/nextjs-containers.js +57 -20
- package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
- package/lib/nextjs-compute/nextjs-functions.js +113 -67
- package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
- package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
- package/lib/nextjs-distribution.d.ts +194 -23
- package/lib/nextjs-distribution.js +535 -62
- package/lib/nextjs-distribution.test.d.ts +1 -0
- package/lib/nextjs-distribution.test.js +697 -0
- package/lib/nextjs-post-deploy.d.ts +13 -5
- package/lib/nextjs-post-deploy.js +13 -10
- package/lib/nextjs-post-deploy.test.d.ts +1 -0
- package/lib/nextjs-post-deploy.test.js +34 -0
- package/lib/nextjs-static-assets.d.ts +17 -4
- package/lib/nextjs-static-assets.js +22 -5
- package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
- package/lib/root-constructs/nextjs-base-construct.js +139 -47
- package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
- package/lib/root-constructs/nextjs-global-containers.js +20 -71
- package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
- package/lib/root-constructs/nextjs-global-functions.js +52 -70
- package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
- package/lib/root-constructs/nextjs-regional-containers.js +8 -15
- package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
- package/lib/root-constructs/nextjs-regional-functions.js +8 -26
- package/lib/runtime/api-gateway-path.d.ts +34 -0
- package/lib/runtime/api-gateway-path.js +71 -0
- package/lib/runtime/api-gateway-path.test.d.ts +1 -0
- package/lib/runtime/api-gateway-path.test.js +65 -0
- package/lib/runtime/case-redirect.d.ts +22 -0
- package/lib/runtime/case-redirect.js +63 -0
- package/lib/runtime/case-redirect.test.d.ts +1 -0
- package/lib/runtime/case-redirect.test.js +32 -0
- package/lib/runtime/core.d.ts +234 -0
- package/lib/runtime/core.js +1216 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1686 -0
- package/lib/runtime/deployment-root.d.ts +13 -0
- package/lib/runtime/deployment-root.js +29 -0
- package/lib/runtime/dispatch.d.ts +331 -0
- package/lib/runtime/dispatch.js +751 -0
- package/lib/runtime/dispatch.test.d.ts +1 -0
- package/lib/runtime/dispatch.test.js +853 -0
- package/lib/runtime/entrypoints.d.ts +57 -0
- package/lib/runtime/entrypoints.js +115 -0
- package/lib/runtime/http/abort-signal.d.ts +6 -0
- package/lib/runtime/http/abort-signal.js +19 -0
- package/lib/runtime/http/abort-signal.test.d.ts +1 -0
- package/lib/runtime/http/abort-signal.test.js +49 -0
- package/lib/runtime/http/node-server.d.ts +38 -0
- package/lib/runtime/http/node-server.js +99 -0
- package/lib/runtime/http/node-server.test.d.ts +1 -0
- package/lib/runtime/http/node-server.test.js +96 -0
- package/lib/runtime/http/node-sink.d.ts +16 -0
- package/lib/runtime/http/node-sink.js +48 -0
- package/lib/runtime/http/node-sink.test.d.ts +1 -0
- package/lib/runtime/http/node-sink.test.js +66 -0
- package/lib/runtime/http/request.d.ts +62 -0
- package/lib/runtime/http/request.js +134 -0
- package/lib/runtime/http/request.test.d.ts +1 -0
- package/lib/runtime/http/request.test.js +103 -0
- package/lib/runtime/http/response.d.ts +77 -0
- package/lib/runtime/http/response.js +229 -0
- package/lib/runtime/http/response.test.d.ts +1 -0
- package/lib/runtime/http/response.test.js +178 -0
- package/lib/runtime/http/sink.d.ts +73 -0
- package/lib/runtime/http/sink.js +188 -0
- package/lib/runtime/http/sink.test.d.ts +1 -0
- package/lib/runtime/http/sink.test.js +257 -0
- package/lib/runtime/image-utils.d.ts +78 -0
- package/lib/runtime/image-utils.js +129 -0
- package/lib/runtime/image-utils.test.d.ts +1 -0
- package/lib/runtime/image-utils.test.js +237 -0
- package/lib/runtime/image.d.ts +76 -0
- package/lib/runtime/image.js +296 -0
- package/lib/runtime/image.test.d.ts +1 -0
- package/lib/runtime/image.test.js +405 -0
- package/lib/runtime/lambda-event.d.ts +4 -0
- package/lib/runtime/lambda-event.js +113 -0
- package/lib/runtime/lambda-event.test.d.ts +1 -0
- package/lib/runtime/lambda-event.test.js +119 -0
- package/lib/runtime/lambda.mjs +41600 -0
- package/lib/runtime/load-module.d.ts +8 -0
- package/lib/runtime/load-module.js +35 -0
- package/lib/runtime/manifest.d.ts +215 -0
- package/lib/runtime/manifest.js +118 -0
- package/lib/runtime/middleware.d.ts +43 -0
- package/lib/runtime/middleware.js +113 -0
- package/lib/runtime/middleware.test.d.ts +1 -0
- package/lib/runtime/middleware.test.js +259 -0
- package/lib/runtime/next-modules.d.ts +71 -0
- package/lib/runtime/next-modules.js +144 -0
- package/lib/runtime/next-modules.test.d.ts +1 -0
- package/lib/runtime/next-modules.test.js +34 -0
- package/lib/runtime/public-files.d.ts +32 -0
- package/lib/runtime/public-files.js +117 -0
- package/lib/runtime/public-files.test.d.ts +1 -0
- package/lib/runtime/public-files.test.js +97 -0
- package/lib/runtime/server.mjs +41593 -0
- package/lib/runtime/static-files.d.ts +50 -0
- package/lib/runtime/static-files.js +266 -0
- package/lib/runtime/static-files.test.d.ts +1 -0
- package/lib/runtime/static-files.test.js +118 -0
- package/lib/runtime/util.d.ts +28 -0
- package/lib/runtime/util.js +79 -0
- package/lib/utils/base-path.d.ts +106 -13
- package/lib/utils/base-path.js +254 -41
- package/lib/utils/base-path.test.js +219 -51
- package/lib/utils/get-architecture.d.ts +7 -8
- package/lib/utils/get-architecture.js +12 -13
- package/lib/utils/zip-directory.d.ts +14 -0
- package/lib/utils/zip-directory.js +121 -0
- package/lib/utils/zip-directory.test.d.ts +1 -0
- package/lib/utils/zip-directory.test.js +99 -0
- package/package.json +22 -3
- package/scripts/capture-adapter-fixture.mjs +325 -0
- package/scripts/e2e-deploy.sh +398 -0
- package/scripts/e2e-harness/README.md +707 -0
- package/scripts/e2e-harness/app.js +370 -0
- package/scripts/e2e-harness/common.sh +249 -0
- package/scripts/e2e-harness/screen.mjs +302 -0
- package/scripts/e2e-harness/stage-proxy.mjs +145 -0
- package/scripts/e2e-harness/type-filters.mjs +47 -0
- package/scripts/e2e-logs.sh +75 -0
- package/scripts/e2e-offline.sh +91 -0
- package/scripts/e2e-sweep.sh +370 -0
- package/scripts/e2e-warm.sh +114 -0
- package/scripts/zero-config-build.mjs +418 -0
- package/docs/1k-concurrent-users-executions.png +0 -0
- package/docs/plans/adapter-runtime-release.md +0 -362
- package/docs/plans/phase-0-image-function-opt-in.md +0 -295
- package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
- package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
- package/lib/image-optimization/handler-utils.d.ts +0 -34
- package/lib/image-optimization/handler-utils.js +0 -83
- package/lib/image-optimization/handler-utils.test.js +0 -178
- package/lib/nextjs-build/functions.Dockerfile +0 -31
- package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
- package/lib/nextjs-compute/nextjs-image-function.js +0 -59
- package/lib/utils/experimental-flags.d.ts +0 -24
- package/lib/utils/experimental-flags.js +0 -30
- /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
package/docs/caching-guide.md
CHANGED
|
@@ -8,7 +8,7 @@ Next.js uses multiple caching layers to improve performance and reduce costs. cd
|
|
|
8
8
|
|
|
9
9
|
## Next.js Caching Mechanisms
|
|
10
10
|
|
|
11
|
-
Next.js uses multiple caching layers
|
|
11
|
+
Next.js uses multiple caching layers. Those the incremental cache stores each have a `CachedRouteKind`, recorded in the entry itself:
|
|
12
12
|
|
|
13
13
|
### 1. Request Memoization
|
|
14
14
|
|
|
@@ -25,7 +25,7 @@ Next.js uses multiple caching layers, each with a specific `CachedRouteKind` tha
|
|
|
25
25
|
**Kind**: `FETCH`
|
|
26
26
|
**cdk-nextjs Implementation**:
|
|
27
27
|
|
|
28
|
-
- **Storage**: S3 bucket at
|
|
28
|
+
- **Storage**: S3 bucket at `{buildId}/{cache-key}.json`
|
|
29
29
|
- **Custom Cache Handler**: S3CacheHandler manages read/write operations
|
|
30
30
|
- **Revalidation**: DynamoDB table tracks tag-based revalidation metadata
|
|
31
31
|
|
|
@@ -39,7 +39,8 @@ Next.js uses multiple caching layers, each with a specific `CachedRouteKind` tha
|
|
|
39
39
|
- `APP_PAGE` - App Router pages
|
|
40
40
|
- `APP_ROUTE` - App Router API routes
|
|
41
41
|
- `PAGES` - Pages Router pages
|
|
42
|
-
|
|
42
|
+
|
|
43
|
+
**cdk-nextjs Implementation**:
|
|
43
44
|
|
|
44
45
|
- **ISR Support**: Files updated during Incremental Static Regeneration
|
|
45
46
|
- **Revalidation**: Tag-based invalidation via DynamoDB tracking
|
|
@@ -52,15 +53,15 @@ Next.js uses multiple caching layers, each with a specific `CachedRouteKind` tha
|
|
|
52
53
|
**Kind**: `IMAGE`
|
|
53
54
|
**cdk-nextjs Implementation**:
|
|
54
55
|
|
|
55
|
-
- **Storage**: S3 bucket at
|
|
56
|
+
- **Storage**: S3 bucket at `{buildId}/{cache-key}.json`
|
|
56
57
|
- **Optimization**: Cached resized, format-converted images
|
|
57
58
|
- **Revalidation**: Time-based or on-demand revalidation
|
|
58
59
|
|
|
59
|
-
This applies on every `NextjsType
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
This applies on every `NextjsType`: `_next/image` is handled inside cdk-nextjs's
|
|
61
|
+
runtime, which runs Next.js's own image optimizer and image cache over the cache
|
|
62
|
+
handler, so a variant is optimized once and then served with
|
|
63
|
+
`X-Nextjs-Cache: HIT`. Behind CloudFront (the Global types) that makes an edge
|
|
64
|
+
miss an S3 read rather than a second optimization.
|
|
64
65
|
|
|
65
66
|
### 5. Redirect Cache (REDIRECT)
|
|
66
67
|
|
|
@@ -70,7 +71,7 @@ this cache kind is no longer written and you rely on HTTP caching instead
|
|
|
70
71
|
**Kind**: `REDIRECT`
|
|
71
72
|
**cdk-nextjs Implementation**:
|
|
72
73
|
|
|
73
|
-
- **Storage**: S3 bucket at
|
|
74
|
+
- **Storage**: S3 bucket at `{buildId}/{cache-key}.json`
|
|
74
75
|
- **Configuration**: Cached redirect rules and destinations
|
|
75
76
|
|
|
76
77
|
### 6. Router Cache (Client-side)
|
|
@@ -89,14 +90,24 @@ this cache kind is no longer written and you rely on HTTP caching instead
|
|
|
89
90
|
|
|
90
91
|
### S3 Cache Storage
|
|
91
92
|
|
|
92
|
-
cdk-nextjs uses a dedicated S3 bucket for cache storage with
|
|
93
|
+
cdk-nextjs uses a dedicated S3 bucket for cache storage, with every key under the build's ID so deployments never read each other's entries:
|
|
93
94
|
|
|
94
95
|
```
|
|
95
96
|
Cache Bucket Structure:
|
|
96
|
-
|
|
97
|
-
|
|
97
|
+
{buildId}/
|
|
98
|
+
├── {cache-key}.json # Incremental cache entries (FETCH, IMAGE, APP_PAGE, APP_ROUTE, PAGES, REDIRECT)
|
|
99
|
+
└── _use-cache/{sha256}.entry # 'use cache: remote' entries, keyed by a hash of the cache key
|
|
98
100
|
```
|
|
99
101
|
|
|
102
|
+
Each instance also keeps an in-memory copy of the entries it read or wrote, in
|
|
103
|
+
front of S3, for `CDK_NEXTJS_MEMORY_CACHE_TTL_MS` (1 hour by default; see the
|
|
104
|
+
[README](../README.md#cdk_nextjs_memory_cache_ttl_ms)). A memory hit is still
|
|
105
|
+
checked against its tags' revalidation markers, so a `revalidateTag` on any
|
|
106
|
+
instance expires it. `'use cache'` and `'use cache: remote'` have their own
|
|
107
|
+
handlers, described in the
|
|
108
|
+
[README](../README.md#use-cache-and-use-cache-remote); they read the same
|
|
109
|
+
revalidation markers.
|
|
110
|
+
|
|
100
111
|
#### Examples
|
|
101
112
|
|
|
102
113
|
<details>
|
|
@@ -110,10 +121,8 @@ Cache Bucket Structure:
|
|
|
110
121
|
"kind": "APP_PAGE",
|
|
111
122
|
"html": "<!DOCTYPE html><html lang=\"en\" class=\"[color-scheme:dark]\">...</html>",
|
|
112
123
|
"rscData": {
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
49, 58, 34, 36, 83, 114, 101, 97, 99, 116, 46, 102, 114, 97, 103, 109, ...
|
|
116
|
-
]
|
|
124
|
+
"__type": "Buffer",
|
|
125
|
+
"base64": "MToiJFNyZWFjdC5mcmFnbQ..."
|
|
117
126
|
},
|
|
118
127
|
"headers": {
|
|
119
128
|
"x-nextjs-stale-time": "300",
|
|
@@ -123,46 +132,32 @@ Cache Bucket Structure:
|
|
|
123
132
|
"__type": "Map",
|
|
124
133
|
"data": {
|
|
125
134
|
"/_tree": {
|
|
126
|
-
"
|
|
127
|
-
"
|
|
128
|
-
58, 72, 76, 91, 34, 47, 95, 110, 101, 120, 116, 47, 115, 116, 97, ...
|
|
129
|
-
]
|
|
135
|
+
"__type": "Buffer",
|
|
136
|
+
"base64": "OkhMWyIvX25leHQvc3Rh..."
|
|
130
137
|
},
|
|
131
138
|
"/_full": {
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
49, 58, 34, 36, 83, 114, 101, 97, 99, 116, 46, 102, 114, 97, 103, ...
|
|
135
|
-
]
|
|
139
|
+
"__type": "Buffer",
|
|
140
|
+
"base64": "MToiJFNyZWFjdC5mcmFn..."
|
|
136
141
|
},
|
|
137
142
|
"/isr/$d$id/__PAGE__": {
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
49, 58, 34, 36, 83, 114, 101, 97, 99, 116, 46, 102, 114, 97, 103, ...
|
|
141
|
-
]
|
|
143
|
+
"__type": "Buffer",
|
|
144
|
+
"base64": "MToiJFNyZWFjdC5mcmFn..."
|
|
142
145
|
},
|
|
143
146
|
"/isr/$d$id": {
|
|
144
|
-
"
|
|
145
|
-
"
|
|
146
|
-
49, 58, 34, 36, 83, 114, 101, 97, 99, 116, 46, 102, 114, 97, 103, ...
|
|
147
|
-
]
|
|
147
|
+
"__type": "Buffer",
|
|
148
|
+
"base64": "MToiJFNyZWFjdC5mcmFn..."
|
|
148
149
|
},
|
|
149
150
|
"/isr": {
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
49, 58, 34, 36, 83, 114, 101, 97, 99, 116, 46, 102, 114, 97, 103, ...
|
|
153
|
-
]
|
|
151
|
+
"__type": "Buffer",
|
|
152
|
+
"base64": "MToiJFNyZWFjdC5mcmFn..."
|
|
154
153
|
},
|
|
155
154
|
"/_index": {
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
49, 58, 34, 36, 83, 114, 101, 97, 99, 116, 46, 102, 114, 97, 103, ...
|
|
159
|
-
]
|
|
155
|
+
"__type": "Buffer",
|
|
156
|
+
"base64": "MToiJFNyZWFjdC5mcmFn..."
|
|
160
157
|
},
|
|
161
158
|
"/_head": {
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
49, 58, 34, 36, 83, 114, 101, 97, 99, 116, 46, 102, 114, 97, 103, ...
|
|
165
|
-
]
|
|
159
|
+
"__type": "Buffer",
|
|
160
|
+
"base64": "MToiJFNyZWFjdC5mcmFn..."
|
|
166
161
|
}
|
|
167
162
|
}
|
|
168
163
|
}
|
|
@@ -184,10 +179,8 @@ Cache Bucket Structure:
|
|
|
184
179
|
"kind": "APP_ROUTE",
|
|
185
180
|
"status": 200,
|
|
186
181
|
"body": {
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
0, 0, 1, 0, 3, 0, 48, 48, 0, 0, 1, 0, 32, 0, 168, 37, 0, 0, 54, 0, 0, 0, ...
|
|
190
|
-
]
|
|
182
|
+
"__type": "Buffer",
|
|
183
|
+
"base64": "AAABAAMAMDAAAAEAIACoJQAANgAAAA..."
|
|
191
184
|
},
|
|
192
185
|
"headers": {
|
|
193
186
|
"cache-control": "public, max-age=0, must-revalidate",
|
|
@@ -260,10 +253,8 @@ Cache Bucket Structure:
|
|
|
260
253
|
"value": {
|
|
261
254
|
"kind": "IMAGE",
|
|
262
255
|
"buffer": {
|
|
263
|
-
"
|
|
264
|
-
"
|
|
265
|
-
255, 216, 255, 219, 0, 67, 0, 8, 8, 8, 8, 9, 8, 9, 10, 10, 9, 13, 14, ...
|
|
266
|
-
]
|
|
256
|
+
"__type": "Buffer",
|
|
257
|
+
"base64": "/9j/2wBDAAgICAgJCAkKCgkNDg..."
|
|
267
258
|
},
|
|
268
259
|
"etag": "J29FvqevmUxXsoXBJzPbJC-g_PiMBegRLXAFLl_ZfhE",
|
|
269
260
|
"extension": "jpeg",
|
|
@@ -272,72 +263,114 @@ Cache Bucket Structure:
|
|
|
272
263
|
},
|
|
273
264
|
"tags": []
|
|
274
265
|
}
|
|
275
|
-
|
|
276
266
|
```
|
|
277
267
|
|
|
278
268
|
</details>
|
|
279
269
|
|
|
280
270
|
**Key Features**:
|
|
281
271
|
|
|
282
|
-
- **BUILD_ID Isolation**: All cache keys prefixed with
|
|
272
|
+
- **BUILD_ID Isolation**: All cache keys prefixed with `{buildId}/`
|
|
283
273
|
- **Next.js Cache Key Passthrough**: Preserves Next.js internal cache key structure
|
|
284
274
|
- **Cache Kind Metadata**: Cache type stored within each cache entry's metadata
|
|
275
|
+
- **Binary Payloads as base64**: RSC payloads and image bodies are `Buffer`s, written as
|
|
276
|
+
`{ "__type": "Buffer", "base64": "..." }`. `JSON.stringify` on a `Buffer` would otherwise
|
|
277
|
+
produce `{ "type": "Buffer", "data": [97, 97, ...] }` — one JSON number per byte, roughly
|
|
278
|
+
3x the bytes and, on read, one `JSON.parse` reviver call per byte. A 1 MiB RSC payload
|
|
279
|
+
costs ~4.8s of Lambda time to parse that way against ~0.2s for base64. Entries written by
|
|
280
|
+
an older build in the integer-array format are still read correctly.
|
|
285
281
|
|
|
286
282
|
### DynamoDB Revalidation Tracking
|
|
287
283
|
|
|
288
|
-
|
|
284
|
+
The revalidation table holds four kinds of item. Everything a build writes is
|
|
285
|
+
under its `buildId`, so pruning a previous build is a query of its partitions,
|
|
286
|
+
not a scan.
|
|
289
287
|
|
|
290
288
|
```typescript
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
289
|
+
// When a tag was last revalidated, and how. What every revalidation check
|
|
290
|
+
// reads, and the source of truth.
|
|
291
|
+
interface TagMarkerItem {
|
|
292
|
+
pk: string; // buildId, e.g. "build-abc123"
|
|
293
|
+
sk: string; // the tag, e.g. "user-profile"
|
|
294
|
+
revalidatedAt?: number; // expired outright: updateTag, or revalidateTag with no profile
|
|
295
|
+
staleAt?: number; // stale from here: revalidateTag(tag, profile)
|
|
296
|
+
expiredAt?: number; // when that profile's expire runs out
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// One row per revalidation of a tag, so an instance can ask "what changed
|
|
300
|
+
// since I last looked?" in one Query instead of re-reading every tag it keeps.
|
|
301
|
+
interface RevalidationLogItem {
|
|
302
|
+
pk: string; // "{buildId}#log"
|
|
303
|
+
sk: string; // "{epoch ms, zero-padded to 15 digits}#{tag}": sorts by time
|
|
304
|
+
revalidatedAt?: number; // the same fields the marker got
|
|
305
|
+
staleAt?: number;
|
|
306
|
+
expiredAt?: number;
|
|
307
|
+
ttl: number; // epoch seconds, 15 minutes out; DynamoDB deletes it after
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Which cached pages a tag appears on, so revalidateTag can name their
|
|
311
|
+
// CloudFront paths. Only written on the Global constructs.
|
|
312
|
+
interface TagMappingItem {
|
|
313
|
+
pk: string; // buildId
|
|
314
|
+
sk: string; // "{tag}#{s3Key}"
|
|
315
|
+
createdAt: number;
|
|
296
316
|
}
|
|
297
317
|
|
|
298
318
|
interface MetadataItem {
|
|
299
|
-
pk: "METADATA";
|
|
300
|
-
sk: "CURRENT_BUILD";
|
|
301
|
-
buildId: string; //
|
|
302
|
-
updatedAt: number;
|
|
319
|
+
pk: "METADATA";
|
|
320
|
+
sk: "CURRENT_BUILD";
|
|
321
|
+
buildId: string; // the current build, so the next deploy knows what to prune
|
|
322
|
+
updatedAt: number;
|
|
303
323
|
}
|
|
304
324
|
```
|
|
305
325
|
|
|
306
|
-
**Example Data
|
|
326
|
+
**Example Data**, after `revalidateTag("user-profile")`:
|
|
307
327
|
|
|
308
328
|
```
|
|
309
|
-
PK: "build-abc123"
|
|
310
|
-
PK: "build-abc123" SK: "user-profile
|
|
311
|
-
PK: "build-abc123"
|
|
312
|
-
PK: "build-abc123"
|
|
313
|
-
PK: "METADATA"
|
|
329
|
+
PK: "build-abc123" SK: "user-profile" revalidatedAt: 1790467483203
|
|
330
|
+
PK: "build-abc123#log" SK: "001790467483193#user-profile" revalidatedAt: 1790467483193, ttl: 1790468384
|
|
331
|
+
PK: "build-abc123" SK: "user-profile#build-abc123/users-profile.json" createdAt: 1790467248586
|
|
332
|
+
PK: "build-abc123" SK: "product-data#build-abc123/products.json" createdAt: 1790467248586
|
|
333
|
+
PK: "METADATA" SK: "CURRENT_BUILD" buildId: "build-abc123"
|
|
314
334
|
```
|
|
315
335
|
|
|
316
336
|
**Key Features**:
|
|
317
337
|
|
|
318
|
-
- **
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
-
|
|
338
|
+
- **Checks read markers, not mappings**: an instance reads a tag's marker the
|
|
339
|
+
first time it needs it, then learns of other instances' revalidations from
|
|
340
|
+
one log `Query` per second (see
|
|
341
|
+
[On-Demand Revalidation](#on-demand-revalidation)).
|
|
342
|
+
- **Log rows sort by time**: the sort key's timestamp is what makes "every
|
|
343
|
+
revalidation since my last query" one key range. Rows older than the query's
|
|
344
|
+
range are never read, so DynamoDB deleting expired rows late costs only
|
|
345
|
+
storage.
|
|
346
|
+
- **Mapping rows name CloudFront paths**: `revalidateTag` queries
|
|
347
|
+
`begins_with(sk, "{tag}#")` for the S3 keys, and so the paths, to invalidate.
|
|
348
|
+
Runtime `set`s write them; build-time prerenders are named by the build's
|
|
349
|
+
tag manifest in the cache bucket instead.
|
|
350
|
+
- **Efficient pruning**: the post-deploy step queries the previous build's
|
|
351
|
+
partition and deletes it. Log rows expire through TTL instead.
|
|
322
352
|
|
|
323
353
|
### Custom Cache Handler
|
|
324
354
|
|
|
325
|
-
The S3CacheHandler implements Next.js's cache interface
|
|
355
|
+
The `cacheHandler` the adapter registers (`src/adapter/cache-handler.ts`) writes local files at build time and, at runtime, puts an in-memory handler in front of `S3CacheHandler`, which implements Next.js's incremental cache interface:
|
|
326
356
|
|
|
327
357
|
```typescript
|
|
328
358
|
export class S3CacheHandler {
|
|
329
359
|
async get(
|
|
330
360
|
cacheKey: string,
|
|
331
|
-
ctx:
|
|
361
|
+
ctx: GetIncrementalFetchCacheContext | GetIncrementalResponseCacheContext,
|
|
332
362
|
): Promise<CacheHandlerValue | null>;
|
|
333
363
|
|
|
334
364
|
async set(
|
|
335
365
|
cacheKey: string,
|
|
336
|
-
data: IncrementalCacheValue,
|
|
337
|
-
ctx:
|
|
366
|
+
data: IncrementalCacheValue | null,
|
|
367
|
+
ctx: SetIncrementalFetchCacheContext | SetIncrementalResponseCacheContext,
|
|
338
368
|
): Promise<void>;
|
|
339
369
|
|
|
340
|
-
async revalidateTag(
|
|
370
|
+
async revalidateTag(
|
|
371
|
+
tag: string | string[],
|
|
372
|
+
durations?: { expire?: number },
|
|
373
|
+
): Promise<void>;
|
|
341
374
|
}
|
|
342
375
|
```
|
|
343
376
|
|
|
@@ -365,9 +398,9 @@ Each cache entry stored in S3 includes both the cached data and associated tags
|
|
|
365
398
|
**Cache Retrieval Process**:
|
|
366
399
|
|
|
367
400
|
1. **Fetch from S3**: Retrieve cache entry with embedded tags
|
|
368
|
-
2. **Revalidation Check**:
|
|
369
|
-
3. **Timestamp Comparison**: Compare `revalidatedAt` with
|
|
370
|
-
4. **Invalidation**: If
|
|
401
|
+
2. **Revalidation Check**: Look up each tag's marker (see [On-Demand Revalidation](#on-demand-revalidation) for where it comes from)
|
|
402
|
+
3. **Timestamp Comparison**: Compare the marker's `revalidatedAt`/`staleAt`/`expiredAt` with the entry's `lastModified`
|
|
403
|
+
4. **Invalidation**: If a tag was revalidated after the entry was created, a `fetch` entry reads as a miss and a page entry comes back expired, so Next.js refetches or re-renders it. The S3 object is left for that write to replace.
|
|
371
404
|
5. **Return**: If valid, return cached data without tags
|
|
372
405
|
|
|
373
406
|
**Key Features**:
|
|
@@ -376,7 +409,6 @@ Each cache entry stored in S3 includes both the cached data and associated tags
|
|
|
376
409
|
- **Tag Storage**: Tags stored with cache entries for revalidation checking
|
|
377
410
|
- **Timestamp Validation**: Prevents serving stale data after tag revalidation
|
|
378
411
|
- **Graceful Error Handling**: Logs errors and returns cache miss on failures
|
|
379
|
-
- **Bulletproof Consistency**: Even if S3 deletions fail, stale data won't be served
|
|
380
412
|
|
|
381
413
|
## Static Assets vs Cache Assets
|
|
382
414
|
|
|
@@ -388,13 +420,17 @@ Each cache entry stored in S3 includes both the cached data and associated tags
|
|
|
388
420
|
|
|
389
421
|
- `public/` folder contents
|
|
390
422
|
- `.next/static/` build artifacts (JS, CSS, images)
|
|
391
|
-
- BUILD_ID metadata for pruning
|
|
423
|
+
- A `BUILD_ID` object metadata entry on each file, for pruning
|
|
392
424
|
|
|
393
|
-
**
|
|
425
|
+
**Serving** (Global constructs):
|
|
394
426
|
|
|
395
427
|
- Requests to `/_next/static/*` → S3 bucket
|
|
396
|
-
- Requests
|
|
397
|
-
-
|
|
428
|
+
- Requests for `public/` files, at their own paths (one CloudFront behavior per top-level entry, e.g. `/favicon.ico`, `/images/*`) → S3 bucket
|
|
429
|
+
- Cached at the edge with CloudFront's `CachingOptimized` policy
|
|
430
|
+
|
|
431
|
+
On the Regional constructs there is no CDN: `NextjsRegionalFunctions` serves
|
|
432
|
+
them through API Gateway's S3 integration, and `NextjsRegionalContainers` from
|
|
433
|
+
the tasks.
|
|
398
434
|
|
|
399
435
|
### Cache Assets (S3CacheHandler)
|
|
400
436
|
|
|
@@ -412,47 +448,55 @@ Each cache entry stored in S3 includes both the cached data and associated tags
|
|
|
412
448
|
|
|
413
449
|
When `revalidateTag("user-profile")` is called:
|
|
414
450
|
|
|
415
|
-
1. **
|
|
416
|
-
2. **
|
|
417
|
-
3. **
|
|
451
|
+
1. **Write the marker**: Set `revalidatedAt` (or `staleAt`/`expiredAt` for a profile) on the tag's marker row, `pk = {buildId}, sk = user-profile`
|
|
452
|
+
2. **Log it**: Put a revalidation log row, `pk = {buildId}#log, sk = {epoch ms}#user-profile`, for other instances to find
|
|
453
|
+
3. **Find the pages** (Global constructs only): Query the mapping rows, `pk = {buildId} and begins_with(sk, "user-profile#")`, for the S3 keys, and so the paths, the tag appears on, plus the build-time prerenders the build's tag manifest (`{buildId}/_cdk-nextjs-tag-manifest.json` in the cache bucket, read once per instance) lists for it
|
|
418
454
|
4. **Invalidate CloudFront** (`NextjsGlobalFunctions`/`NextjsGlobalContainers` only): Evict the corresponding paths from the CDN edge cache too, so the origin's now-fresh state isn't masked by a still-cached edge response. This is best-effort and asynchronous (`cloudfront:CreateInvalidation` has no bounded completion SLA), so a client may briefly still observe stale content immediately after revalidation.
|
|
419
455
|
|
|
420
|
-
|
|
456
|
+
No S3 object is deleted: the next `get()` of an entry the tag is on compares the marker with the entry's `lastModified` and treats it as revalidated, and the refetch or re-render that follows overwrites it.
|
|
421
457
|
|
|
422
458
|
**Cache Retrieval After Revalidation**:
|
|
423
459
|
|
|
424
460
|
1. **Fetch Cache Entry**: Retrieve from S3 with embedded tags
|
|
425
|
-
2. **Check Revalidation**:
|
|
426
|
-
3. **Compare Timestamps**: If any `revalidatedAt` >
|
|
427
|
-
4. **
|
|
428
|
-
|
|
461
|
+
2. **Check Revalidation**: Look up each tag's marker
|
|
462
|
+
3. **Compare Timestamps**: If any `revalidatedAt` (or a past `expiredAt`) > the entry's `lastModified`, it is expired; a later `staleAt` alone makes it stale, served while it regenerates
|
|
463
|
+
4. **Fresh Data**: The refetch or re-render writes a new entry over the old one
|
|
464
|
+
|
|
465
|
+
**Marker reads are kept per instance, and caught up from a log.** Every cache hit checks its tags, in-memory hits included, and every marker of a deployment shares one partition key. So each instance reads a tag's marker the first time it needs it and keeps it. Once a second it sends one `Query` to the revalidation log (`pk = <buildId>#log`, one row per revalidated tag, expiring after 15 minutes) for what other instances revalidated since, instead of re-reading its tags. Concurrent checks share that query. It still re-reads each marker it keeps every 7.5 to 10 minutes (a random point per tag, so tags first read together don't come due together), since the marker rows are the source of truth, but at most 100 per second rather than all at once. An instance keeps up to 10,000 tags. The instance that calls `revalidateTag` sees it immediately; other instances see it up to 1 s later, which is within what CloudFront's invalidation already takes. ISR, the data cache and `'use cache'` share one copy of the markers per instance, and so one query. Set `CDK_NEXTJS_TAG_REFRESH_MS` on the functions or tasks (through `overrides`) to change the interval, or to `0` to query the log on every check.
|
|
429
466
|
|
|
430
467
|
### Time-based Revalidation
|
|
431
468
|
|
|
432
469
|
For routes with time-based revalidation (e.g., `revalidate: 3600`):
|
|
433
470
|
|
|
434
|
-
- Next.js checks
|
|
435
|
-
-
|
|
436
|
-
-
|
|
471
|
+
- Next.js checks the entry's age before serving
|
|
472
|
+
- Past `revalidate`, serves the stale entry and regenerates it in the background
|
|
473
|
+
- The regenerated entry is written to S3 (and memory) as usual
|
|
437
474
|
|
|
438
|
-
**
|
|
475
|
+
**On Lambda, background regeneration completes before the environment freezes.** Next.js hands this work to the runtime through the adapter API's `waitUntil`. The runtime awaits it after the response stream has closed, so it adds billed duration but no latency, and the function's timeout bounds it. The Containers constructs' server does the same. This is unrelated to the CloudFront edge-cache invalidation described below, which only fires for explicit tag or path revalidation, not time-based expiry.
|
|
439
476
|
|
|
440
477
|
### Tag-based Revalidation
|
|
441
478
|
|
|
442
479
|
```typescript
|
|
443
|
-
|
|
444
|
-
|
|
480
|
+
"use server";
|
|
481
|
+
// In a Server Action
|
|
482
|
+
import { revalidateTag, updateTag } from "next/cache";
|
|
445
483
|
|
|
446
484
|
export async function updateUser(userId: string) {
|
|
447
|
-
// Update user data
|
|
448
485
|
await updateUserInDatabase(userId);
|
|
449
486
|
|
|
450
|
-
//
|
|
451
|
-
|
|
452
|
-
|
|
487
|
+
// Expire at once, so this user sees their own change on the next render
|
|
488
|
+
updateTag(`user-${userId}`);
|
|
489
|
+
// Serve stale while every page listing users regenerates in the background
|
|
490
|
+
revalidateTag("user-list", "max");
|
|
453
491
|
}
|
|
454
492
|
```
|
|
455
493
|
|
|
494
|
+
`updateTag` (Server Actions only) sets the marker's `revalidatedAt`: entries
|
|
495
|
+
expire immediately. `revalidateTag(tag, profile)` sets `staleAt`, and `expiredAt`
|
|
496
|
+
from the profile's `expire`: entries are served stale while they regenerate,
|
|
497
|
+
until that runs out (with `{ expire: 0 }`, at once). Route handlers can use
|
|
498
|
+
`revalidateTag` but not `updateTag`.
|
|
499
|
+
|
|
456
500
|
## Performance Characteristics
|
|
457
501
|
|
|
458
502
|
### S3 Cache Operations
|
|
@@ -465,7 +509,7 @@ export async function updateUser(userId: string) {
|
|
|
465
509
|
### DynamoDB Revalidation
|
|
466
510
|
|
|
467
511
|
- **Query Latency**: ~1-5ms (single partition key lookup)
|
|
468
|
-
- **Revalidation Check**:
|
|
512
|
+
- **Revalidation Check**: One `BatchGetItem` for tags an instance hasn't seen yet, then one revalidation log `Query` per second per instance, however many tags it keeps (`CDK_NEXTJS_TAG_REFRESH_MS`)
|
|
469
513
|
- **Scalability**: Handles millions of cache entries
|
|
470
514
|
- **Cost**: Minimal - only pays for actual reads/writes
|
|
471
515
|
- **Consistency**: Eventually consistent (sufficient for cache invalidation)
|
|
@@ -481,7 +525,7 @@ export async function updateUser(userId: string) {
|
|
|
481
525
|
|
|
482
526
|
### Cache Not Working
|
|
483
527
|
|
|
484
|
-
1. Check environment
|
|
528
|
+
1. Check the compute's environment has `CDK_NEXTJS_CACHE_BUCKET_NAME`, `CDK_NEXTJS_REVALIDATION_TABLE_NAME` and `CDK_NEXTJS_BUILD_ID` (the constructs set them)
|
|
485
529
|
2. Verify S3 bucket and DynamoDB table exist
|
|
486
530
|
3. Check Lambda/container permissions
|
|
487
531
|
4. Review CloudWatch logs for errors
|
|
@@ -489,11 +533,11 @@ export async function updateUser(userId: string) {
|
|
|
489
533
|
### Revalidation Issues
|
|
490
534
|
|
|
491
535
|
1. Verify tags are set correctly in fetch requests
|
|
492
|
-
2. Check DynamoDB
|
|
536
|
+
2. Check the tag's marker row in DynamoDB (`pk = {buildId}, sk = {tag}`) and its log rows (`pk = {buildId}#log`)
|
|
493
537
|
3. Ensure revalidateTag() calls are working
|
|
494
|
-
4.
|
|
495
|
-
5.
|
|
496
|
-
6.
|
|
538
|
+
4. On the Global constructs, check the tag's mapping rows (`sk` beginning `{tag}#`) and the build's tag manifest (`{buildId}/_cdk-nextjs-tag-manifest.json`), which name the CloudFront paths to invalidate
|
|
539
|
+
5. With `DEBUG=cdk-nextjs:*`, check CloudWatch logs for "CACHE INVALIDATED BY TAG" messages
|
|
540
|
+
6. Compare the marker's timestamps with the entry's `lastModified`
|
|
497
541
|
|
|
498
542
|
### Performance Problems
|
|
499
543
|
|
|
@@ -53,7 +53,7 @@ Expanding Turbopack's root to include the entire monorepo causes it to repeatedl
|
|
|
53
53
|
The `examples/app-playground/package.json` includes a `sync-cdk-nextjs` script that copies the necessary files directly into `node_modules` without symlinks:
|
|
54
54
|
|
|
55
55
|
```json
|
|
56
|
-
"sync-cdk-nextjs": "rm -rf node_modules/cdk-nextjs && mkdir -p node_modules/cdk-nextjs/lib/adapter && cp ../../package.json node_modules/cdk-nextjs/package.json && cp ../../lib/adapter/adapter.mjs node_modules/cdk-nextjs/lib/adapter/adapter.mjs && cp ../../lib/adapter/cache-handler.mjs
|
|
56
|
+
"sync-cdk-nextjs": "rm -rf node_modules/cdk-nextjs && mkdir -p node_modules/cdk-nextjs/lib/adapter && cp ../../package.json node_modules/cdk-nextjs/package.json && cp ../../lib/adapter/adapter.mjs node_modules/cdk-nextjs/lib/adapter/adapter.mjs && cp ../../lib/adapter/cache-handler.mjs ../../lib/adapter/use-cache-default-handler.mjs ../../lib/adapter/use-cache-remote-handler.mjs node_modules/cdk-nextjs/lib/adapter/"
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
Both `build` and `dev` chain it explicitly (`npm run sync-cdk-nextjs && next …`) so the copy happens no matter which package manager invokes them. While hacky, it:
|