cdk-nextjs 0.6.2 → 0.7.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/.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 +1548 -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 +852 -0
- package/lib/adapter/build-outputs.test.d.ts +1 -0
- package/lib/adapter/build-outputs.test.js +861 -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 +1213 -0
- package/lib/runtime/core.test.d.ts +1 -0
- package/lib/runtime/core.test.js +1678 -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 +41595 -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 +55 -0
- package/lib/runtime/next-modules.js +124 -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 +41588 -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
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build a throwaway Next.js app against a *packed and installed* cdk-nextjs, with
|
|
4
|
+
* no `adapterPath` in `next.config` — the zero-config path the README recommends
|
|
5
|
+
* (`NEXT_ADAPTER_PATH`), which nothing else in CI covers.
|
|
6
|
+
*
|
|
7
|
+
* pnpm compile && pnpm bundle
|
|
8
|
+
* node scripts/zero-config-build.mjs
|
|
9
|
+
*
|
|
10
|
+
* Why a packed tarball and not `examples/`. Every example takes cdk-nextjs as
|
|
11
|
+
* `link:../..`, and a link is exactly the setup zero-config cannot serve: the
|
|
12
|
+
* symlink resolves out of the project root, the adapter derives its cache handler
|
|
13
|
+
* path from its own location, and Turbopack rejects a `cacheHandler` outside
|
|
14
|
+
* `turbopack.root`. So the examples all set `adapterPath` explicitly, and the
|
|
15
|
+
* variable they would otherwise exercise goes untested. `npm install` of a `.tgz`
|
|
16
|
+
* extracts a real directory into the app's own `node_modules`, which is what a
|
|
17
|
+
* user's install looks like and the only shape under which
|
|
18
|
+
* `require.resolve("cdk-nextjs/adapter", { paths: [appDir] })` — the resolution
|
|
19
|
+
* `NextjsBuild.adapterPathEnv` performs — produces a usable path.
|
|
20
|
+
*
|
|
21
|
+
* Two cases, one install, because the second is nearly free:
|
|
22
|
+
*
|
|
23
|
+
* 1. `next.config.js`, the plain zero-config case.
|
|
24
|
+
* 2. `next.config.ts` using top-level `await`, built with
|
|
25
|
+
* `--experimental-next-config-strip-types` so Node.js's native TypeScript
|
|
26
|
+
* resolution loads it instead of the default swc-to-CJS transpile. This is the
|
|
27
|
+
* whole of what vercel/next.js's 18-file `next-config-ts-native-ts` family
|
|
28
|
+
* would tell us about cdk-nextjs: that `modifyConfig` still applies when the
|
|
29
|
+
* config arrives through the native loader. See docs/harness-coverage.md.
|
|
30
|
+
*
|
|
31
|
+
* No AWS, no deploy, no credentials. Two `next build`s and an `npm install`.
|
|
32
|
+
*
|
|
33
|
+
* Flags: `--dir <path>` to build somewhere fixed instead of a fresh mkdtemp, and
|
|
34
|
+
* `--keep` to leave the tree behind for inspection.
|
|
35
|
+
*/
|
|
36
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
37
|
+
import {
|
|
38
|
+
existsSync,
|
|
39
|
+
mkdirSync,
|
|
40
|
+
mkdtempSync,
|
|
41
|
+
readFileSync,
|
|
42
|
+
readdirSync,
|
|
43
|
+
realpathSync,
|
|
44
|
+
rmSync,
|
|
45
|
+
writeFileSync,
|
|
46
|
+
} from "node:fs";
|
|
47
|
+
import { createRequire } from "node:module";
|
|
48
|
+
import { tmpdir } from "node:os";
|
|
49
|
+
import { dirname, join, resolve } from "node:path";
|
|
50
|
+
import { fileURLToPath } from "node:url";
|
|
51
|
+
|
|
52
|
+
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
53
|
+
const MODIFY_CONFIG_LOG = "Applying modifyConfig from cdk-nextjs-adapter";
|
|
54
|
+
/** `next`'s own warning when the native TS loader is not actually in use. */
|
|
55
|
+
const LEGACY_CONFIG_FALLBACK = "Falling back to legacy resolution";
|
|
56
|
+
const REACT_VERSION = "19.2.3";
|
|
57
|
+
|
|
58
|
+
function main() {
|
|
59
|
+
const args = process.argv.slice(2);
|
|
60
|
+
const dirFlag = args.indexOf("--dir");
|
|
61
|
+
const keep = args.includes("--keep");
|
|
62
|
+
|
|
63
|
+
const appDir = realpathSync(
|
|
64
|
+
dirFlag === -1
|
|
65
|
+
? mkdtempSync(join(tmpdir(), "cdk-nextjs-zero-config-"))
|
|
66
|
+
: mkdirIfNeeded(resolve(args[dirFlag + 1])),
|
|
67
|
+
);
|
|
68
|
+
console.log(`zero-config: building in ${appDir}`);
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const tarball = pack(appDir);
|
|
72
|
+
writeFixture(appDir, tarball);
|
|
73
|
+
run("npm", ["install", "--no-audit", "--no-fund"], appDir);
|
|
74
|
+
|
|
75
|
+
// The same resolution `NextjsBuild.adapterPathEnv()` does, for the same
|
|
76
|
+
// reason: from the *app*, so the adapter and its sibling cache handler both
|
|
77
|
+
// live inside the project root.
|
|
78
|
+
const adapterPath = createRequire(join(appDir, "package.json")).resolve(
|
|
79
|
+
"cdk-nextjs/adapter",
|
|
80
|
+
);
|
|
81
|
+
console.log(`zero-config: NEXT_ADAPTER_PATH=${adapterPath}`);
|
|
82
|
+
assert(
|
|
83
|
+
adapterPath.startsWith(join(appDir, "node_modules", "cdk-nextjs") + "/"),
|
|
84
|
+
`the adapter resolved outside the app's node_modules: ${adapterPath}`,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
writeConfigJs(appDir);
|
|
88
|
+
check(appDir, adapterPath, {
|
|
89
|
+
label: "next.config.js (default config loader)",
|
|
90
|
+
distDir: ".next-cjs",
|
|
91
|
+
buildArgs: [],
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
writeConfigTs(appDir);
|
|
95
|
+
check(appDir, adapterPath, {
|
|
96
|
+
label: "next.config.ts with top-level await (native TS loader)",
|
|
97
|
+
distDir: ".next-ts",
|
|
98
|
+
buildArgs: ["--experimental-next-config-strip-types"],
|
|
99
|
+
// The default loader transpiles to CJS, which cannot express top-level
|
|
100
|
+
// `await`; a silent fallback would surface as ERR_REQUIRE_ASYNC_MODULE
|
|
101
|
+
// rather than a pass, but assert on the warning too so a future fallback
|
|
102
|
+
// that *does* succeed cannot masquerade as native-loader coverage.
|
|
103
|
+
forbid: LEGACY_CONFIG_FALLBACK,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
console.log("\nzero-config: both cases passed");
|
|
107
|
+
} finally {
|
|
108
|
+
if (keep) {
|
|
109
|
+
console.log(`zero-config: left ${appDir} in place (--keep)`);
|
|
110
|
+
} else {
|
|
111
|
+
rmSync(appDir, { recursive: true, force: true });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function mkdirIfNeeded(dir) {
|
|
117
|
+
mkdirSync(dir, { recursive: true });
|
|
118
|
+
return dir;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* `npm pack` the working tree into `appDir`. Fails loudly if a file the package's
|
|
123
|
+
* `exports` points at is missing, because the tarball would otherwise be
|
|
124
|
+
* published-shaped but adapter-less and every assertion below would be about
|
|
125
|
+
* nothing.
|
|
126
|
+
*/
|
|
127
|
+
function pack(appDir) {
|
|
128
|
+
const { exports } = JSON.parse(
|
|
129
|
+
readFileSync(join(repoRoot, "package.json"), "utf8"),
|
|
130
|
+
);
|
|
131
|
+
for (const { default: file } of Object.values(exports)) {
|
|
132
|
+
assert(
|
|
133
|
+
existsSync(join(repoRoot, file)),
|
|
134
|
+
`${file} is missing — run \`pnpm compile && pnpm bundle\` first.`,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
const out = execFileSync(
|
|
138
|
+
"npm",
|
|
139
|
+
["pack", "--ignore-scripts", "--json", "--pack-destination", appDir],
|
|
140
|
+
{ cwd: repoRoot, encoding: "utf8", stdio: ["ignore", "pipe", "inherit"] },
|
|
141
|
+
);
|
|
142
|
+
const filename = JSON.parse(out)[0].filename;
|
|
143
|
+
const tarball = join(appDir, filename);
|
|
144
|
+
assert(existsSync(tarball), `npm pack reported ${filename}, which is absent`);
|
|
145
|
+
console.log(`zero-config: packed ${filename}`);
|
|
146
|
+
return tarball;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function writeFixture(appDir, tarball) {
|
|
150
|
+
// The exact `next` this repo's own lockfile resolved, not its `^16.3.5` range:
|
|
151
|
+
// a per-PR gate should fail on our changes, not on a patch release that landed
|
|
152
|
+
// between two runs of the same commit.
|
|
153
|
+
const nextVersion = JSON.parse(
|
|
154
|
+
readFileSync(
|
|
155
|
+
join(repoRoot, "node_modules", "next", "package.json"),
|
|
156
|
+
"utf8",
|
|
157
|
+
),
|
|
158
|
+
).version;
|
|
159
|
+
|
|
160
|
+
write(appDir, "package.json", {
|
|
161
|
+
name: "cdk-nextjs-zero-config-fixture",
|
|
162
|
+
version: "0.0.0",
|
|
163
|
+
private: true,
|
|
164
|
+
dependencies: {
|
|
165
|
+
// `file:` on a tarball extracts; `file:` on a directory would symlink,
|
|
166
|
+
// which is the case this fixture exists to avoid.
|
|
167
|
+
"cdk-nextjs": `file:${tarball}`,
|
|
168
|
+
next: nextVersion,
|
|
169
|
+
// Pinned for the same reason, and to the `react` in
|
|
170
|
+
// `examples/pnpm-workspace.yaml`'s catalog. Bump the two together.
|
|
171
|
+
react: REACT_VERSION,
|
|
172
|
+
"react-dom": REACT_VERSION,
|
|
173
|
+
},
|
|
174
|
+
devDependencies: {
|
|
175
|
+
"@types/node": "^24",
|
|
176
|
+
"@types/react": "^19",
|
|
177
|
+
typescript: "^5",
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
write(appDir, "tsconfig.json", {
|
|
182
|
+
compilerOptions: {
|
|
183
|
+
target: "ES2022",
|
|
184
|
+
lib: ["dom", "dom.iterable", "esnext"],
|
|
185
|
+
module: "esnext",
|
|
186
|
+
moduleResolution: "bundler",
|
|
187
|
+
jsx: "preserve",
|
|
188
|
+
strict: true,
|
|
189
|
+
noEmit: true,
|
|
190
|
+
skipLibCheck: true,
|
|
191
|
+
esModuleInterop: true,
|
|
192
|
+
resolveJsonModule: true,
|
|
193
|
+
isolatedModules: true,
|
|
194
|
+
incremental: true,
|
|
195
|
+
},
|
|
196
|
+
include: ["**/*.ts", "**/*.tsx", ".next-cjs/types/**/*.ts"],
|
|
197
|
+
exclude: ["node_modules"],
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
write(
|
|
201
|
+
appDir,
|
|
202
|
+
"app/layout.tsx",
|
|
203
|
+
`export default function RootLayout({
|
|
204
|
+
children,
|
|
205
|
+
}: {
|
|
206
|
+
children: React.ReactNode;
|
|
207
|
+
}) {
|
|
208
|
+
return (
|
|
209
|
+
<html lang="en">
|
|
210
|
+
<body>{children}</body>
|
|
211
|
+
</html>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
`,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
write(
|
|
218
|
+
appDir,
|
|
219
|
+
"app/page.tsx",
|
|
220
|
+
`export default function Page() {
|
|
221
|
+
return <main>zero-config</main>;
|
|
222
|
+
}
|
|
223
|
+
`,
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
// An ISR route, so \`onBuildComplete\` has a prerender to seed and the init
|
|
227
|
+
// cache is a real assertion rather than an empty directory.
|
|
228
|
+
write(
|
|
229
|
+
appDir,
|
|
230
|
+
"app/isr/[id]/page.tsx",
|
|
231
|
+
`export const revalidate = 60;
|
|
232
|
+
|
|
233
|
+
export function generateStaticParams() {
|
|
234
|
+
return [{ id: "1" }];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export default async function Page({
|
|
238
|
+
params,
|
|
239
|
+
}: {
|
|
240
|
+
params: Promise<{ id: string }>;
|
|
241
|
+
}) {
|
|
242
|
+
const { id } = await params;
|
|
243
|
+
return <main>isr {id}</main>;
|
|
244
|
+
}
|
|
245
|
+
`,
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** Zero-config: `distDir` and nothing else. No `adapterPath`. */
|
|
250
|
+
function writeConfigJs(appDir) {
|
|
251
|
+
rmSync(join(appDir, "next.config.ts"), { force: true });
|
|
252
|
+
write(
|
|
253
|
+
appDir,
|
|
254
|
+
"next.config.js",
|
|
255
|
+
`/** @type {import("next").NextConfig} */
|
|
256
|
+
module.exports = {
|
|
257
|
+
distDir: ".next-cjs",
|
|
258
|
+
};
|
|
259
|
+
`,
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Also zero-config, but reached through Node.js's native TypeScript resolution:
|
|
265
|
+
* top-level `await` is what the default swc-to-CJS loader cannot express, so this
|
|
266
|
+
* file only loads under `--experimental-next-config-strip-types`. `distDir` comes
|
|
267
|
+
* *out* of the await, which makes every path assertion below evidence that the
|
|
268
|
+
* awaited value reached Next.js.
|
|
269
|
+
*/
|
|
270
|
+
function writeConfigTs(appDir) {
|
|
271
|
+
rmSync(join(appDir, "next.config.js"), { force: true });
|
|
272
|
+
write(
|
|
273
|
+
appDir,
|
|
274
|
+
"next.config.ts",
|
|
275
|
+
`import type { NextConfig } from "next";
|
|
276
|
+
|
|
277
|
+
const resolved = await Promise.resolve({ distDir: ".next-ts" });
|
|
278
|
+
|
|
279
|
+
const nextConfig: NextConfig = { ...resolved };
|
|
280
|
+
|
|
281
|
+
export default nextConfig;
|
|
282
|
+
`,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function check(appDir, adapterPath, { label, distDir, buildArgs, forbid }) {
|
|
287
|
+
console.log(`\nzero-config: === ${label} ===`);
|
|
288
|
+
const dist = join(appDir, distDir);
|
|
289
|
+
rmSync(dist, { recursive: true, force: true });
|
|
290
|
+
|
|
291
|
+
const output = build(appDir, buildArgs, adapterPath);
|
|
292
|
+
|
|
293
|
+
assert(
|
|
294
|
+
output.includes(MODIFY_CONFIG_LOG),
|
|
295
|
+
`"${MODIFY_CONFIG_LOG}" is absent from the build log — the adapter was not loaded, so NEXT_ADAPTER_PATH did not take effect.`,
|
|
296
|
+
);
|
|
297
|
+
if (forbid) {
|
|
298
|
+
assert(!output.includes(forbid), `the build log contains "${forbid}"`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// What `modifyConfig` returned, as the build recorded it. Covers the half of
|
|
302
|
+
// zero-config that the log line does not: that the adapter injected a cache
|
|
303
|
+
// handler resolved from its own installed location.
|
|
304
|
+
const required = readJson(join(dist, "required-server-files.json"));
|
|
305
|
+
assert(
|
|
306
|
+
required.config.adapterPath === adapterPath,
|
|
307
|
+
`required-server-files.json records adapterPath ${required.config.adapterPath}, expected ${adapterPath}`,
|
|
308
|
+
);
|
|
309
|
+
// Relative to `distDir`, which is how Next.js stores it.
|
|
310
|
+
const cacheHandler = resolve(dist, required.config.cacheHandler);
|
|
311
|
+
assert(
|
|
312
|
+
cacheHandler ===
|
|
313
|
+
join(
|
|
314
|
+
appDir,
|
|
315
|
+
"node_modules",
|
|
316
|
+
"cdk-nextjs",
|
|
317
|
+
"lib",
|
|
318
|
+
"adapter",
|
|
319
|
+
"cache-handler.mjs",
|
|
320
|
+
) && existsSync(cacheHandler),
|
|
321
|
+
`cacheHandler resolved to ${cacheHandler}, which is not the installed package's`,
|
|
322
|
+
);
|
|
323
|
+
assert(
|
|
324
|
+
required.config.images.customCacheHandler === true,
|
|
325
|
+
"images.customCacheHandler was not set by modifyConfig",
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
// `onBuildComplete`: the manifest and the staging tree that replace
|
|
329
|
+
// `output: "standalone"`.
|
|
330
|
+
const adapterDir = join(dist, "cdk-nextjs-adapter");
|
|
331
|
+
const manifest = readJson(join(adapterDir, "manifest.json"));
|
|
332
|
+
assert(manifest.version === 1, `manifest version ${manifest.version}`);
|
|
333
|
+
for (const route of ["/", "/isr/[id]"]) {
|
|
334
|
+
assert(
|
|
335
|
+
manifest.entrypoints[route],
|
|
336
|
+
`manifest has no entrypoint for ${route}`,
|
|
337
|
+
);
|
|
338
|
+
const staged = join(
|
|
339
|
+
adapterDir,
|
|
340
|
+
"app",
|
|
341
|
+
manifest.entrypoints[route].filePath,
|
|
342
|
+
);
|
|
343
|
+
assert(
|
|
344
|
+
existsSync(staged),
|
|
345
|
+
`${route}'s entrypoint is not staged: ${staged}`,
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const seeded = jsonFilesIn(join(dist, "cdk-nextjs-init-cache"));
|
|
350
|
+
assert(seeded > 0, "the init cache holds no entries");
|
|
351
|
+
|
|
352
|
+
console.log(
|
|
353
|
+
`zero-config: ok — ${Object.keys(manifest.entrypoints).length} entrypoints, ${seeded} seeded cache entries`,
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function build(appDir, buildArgs, adapterPath) {
|
|
358
|
+
const next = join(appDir, "node_modules", ".bin", "next");
|
|
359
|
+
console.log(`$ next build ${buildArgs.join(" ")} (in ${appDir})`);
|
|
360
|
+
const result = spawnSync(next, ["build", ...buildArgs], {
|
|
361
|
+
cwd: appDir,
|
|
362
|
+
encoding: "utf8",
|
|
363
|
+
env: {
|
|
364
|
+
...process.env,
|
|
365
|
+
// The point of the exercise: no `adapterPath` in `next.config`.
|
|
366
|
+
NEXT_ADAPTER_PATH: adapterPath,
|
|
367
|
+
NEXT_TELEMETRY_DISABLED: "1",
|
|
368
|
+
// Not set by CDK here, so the adapter defaults it inside `distDir` — which
|
|
369
|
+
// is where the init-cache assertion looks.
|
|
370
|
+
CDK_NEXTJS_INIT_CACHE_DIR: "",
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
const output = `${result.stdout ?? ""}${result.stderr ?? ""}`;
|
|
374
|
+
process.stdout.write(output);
|
|
375
|
+
if (result.error) throw result.error;
|
|
376
|
+
assert(result.status === 0, `next build exited with ${result.status}`);
|
|
377
|
+
return output;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function jsonFilesIn(dir) {
|
|
381
|
+
if (!existsSync(dir)) return 0;
|
|
382
|
+
let count = 0;
|
|
383
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
384
|
+
count += entry.isDirectory()
|
|
385
|
+
? jsonFilesIn(join(dir, entry.name))
|
|
386
|
+
: entry.name.endsWith(".json")
|
|
387
|
+
? 1
|
|
388
|
+
: 0;
|
|
389
|
+
}
|
|
390
|
+
return count;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function readJson(path) {
|
|
394
|
+
assert(existsSync(path), `${path} was not written`);
|
|
395
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function write(appDir, relative, contents) {
|
|
399
|
+
const path = join(appDir, relative);
|
|
400
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
401
|
+
writeFileSync(
|
|
402
|
+
path,
|
|
403
|
+
typeof contents === "string"
|
|
404
|
+
? contents
|
|
405
|
+
: `${JSON.stringify(contents, null, 2)}\n`,
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function run(cmd, args, cwd) {
|
|
410
|
+
console.log(`$ ${cmd} ${args.join(" ")} (in ${cwd})`);
|
|
411
|
+
execFileSync(cmd, args, { cwd, stdio: ["ignore", "inherit", "inherit"] });
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function assert(condition, message) {
|
|
415
|
+
if (!condition) throw new Error(`zero-config: ${message}`);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
main();
|
|
Binary file
|