@opennextjs/cloudflare 1.19.4 → 1.19.6
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/dist/api/durable-objects/queue.js +3 -2
- package/dist/api/overrides/tag-cache/tag-cache-filter.d.ts +2 -2
- package/dist/cli/build/build.js +13 -0
- package/dist/cli/build/patches/plugins/turbopack.d.ts +25 -0
- package/dist/cli/build/patches/plugins/turbopack.js +66 -1
- package/dist/cli/build/utils/workerd.js +10 -11
- package/dist/cli/commands/migrate.js +11 -4
- package/dist/cli/commands/populate-cache.js +2 -1
- package/dist/cli/utils/create-wrangler-config.js +1 -1
- package/package.json +2 -2
|
@@ -21,10 +21,11 @@ export class DOQueueHandler extends DurableObject {
|
|
|
21
21
|
disableSQLite;
|
|
22
22
|
constructor(ctx, env) {
|
|
23
23
|
super(ctx, env);
|
|
24
|
-
this.service = env.WORKER_SELF_REFERENCE;
|
|
25
24
|
// If there is no service binding, we throw an error because we can't revalidate without it
|
|
26
|
-
if (!
|
|
25
|
+
if (!env.WORKER_SELF_REFERENCE) {
|
|
27
26
|
throw new IgnorableError("No service binding for cache revalidation worker");
|
|
27
|
+
}
|
|
28
|
+
this.service = env.WORKER_SELF_REFERENCE;
|
|
28
29
|
this.sql = ctx.storage.sql;
|
|
29
30
|
this.maxRevalidations = env.NEXT_CACHE_DO_QUEUE_MAX_REVALIDATION
|
|
30
31
|
? parseInt(env.NEXT_CACHE_DO_QUEUE_MAX_REVALIDATION)
|
|
@@ -10,7 +10,7 @@ interface WithFilterOptions {
|
|
|
10
10
|
* @param tag The tag to filter.
|
|
11
11
|
* @returns true if the tag should be forwarded, false otherwise.
|
|
12
12
|
*/
|
|
13
|
-
filterFn: (tag:
|
|
13
|
+
filterFn: (tag: NextModeTagCacheWriteInput) => boolean;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Creates a new tag cache that filters tags based on the provided filter function.
|
|
@@ -22,5 +22,5 @@ export declare function withFilter({ tagCache, filterFn }: WithFilterOptions): N
|
|
|
22
22
|
* This is used to filter out internal soft tags.
|
|
23
23
|
* Can be used if `revalidatePath` is not used.
|
|
24
24
|
*/
|
|
25
|
-
export declare function softTagFilter(tag:
|
|
25
|
+
export declare function softTagFilter(tag: NextModeTagCacheWriteInput): boolean;
|
|
26
26
|
export {};
|
package/dist/cli/build/build.js
CHANGED
|
@@ -38,6 +38,19 @@ export async function build(options, config, projectOpts, wranglerConfig, allowU
|
|
|
38
38
|
const { aws, cloudflare } = getVersion();
|
|
39
39
|
logger.info(`@opennextjs/cloudflare version: ${cloudflare}`);
|
|
40
40
|
logger.info(`@opennextjs/aws version: ${aws}`);
|
|
41
|
+
if (wranglerConfig.compatibility_date) {
|
|
42
|
+
const sixMonthsAgoMs = Date.now() - 6 * 30 * 24 * 60 * 60 * 1000;
|
|
43
|
+
const compatDateMs = new Date(wranglerConfig.compatibility_date).getTime();
|
|
44
|
+
if (!isNaN(compatDateMs)) {
|
|
45
|
+
const dateMessage = `workerd compatibility_date: ${wranglerConfig.compatibility_date}`;
|
|
46
|
+
if (compatDateMs < sixMonthsAgoMs) {
|
|
47
|
+
logger.warn(`${dateMessage}, consider updating your wrangler config to a more recent date to benefit from the latest features and fixes.`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
logger.info(`${dateMessage}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
41
54
|
// Clean the output directory before building the Next app.
|
|
42
55
|
buildHelper.initOutputDir(options);
|
|
43
56
|
if (projectOpts.skipNextBuild) {
|
|
@@ -1,2 +1,27 @@
|
|
|
1
1
|
import type { CodePatcher } from "@opennextjs/aws/build/patch/codePatcher.js";
|
|
2
|
+
/**
|
|
3
|
+
* Replace Turbopack's `loadWebAssemblyModule` with a call to our generated `loadWasmChunk`.
|
|
4
|
+
*
|
|
5
|
+
* The original implementation uses `WebAssembly.compileStreaming`, which is not available
|
|
6
|
+
* in workerd. `loadWasmChunk` resolves the chunk via a static `import()` switch so the
|
|
7
|
+
* bundler can statically discover and bundle each `.wasm` chunk.
|
|
8
|
+
*/
|
|
9
|
+
export declare const replaceLoadWebAssemblyModuleRule = "\nrule:\n kind: function_declaration\n has:\n field: name\n regex: \"^loadWebAssemblyModule$\"\nfix: |-\n function loadWebAssemblyModule(chunkPath, _edgeModule) {\n return loadWasmChunk(chunkPath);\n }\n";
|
|
10
|
+
/**
|
|
11
|
+
* Replace Turbopack's `loadWebAssembly` with a synchronous-instantiation variant.
|
|
12
|
+
*
|
|
13
|
+
* The original implementation uses `WebAssembly.instantiateStreaming`, which is not
|
|
14
|
+
* available in workerd. We load the compiled module via `loadWasmChunk` and then call
|
|
15
|
+
* the synchronous `WebAssembly.instantiate` to produce the instance's exports.
|
|
16
|
+
*/
|
|
17
|
+
export declare const replaceLoadWebAssemblyRule = "\nrule:\n kind: function_declaration\n has:\n field: name\n regex: \"^loadWebAssembly$\"\nfix: |-\n async function loadWebAssembly(chunkPath, _edgeModule, imports) {\n const mod = await loadWasmChunk(chunkPath);\n const { exports } = await WebAssembly.instantiate(mod, imports);\n return exports;\n }\n";
|
|
2
18
|
export declare const patchTurbopackRuntime: CodePatcher;
|
|
19
|
+
/**
|
|
20
|
+
* Generate a `loadWasmChunk` function that maps a `.next`-relative chunk path to a
|
|
21
|
+
* statically-importable `.wasm` module.
|
|
22
|
+
*
|
|
23
|
+
* The replacement rules for Turbopack's `loadWebAssembly{,Module}` delegate to this
|
|
24
|
+
* function. Because the imports are emitted as string literals, the bundler can
|
|
25
|
+
* statically discover every wasm chunk and include them in the final build.
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadWasmChunkFn(tracedFiles: string[]): string;
|
|
@@ -9,6 +9,44 @@ rule:
|
|
|
9
9
|
fix:
|
|
10
10
|
requireChunk(chunkPath)
|
|
11
11
|
`;
|
|
12
|
+
/**
|
|
13
|
+
* Replace Turbopack's `loadWebAssemblyModule` with a call to our generated `loadWasmChunk`.
|
|
14
|
+
*
|
|
15
|
+
* The original implementation uses `WebAssembly.compileStreaming`, which is not available
|
|
16
|
+
* in workerd. `loadWasmChunk` resolves the chunk via a static `import()` switch so the
|
|
17
|
+
* bundler can statically discover and bundle each `.wasm` chunk.
|
|
18
|
+
*/
|
|
19
|
+
export const replaceLoadWebAssemblyModuleRule = `
|
|
20
|
+
rule:
|
|
21
|
+
kind: function_declaration
|
|
22
|
+
has:
|
|
23
|
+
field: name
|
|
24
|
+
regex: "^loadWebAssemblyModule$"
|
|
25
|
+
fix: |-
|
|
26
|
+
function loadWebAssemblyModule(chunkPath, _edgeModule) {
|
|
27
|
+
return loadWasmChunk(chunkPath);
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
/**
|
|
31
|
+
* Replace Turbopack's `loadWebAssembly` with a synchronous-instantiation variant.
|
|
32
|
+
*
|
|
33
|
+
* The original implementation uses `WebAssembly.instantiateStreaming`, which is not
|
|
34
|
+
* available in workerd. We load the compiled module via `loadWasmChunk` and then call
|
|
35
|
+
* the synchronous `WebAssembly.instantiate` to produce the instance's exports.
|
|
36
|
+
*/
|
|
37
|
+
export const replaceLoadWebAssemblyRule = `
|
|
38
|
+
rule:
|
|
39
|
+
kind: function_declaration
|
|
40
|
+
has:
|
|
41
|
+
field: name
|
|
42
|
+
regex: "^loadWebAssembly$"
|
|
43
|
+
fix: |-
|
|
44
|
+
async function loadWebAssembly(chunkPath, _edgeModule, imports) {
|
|
45
|
+
const mod = await loadWasmChunk(chunkPath);
|
|
46
|
+
const { exports } = await WebAssembly.instantiate(mod, imports);
|
|
47
|
+
return exports;
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
12
50
|
/**
|
|
13
51
|
* Discover Turbopack external module mappings by reading symlinks in .next/node_modules/.
|
|
14
52
|
*
|
|
@@ -196,7 +234,10 @@ export const patchTurbopackRuntime = {
|
|
|
196
234
|
const externalImportRule = buildExternalImportRule(mappings, tracedFiles, code);
|
|
197
235
|
let patched = patchCode(code, externalImportRule);
|
|
198
236
|
patched = patchCode(patched, inlineChunksRule);
|
|
199
|
-
|
|
237
|
+
patched = patchCode(patched, replaceLoadWebAssemblyModuleRule);
|
|
238
|
+
patched = patchCode(patched, replaceLoadWebAssemblyRule);
|
|
239
|
+
return `${patched}
|
|
240
|
+
${inlineChunksFn(tracedFiles)}\n${loadWasmChunkFn(tracedFiles)}`;
|
|
200
241
|
},
|
|
201
242
|
},
|
|
202
243
|
],
|
|
@@ -230,3 +271,27 @@ ${chunks
|
|
|
230
271
|
}
|
|
231
272
|
`;
|
|
232
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* Generate a `loadWasmChunk` function that maps a `.next`-relative chunk path to a
|
|
276
|
+
* statically-importable `.wasm` module.
|
|
277
|
+
*
|
|
278
|
+
* The replacement rules for Turbopack's `loadWebAssembly{,Module}` delegate to this
|
|
279
|
+
* function. Because the imports are emitted as string literals, the bundler can
|
|
280
|
+
* statically discover every wasm chunk and include them in the final build.
|
|
281
|
+
*/
|
|
282
|
+
export function loadWasmChunkFn(tracedFiles) {
|
|
283
|
+
const wasmFiles = tracedFiles.filter((f) => f.endsWith(".wasm"));
|
|
284
|
+
const cases = wasmFiles
|
|
285
|
+
.map((absPath) => ({ absPath, relPath: absPath.replace(/.*\/\.next\//, "") }))
|
|
286
|
+
.map(({ absPath, relPath }) => ` case "${relPath}": return (await import("${absPath}")).default;`)
|
|
287
|
+
.join("\n");
|
|
288
|
+
return `
|
|
289
|
+
async function loadWasmChunk(chunkPath) {
|
|
290
|
+
switch (chunkPath) {
|
|
291
|
+
${cases}
|
|
292
|
+
default:
|
|
293
|
+
throw new Error(\`Unknown wasm chunk: \${chunkPath}\`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
`;
|
|
297
|
+
}
|
|
@@ -14,24 +14,23 @@ import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js";
|
|
|
14
14
|
*/
|
|
15
15
|
export function transformBuildCondition(conditionMap, condition) {
|
|
16
16
|
const transformed = {};
|
|
17
|
-
const hasTopLevelBuildCondition =
|
|
17
|
+
const hasTopLevelBuildCondition = condition in conditionMap && conditionMap[condition] != null;
|
|
18
18
|
let hasBuildCondition = hasTopLevelBuildCondition;
|
|
19
19
|
for (const [key, value] of Object.entries(conditionMap)) {
|
|
20
20
|
if (typeof value === "object" && value != null) {
|
|
21
21
|
const { transformedExports, hasBuildCondition: innerBuildCondition } = transformBuildCondition(value, condition);
|
|
22
|
+
// If a build condition is present at this level but a sibling
|
|
23
|
+
// subtree doesn't contain the build condition, we can drop it entirely.
|
|
24
|
+
if (hasTopLevelBuildCondition && key !== condition && !innerBuildCondition) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
22
27
|
transformed[key] = transformedExports;
|
|
23
28
|
hasBuildCondition ||= innerBuildCondition;
|
|
24
29
|
}
|
|
25
|
-
else {
|
|
26
|
-
// If
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
if (!hasTopLevelBuildCondition) {
|
|
30
|
-
transformed[key] = value;
|
|
31
|
-
}
|
|
32
|
-
else if (key === condition) {
|
|
33
|
-
transformed[key] = value;
|
|
34
|
-
}
|
|
30
|
+
else if (!hasTopLevelBuildCondition || key === condition) {
|
|
31
|
+
// If there is no build condition at this level or this is a non-object build condition,
|
|
32
|
+
// we need to keep the child condition as is.
|
|
33
|
+
transformed[key] = value;
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
return { transformedExports: transformed, hasBuildCondition };
|
|
@@ -97,13 +97,20 @@ async function migrateCommand(args) {
|
|
|
97
97
|
}
|
|
98
98
|
catch (error) {
|
|
99
99
|
logger.error("Failed to update package.json", error.message);
|
|
100
|
-
logger.warn(
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
logger.warn(`Please ensure that your package.json contains the following scripts:
|
|
101
|
+
${[...Object.entries(openNextScripts)].map(([k, v]) => ` - ${k}: ${v}`).join("\n")}
|
|
102
|
+
`);
|
|
103
103
|
}
|
|
104
104
|
const gitIgnoreExists = fs.existsSync(".gitignore");
|
|
105
105
|
printStepTitle(`${gitIgnoreExists ? "Updating" : "Creating"} .gitignore file`);
|
|
106
|
-
conditionalAppendFileSync(".gitignore",
|
|
106
|
+
conditionalAppendFileSync(".gitignore", `# OpenNext
|
|
107
|
+
.open-next
|
|
108
|
+
|
|
109
|
+
# wrangler files
|
|
110
|
+
.wrangler
|
|
111
|
+
.dev.vars*
|
|
112
|
+
!.dev.vars.example
|
|
113
|
+
`, {
|
|
107
114
|
appendIf: (content) => !content.includes(".open-next"),
|
|
108
115
|
appendPrefix: "\n",
|
|
109
116
|
});
|
|
@@ -404,7 +404,8 @@ function populateD1TagCache(buildOpts, config, populateCacheOptions) {
|
|
|
404
404
|
target: populateCacheOptions.target,
|
|
405
405
|
environment: populateCacheOptions.environment,
|
|
406
406
|
configPath: populateCacheOptions.wranglerConfigPath,
|
|
407
|
-
|
|
407
|
+
// Do not log errors since the ALTER TABLE command will fail if the columns already exist.
|
|
408
|
+
logging: "none",
|
|
408
409
|
});
|
|
409
410
|
logger.info("\nSuccessfully created D1 table");
|
|
410
411
|
}
|
|
@@ -34,7 +34,7 @@ export function findWranglerConfig(appDir) {
|
|
|
34
34
|
* @returns An object containing a `cachingEnabled` which indicates whether caching has been set up during the wrangler
|
|
35
35
|
* config file creation or not
|
|
36
36
|
*/
|
|
37
|
-
export async function createWranglerConfigFile(projectDir, defaultCompatDate = "2026-
|
|
37
|
+
export async function createWranglerConfigFile(projectDir, defaultCompatDate = "2026-04-15") {
|
|
38
38
|
const workerName = getWorkerName(projectDir);
|
|
39
39
|
const compatibilityDate = (await getLatestCompatDate()) ?? defaultCompatDate;
|
|
40
40
|
const wranglerConfigStr = readFileSync(join(getPackageTemplatesDirPath(), "wrangler.jsonc"), "utf8")
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opennextjs/cloudflare",
|
|
3
3
|
"description": "Cloudflare builder for next apps",
|
|
4
|
-
"version": "1.19.
|
|
4
|
+
"version": "1.19.6",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"opennextjs-cloudflare": "dist/cli/index.js"
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
80
|
"next": ">=15.5.15 <16 || >=16.2.3",
|
|
81
|
-
"wrangler": "^4.
|
|
81
|
+
"wrangler": "^4.86.0"
|
|
82
82
|
},
|
|
83
83
|
"scripts": {
|
|
84
84
|
"clean": "rimraf dist",
|