@opennextjs/cloudflare 1.6.2 → 1.6.4
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/cli/build/build.js +1 -8
- package/dist/cli/build/bundle-server.d.ts +2 -1
- package/dist/cli/build/bundle-server.js +7 -3
- package/dist/cli/build/patches/plugins/dynamic-requires.js +8 -12
- package/dist/cli/build/patches/plugins/find-dir.js +3 -5
- package/dist/cli/build/patches/plugins/instrumentation.js +11 -17
- package/dist/cli/build/patches/plugins/load-manifest.js +10 -12
- package/dist/cli/build/patches/plugins/next-server.d.ts +1 -0
- package/dist/cli/build/patches/plugins/next-server.js +26 -15
- package/dist/cli/build/patches/plugins/open-next.js +6 -8
- package/dist/cli/build/patches/plugins/patch-depd-deprecations.js +3 -5
- package/dist/cli/build/patches/plugins/require.js +36 -38
- package/dist/cli/build/patches/plugins/res-revalidate.js +5 -7
- package/dist/cli/build/patches/plugins/route-module.d.ts +24 -0
- package/dist/cli/build/patches/plugins/route-module.js +77 -0
- package/dist/cli/build/patches/plugins/use-cache.js +5 -7
- package/dist/cli/templates/images.d.ts +1 -1
- package/dist/cli/templates/images.js +28 -5
- package/package.json +2 -2
package/dist/cli/build/build.js
CHANGED
|
@@ -63,7 +63,7 @@ export async function build(options, config, projectOpts, wranglerConfig) {
|
|
|
63
63
|
}
|
|
64
64
|
await createServerBundle(options);
|
|
65
65
|
await compileDurableObjects(options);
|
|
66
|
-
await bundleServer(options);
|
|
66
|
+
await bundleServer(options, projectOpts);
|
|
67
67
|
if (!projectOpts.skipWranglerConfigCheck) {
|
|
68
68
|
await createWranglerConfigIfNotExistent(projectOpts);
|
|
69
69
|
}
|
|
@@ -74,11 +74,4 @@ function ensureNextjsVersionSupported(options) {
|
|
|
74
74
|
logger.error("Next.js version unsupported, please upgrade to version 14.2 or greater.");
|
|
75
75
|
process.exit(1);
|
|
76
76
|
}
|
|
77
|
-
// TODO: remove when 15.4 is supported
|
|
78
|
-
// Note: `e2e/experimental` is on 15.4.0-canary.14 which works
|
|
79
|
-
if (!options.appPath.endsWith("opennextjs-cloudflare/examples/e2e/experimental") &&
|
|
80
|
-
buildHelper.compareSemver(options.nextVersion, ">=", "15.4.0")) {
|
|
81
|
-
logger.error("Next.js version unsupported, the latest supported version is 15.3");
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
77
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type BuildOptions } from "@opennextjs/aws/build/helper.js";
|
|
2
|
+
import type { ProjectOptions } from "../project-options.js";
|
|
2
3
|
/**
|
|
3
4
|
* Bundle the Open Next server.
|
|
4
5
|
*/
|
|
5
|
-
export declare function bundleServer(buildOpts: BuildOptions): Promise<void>;
|
|
6
|
+
export declare function bundleServer(buildOpts: BuildOptions, projectOpts: ProjectOptions): Promise<void>;
|
|
6
7
|
/**
|
|
7
8
|
* This function apply updates to the bundled code.
|
|
8
9
|
*/
|
|
@@ -19,6 +19,7 @@ import { patchPagesRouterContext } from "./patches/plugins/pages-router-context.
|
|
|
19
19
|
import { patchDepdDeprecations } from "./patches/plugins/patch-depd-deprecations.js";
|
|
20
20
|
import { fixRequire } from "./patches/plugins/require.js";
|
|
21
21
|
import { shimRequireHook } from "./patches/plugins/require-hook.js";
|
|
22
|
+
import { patchRouteModules } from "./patches/plugins/route-module.js";
|
|
22
23
|
import { setWranglerExternal } from "./patches/plugins/wrangler-external.js";
|
|
23
24
|
import { copyPackageCliFiles, needsExperimentalReact, normalizePath } from "./utils/index.js";
|
|
24
25
|
/** The dist directory of the Cloudflare adapter package */
|
|
@@ -39,7 +40,7 @@ const optionalDependencies = [
|
|
|
39
40
|
/**
|
|
40
41
|
* Bundle the Open Next server.
|
|
41
42
|
*/
|
|
42
|
-
export async function bundleServer(buildOpts) {
|
|
43
|
+
export async function bundleServer(buildOpts, projectOpts) {
|
|
43
44
|
copyPackageCliFiles(packageDistDir, buildOpts);
|
|
44
45
|
const { appPath, outputDir, monorepoRoot, debug } = buildOpts;
|
|
45
46
|
const baseManifestPath = path.join(outputDir, "server-functions/default", getPackagePath(buildOpts), ".next");
|
|
@@ -60,9 +61,9 @@ export async function bundleServer(buildOpts) {
|
|
|
60
61
|
format: "esm",
|
|
61
62
|
target: "esnext",
|
|
62
63
|
// Minify code as much as possible but stay safe by not renaming identifiers
|
|
63
|
-
minifyWhitespace: !debug,
|
|
64
|
+
minifyWhitespace: projectOpts.minify && !debug,
|
|
64
65
|
minifyIdentifiers: false,
|
|
65
|
-
minifySyntax: !debug,
|
|
66
|
+
minifySyntax: projectOpts.minify && !debug,
|
|
66
67
|
legalComments: "none",
|
|
67
68
|
metafile: true,
|
|
68
69
|
// Next traces files using the default conditions from `nft` (`node`, `require`, `import` and `default`)
|
|
@@ -86,6 +87,7 @@ export async function bundleServer(buildOpts) {
|
|
|
86
87
|
inlineFindDir(updater, buildOpts),
|
|
87
88
|
inlineLoadManifest(updater, buildOpts),
|
|
88
89
|
patchNextServer(updater, buildOpts),
|
|
90
|
+
patchRouteModules(updater, buildOpts),
|
|
89
91
|
patchDepdDeprecations(updater),
|
|
90
92
|
patchResolveCache(updater, buildOpts),
|
|
91
93
|
// Apply updater updates, must be the last plugin
|
|
@@ -124,6 +126,8 @@ export async function bundleServer(buildOpts) {
|
|
|
124
126
|
"process.env.TURBOPACK": "false",
|
|
125
127
|
// This define should be safe to use for Next 14.2+, earlier versions (13.5 and less) will cause trouble
|
|
126
128
|
"process.env.__NEXT_EXPERIMENTAL_REACT": `${needsExperimentalReact(nextConfig)}`,
|
|
129
|
+
// Fix `res.validate` in Next 15.4 (together with the `route-module` patch)
|
|
130
|
+
"process.env.__NEXT_TRUST_HOST_HEADER": "true",
|
|
127
131
|
},
|
|
128
132
|
banner: {
|
|
129
133
|
// We need to import them here, assigning them to `globalThis` does not work because node:timers use `globalThis` and thus create an infinite loop
|
|
@@ -37,22 +37,18 @@ function getRequires(idVariable, files, serverDir) {
|
|
|
37
37
|
export function inlineDynamicRequires(updater, buildOpts) {
|
|
38
38
|
updater.updateContent("inline-node-module-loader", [
|
|
39
39
|
{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
callback: async ({ contents }) => patchCode(contents, await getNodeModuleLoaderRule(buildOpts)),
|
|
46
|
-
},
|
|
40
|
+
filter: getCrossPlatformPathRegex(String.raw `/module-loader/node-module-loader\.js$`, {
|
|
41
|
+
escape: false,
|
|
42
|
+
}),
|
|
43
|
+
contentFilter: /class NodeModuleLoader {/,
|
|
44
|
+
callback: async ({ contents }) => patchCode(contents, await getNodeModuleLoaderRule(buildOpts)),
|
|
47
45
|
},
|
|
48
46
|
]);
|
|
49
47
|
updater.updateContent("inline-require-page", [
|
|
50
48
|
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
callback: async ({ contents }) => patchCode(contents, await getRequirePageRule(buildOpts)),
|
|
55
|
-
},
|
|
49
|
+
filter: getCrossPlatformPathRegex(String.raw `/next/dist/server/require\.js$`, { escape: false }),
|
|
50
|
+
contentFilter: /function requirePage\(/,
|
|
51
|
+
callback: async ({ contents }) => patchCode(contents, await getRequirePageRule(buildOpts)),
|
|
56
52
|
},
|
|
57
53
|
]);
|
|
58
54
|
return { name: "inline-dynamic-requires", setup() { } };
|
|
@@ -9,11 +9,9 @@ import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js";
|
|
|
9
9
|
export function inlineFindDir(updater, buildOpts) {
|
|
10
10
|
return updater.updateContent("inline-find-dir", [
|
|
11
11
|
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
callback: async ({ contents }) => patchCode(contents, await getRule(buildOpts)),
|
|
16
|
-
},
|
|
12
|
+
filter: getCrossPlatformPathRegex(String.raw `/next/dist/lib/find-pages-dir\.js$`, { escape: false }),
|
|
13
|
+
contentFilter: /function findDir\(/,
|
|
14
|
+
callback: async ({ contents }) => patchCode(contents, await getRule(buildOpts)),
|
|
17
15
|
},
|
|
18
16
|
]);
|
|
19
17
|
}
|
|
@@ -8,31 +8,25 @@ export function patchInstrumentation(updater, buildOpts) {
|
|
|
8
8
|
const builtInstrumentationPath = getBuiltInstrumentationPath(buildOpts);
|
|
9
9
|
updater.updateContent("patch-instrumentation-next15-4", [
|
|
10
10
|
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
callback: ({ contents }) => patchCode(contents, getNext154Rule(builtInstrumentationPath)),
|
|
17
|
-
},
|
|
11
|
+
filter: getCrossPlatformPathRegex(String.raw `/server/lib/router-utils/instrumentation-globals.external\.js$`, {
|
|
12
|
+
escape: false,
|
|
13
|
+
}),
|
|
14
|
+
contentFilter: /getInstrumentationModule\(/,
|
|
15
|
+
callback: ({ contents }) => patchCode(contents, getNext154Rule(builtInstrumentationPath)),
|
|
18
16
|
},
|
|
19
17
|
]);
|
|
20
18
|
updater.updateContent("patch-instrumentation-next15", [
|
|
21
19
|
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
callback: ({ contents }) => patchCode(contents, getNext15Rule(builtInstrumentationPath)),
|
|
26
|
-
},
|
|
20
|
+
filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
|
|
21
|
+
contentFilter: /async loadInstrumentationModule\(/,
|
|
22
|
+
callback: ({ contents }) => patchCode(contents, getNext15Rule(builtInstrumentationPath)),
|
|
27
23
|
},
|
|
28
24
|
]);
|
|
29
25
|
updater.updateContent("patch-instrumentation-next14", [
|
|
30
26
|
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
callback: ({ contents }) => patchCode(contents, getNext14Rule(builtInstrumentationPath)),
|
|
35
|
-
},
|
|
27
|
+
filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
|
|
28
|
+
contentFilter: /async prepareImpl\(/,
|
|
29
|
+
callback: ({ contents }) => patchCode(contents, getNext14Rule(builtInstrumentationPath)),
|
|
36
30
|
},
|
|
37
31
|
]);
|
|
38
32
|
return {
|
|
@@ -13,16 +13,14 @@ import { normalizePath } from "../../utils/normalize-path.js";
|
|
|
13
13
|
export function inlineLoadManifest(updater, buildOpts) {
|
|
14
14
|
return updater.updateContent("inline-load-manifest", [
|
|
15
15
|
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return contents;
|
|
25
|
-
},
|
|
16
|
+
filter: getCrossPlatformPathRegex(String.raw `/next/dist/server/load-manifest(\.external)?\.js$`, {
|
|
17
|
+
escape: false,
|
|
18
|
+
}),
|
|
19
|
+
contentFilter: /function loadManifest\(/,
|
|
20
|
+
callback: async ({ contents }) => {
|
|
21
|
+
contents = await patchCode(contents, await getLoadManifestRule(buildOpts));
|
|
22
|
+
contents = await patchCode(contents, await getEvalManifestRule(buildOpts));
|
|
23
|
+
return contents;
|
|
26
24
|
},
|
|
27
25
|
},
|
|
28
26
|
]);
|
|
@@ -48,8 +46,8 @@ function loadManifest($PATH, $$$ARGS) {
|
|
|
48
46
|
fix: `
|
|
49
47
|
function loadManifest($PATH, $$$ARGS) {
|
|
50
48
|
$PATH = $PATH.replaceAll(${JSON.stringify(sep)}, ${JSON.stringify(posix.sep)});
|
|
51
|
-
if ($PATH
|
|
52
|
-
|
|
49
|
+
if ($PATH.endsWith(".next/BUILD_ID")) {
|
|
50
|
+
return process.env.NEXT_BUILD_ID;
|
|
53
51
|
}
|
|
54
52
|
${returnManifests}
|
|
55
53
|
throw new Error(\`Unexpected loadManifest(\${$PATH}) call!\`);
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { type BuildOptions } from "@opennextjs/aws/build/helper.js";
|
|
10
10
|
import type { ContentUpdater, Plugin } from "@opennextjs/aws/plugins/content-updater.js";
|
|
11
11
|
export declare function patchNextServer(updater: ContentUpdater, buildOpts: BuildOptions): Plugin;
|
|
12
|
+
export declare const disableNodeMiddlewareRule = "\nrule:\n pattern:\n selector: method_definition\n context: \"class { async loadNodeMiddleware($$$PARAMS) { $$$_ } }\"\nfix: |-\n async loadNodeMiddleware($$$PARAMS) {\n // patched by open next\n }\n";
|
|
12
13
|
export declare const buildIdRule = "\nrule:\n pattern:\n selector: method_definition\n context: \"class { getBuildId($$$PARAMS) { $$$_ } }\"\nfix: |-\n getBuildId($$$PARAMS) {\n return process.env.NEXT_BUILD_ID;\n }\n";
|
|
13
14
|
/**
|
|
14
15
|
* The cache handler used by Next.js is normally defined in the config file as a path. At runtime,
|
|
@@ -14,25 +14,36 @@ import { normalizePath } from "../../utils/index.js";
|
|
|
14
14
|
export function patchNextServer(updater, buildOpts) {
|
|
15
15
|
return updater.updateContent("next-server", [
|
|
16
16
|
{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
17
|
+
filter: getCrossPlatformPathRegex(String.raw `/next/dist/server/next-server\.js$`, {
|
|
18
|
+
escape: false,
|
|
19
|
+
}),
|
|
20
|
+
contentFilter: /getBuildId\(/,
|
|
21
|
+
callback: async ({ contents }) => {
|
|
22
|
+
const { outputDir } = buildOpts;
|
|
23
|
+
contents = patchCode(contents, buildIdRule);
|
|
24
|
+
const outputPath = path.join(outputDir, "server-functions/default");
|
|
25
|
+
const cacheHandler = path.join(outputPath, getPackagePath(buildOpts), "cache.cjs");
|
|
26
|
+
contents = patchCode(contents, createCacheHandlerRule(cacheHandler));
|
|
27
|
+
const composableCacheHandler = path.join(outputPath, getPackagePath(buildOpts), "composable-cache.cjs");
|
|
28
|
+
contents = patchCode(contents, createComposableCacheHandlersRule(composableCacheHandler));
|
|
29
|
+
// Node middleware are not supported on Cloudflare yet
|
|
30
|
+
contents = patchCode(contents, disableNodeMiddlewareRule);
|
|
31
|
+
return contents;
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
34
|
]);
|
|
35
35
|
}
|
|
36
|
+
// Do not try to load Node middlewares
|
|
37
|
+
export const disableNodeMiddlewareRule = `
|
|
38
|
+
rule:
|
|
39
|
+
pattern:
|
|
40
|
+
selector: method_definition
|
|
41
|
+
context: "class { async loadNodeMiddleware($$$PARAMS) { $$$_ } }"
|
|
42
|
+
fix: |-
|
|
43
|
+
async loadNodeMiddleware($$$PARAMS) {
|
|
44
|
+
// patched by open next
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
36
47
|
export const buildIdRule = `
|
|
37
48
|
rule:
|
|
38
49
|
pattern:
|
|
@@ -12,14 +12,12 @@ export function patchResolveCache(updater, buildOpts) {
|
|
|
12
12
|
const indexPath = path.relative(buildOpts.appBuildOutputPath, path.join(outputPath, packagePath, `index.mjs`));
|
|
13
13
|
return updater.updateContent("patch-resolve-cache", [
|
|
14
14
|
{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return contents;
|
|
22
|
-
},
|
|
15
|
+
filter: getCrossPlatformPathRegex(indexPath),
|
|
16
|
+
contentFilter: /cacheHandlerPath/,
|
|
17
|
+
callback: async ({ contents }) => {
|
|
18
|
+
contents = patchCode(contents, cacheHandlerRule);
|
|
19
|
+
contents = patchCode(contents, compositeCacheHandlerRule);
|
|
20
|
+
return contents;
|
|
23
21
|
},
|
|
24
22
|
},
|
|
25
23
|
]);
|
|
@@ -8,11 +8,9 @@ import { patchCode } from "@opennextjs/aws/build/patch/astCodePatcher.js";
|
|
|
8
8
|
export function patchDepdDeprecations(updater) {
|
|
9
9
|
return updater.updateContent("patch-depd-deprecations", [
|
|
10
10
|
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
callback: ({ contents }) => patchCode(contents, rule),
|
|
15
|
-
},
|
|
11
|
+
filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
|
|
12
|
+
contentFilter: /argument fn must be a function/,
|
|
13
|
+
callback: ({ contents }) => patchCode(contents, rule),
|
|
16
14
|
},
|
|
17
15
|
]);
|
|
18
16
|
}
|
|
@@ -1,44 +1,42 @@
|
|
|
1
1
|
export function fixRequire(updater) {
|
|
2
2
|
return updater.updateContent("fix-require", [
|
|
3
3
|
{
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return contents;
|
|
41
|
-
},
|
|
4
|
+
filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
|
|
5
|
+
contentFilter: /.*/,
|
|
6
|
+
callback: ({ contents }) => {
|
|
7
|
+
// `eval(...)` is not supported by workerd.
|
|
8
|
+
contents = contents.replaceAll(`eval("require")`, "require");
|
|
9
|
+
// `@opentelemetry` has a few issues.
|
|
10
|
+
//
|
|
11
|
+
// Next.js has the following code in `next/dist/server/lib/trace/tracer.js`:
|
|
12
|
+
//
|
|
13
|
+
// try {
|
|
14
|
+
// api = require('@opentelemetry/api');
|
|
15
|
+
// } catch (err) {
|
|
16
|
+
// api = require('next/dist/compiled/@opentelemetry/api');
|
|
17
|
+
// }
|
|
18
|
+
//
|
|
19
|
+
// The intent is to allow users to install their own version of `@opentelemetry/api`.
|
|
20
|
+
//
|
|
21
|
+
// The problem is that even when users do not explicitly install `@opentelemetry/api`,
|
|
22
|
+
// `require('@opentelemetry/api')` resolves to the package which is a dependency
|
|
23
|
+
// of Next.
|
|
24
|
+
//
|
|
25
|
+
// The second problem is that when Next traces files, it would not copy the `api/build/esm`
|
|
26
|
+
// folder (used by the `module` conditions in package.json) it would only copy `api/build/src`.
|
|
27
|
+
// This could be solved by updating the next config:
|
|
28
|
+
//
|
|
29
|
+
// const nextConfig: NextConfig = {
|
|
30
|
+
// // ...
|
|
31
|
+
// outputFileTracingIncludes: {
|
|
32
|
+
// "*": ["./node_modules/@opentelemetry/api/build/**/*"],
|
|
33
|
+
// },
|
|
34
|
+
// };
|
|
35
|
+
//
|
|
36
|
+
// We can consider doing that when we want to enable users to install their own version
|
|
37
|
+
// of `@opentelemetry/api`. For now we simply use the pre-compiled version.
|
|
38
|
+
contents = contents.replace(/require\(.@opentelemetry\/api.\)/g, `require("next/dist/compiled/@opentelemetry/api")`);
|
|
39
|
+
return contents;
|
|
42
40
|
},
|
|
43
41
|
},
|
|
44
42
|
]);
|
|
@@ -65,13 +65,11 @@ export const patchResRevalidate = {
|
|
|
65
65
|
patches: [
|
|
66
66
|
{
|
|
67
67
|
versions: ">=14.2.0",
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
patchCode: async ({ code }) => patchCode(code, rule),
|
|
74
|
-
},
|
|
68
|
+
pathFilter: getCrossPlatformPathRegex(String.raw `(pages-api\.runtime\.prod\.js|node/api-resolver\.js)$`, {
|
|
69
|
+
escape: false,
|
|
70
|
+
}),
|
|
71
|
+
contentFilter: /\.trustHostHeader/,
|
|
72
|
+
patchCode: async ({ code }) => patchCode(code, rule),
|
|
75
73
|
},
|
|
76
74
|
],
|
|
77
75
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch for `next/src/server/route-modules/route-module.ts`
|
|
3
|
+
* https://github.com/vercel/next.js/blob/c8c9bef/packages/next/src/server/route-modules/route-module.ts#L389-L437
|
|
4
|
+
*
|
|
5
|
+
* Patch getIncrementalCache to use a string literal for the cache handler path
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import { BuildOptions } from "@opennextjs/aws/build/helper.js";
|
|
9
|
+
import type { ContentUpdater, Plugin } from "@opennextjs/aws/plugins/content-updater.js";
|
|
10
|
+
export declare function patchRouteModules(updater: ContentUpdater, buildOpts: BuildOptions): Plugin;
|
|
11
|
+
/**
|
|
12
|
+
* The cache handler used by Next.js is normally defined in the config file as a path. At runtime,
|
|
13
|
+
* Next.js would then do a dynamic require on a transformed version of the path to retrieve the
|
|
14
|
+
* cache handler and create a new instance of it.
|
|
15
|
+
*
|
|
16
|
+
* This is problematic in workerd due to the dynamic import of the file that is not known from
|
|
17
|
+
* build-time. Therefore, we have to manually override the default way that the cache handler is
|
|
18
|
+
* instantiated with a dynamic require that uses a string literal for the path.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getIncrementalCacheRule(handlerPath: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Force trustHostHeader to be true for revalidation
|
|
23
|
+
*/
|
|
24
|
+
export declare const forceTrustHostHeader = "\nrule:\n pattern: async function $FN($$$ARGS) { $$$BODY }\n all:\n - has:\n pattern: if ($CONTEXT.trustHostHeader) { $$$_ }\n stopBy: end\n - has:\n regex: \"^x-vercel-protection-bypass$\"\n stopBy: end\n - has:\n regex: \"Invariant: missing internal\"\n stopBy: end\nfix: |-\n async function $FN($$$ARGS) {\n $CONTEXT.trustHostHeader = true;\n $$$BODY\n }\n";
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch for `next/src/server/route-modules/route-module.ts`
|
|
3
|
+
* https://github.com/vercel/next.js/blob/c8c9bef/packages/next/src/server/route-modules/route-module.ts#L389-L437
|
|
4
|
+
*
|
|
5
|
+
* Patch getIncrementalCache to use a string literal for the cache handler path
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { getPackagePath } from "@opennextjs/aws/build/helper.js";
|
|
10
|
+
import { patchCode } from "@opennextjs/aws/build/patch/astCodePatcher.js";
|
|
11
|
+
import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js";
|
|
12
|
+
import { normalizePath } from "../../utils/index.js";
|
|
13
|
+
export function patchRouteModules(updater, buildOpts) {
|
|
14
|
+
return updater.updateContent("route-module", [
|
|
15
|
+
{
|
|
16
|
+
filter: getCrossPlatformPathRegex(String.raw `/next/dist/compiled/next-server/.*?\.runtime\.prod\.js$`, {
|
|
17
|
+
escape: false,
|
|
18
|
+
}),
|
|
19
|
+
versions: ">=15.4.0",
|
|
20
|
+
contentFilter: /getIncrementalCache\(/,
|
|
21
|
+
callback: async ({ contents }) => {
|
|
22
|
+
const { outputDir } = buildOpts;
|
|
23
|
+
const outputPath = path.join(outputDir, "server-functions/default");
|
|
24
|
+
const cacheHandler = path.join(outputPath, getPackagePath(buildOpts), "cache.cjs");
|
|
25
|
+
contents = patchCode(contents, getIncrementalCacheRule(cacheHandler));
|
|
26
|
+
contents = patchCode(contents, forceTrustHostHeader);
|
|
27
|
+
return contents;
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
]);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The cache handler used by Next.js is normally defined in the config file as a path. At runtime,
|
|
34
|
+
* Next.js would then do a dynamic require on a transformed version of the path to retrieve the
|
|
35
|
+
* cache handler and create a new instance of it.
|
|
36
|
+
*
|
|
37
|
+
* This is problematic in workerd due to the dynamic import of the file that is not known from
|
|
38
|
+
* build-time. Therefore, we have to manually override the default way that the cache handler is
|
|
39
|
+
* instantiated with a dynamic require that uses a string literal for the path.
|
|
40
|
+
*/
|
|
41
|
+
export function getIncrementalCacheRule(handlerPath) {
|
|
42
|
+
return `
|
|
43
|
+
rule:
|
|
44
|
+
pattern: "let $CACHE_HANDLER, { cacheHandler: $HANDLER_PATH } = $C"
|
|
45
|
+
inside:
|
|
46
|
+
kind: method_definition
|
|
47
|
+
has:
|
|
48
|
+
field: name
|
|
49
|
+
regex: ^getIncrementalCache$
|
|
50
|
+
stopBy: end
|
|
51
|
+
fix: |-
|
|
52
|
+
const $HANDLER_PATH = null;
|
|
53
|
+
let $CACHE_HANDLER = require('${normalizePath(handlerPath)}').default;
|
|
54
|
+
`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Force trustHostHeader to be true for revalidation
|
|
58
|
+
*/
|
|
59
|
+
export const forceTrustHostHeader = `
|
|
60
|
+
rule:
|
|
61
|
+
pattern: async function $FN($$$ARGS) { $$$BODY }
|
|
62
|
+
all:
|
|
63
|
+
- has:
|
|
64
|
+
pattern: if ($CONTEXT.trustHostHeader) { $$$_ }
|
|
65
|
+
stopBy: end
|
|
66
|
+
- has:
|
|
67
|
+
regex: "^x-vercel-protection-bypass$"
|
|
68
|
+
stopBy: end
|
|
69
|
+
- has:
|
|
70
|
+
regex: "Invariant: missing internal"
|
|
71
|
+
stopBy: end
|
|
72
|
+
fix: |-
|
|
73
|
+
async function $FN($$$ARGS) {
|
|
74
|
+
$CONTEXT.trustHostHeader = true;
|
|
75
|
+
$$$BODY
|
|
76
|
+
}
|
|
77
|
+
`;
|
|
@@ -28,13 +28,11 @@ export const patchUseCacheIO = {
|
|
|
28
28
|
patches: [
|
|
29
29
|
{
|
|
30
30
|
versions: ">=15.3.1",
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
patchCode: async ({ code }) => patchCode(code, rule),
|
|
37
|
-
},
|
|
31
|
+
pathFilter: getCrossPlatformPathRegex(String.raw `server/app-render/async-local-storage\.js$`, {
|
|
32
|
+
escape: false,
|
|
33
|
+
}),
|
|
34
|
+
contentFilter: /createSnapshot/,
|
|
35
|
+
patchCode: async ({ code }) => patchCode(code, rule),
|
|
38
36
|
},
|
|
39
37
|
],
|
|
40
38
|
};
|
|
@@ -26,7 +26,7 @@ export declare function matchLocalPattern(pattern: LocalPattern, url: URL): bool
|
|
|
26
26
|
* @param buffer The image bytes
|
|
27
27
|
* @returns a content type of undefined for unsupported content
|
|
28
28
|
*/
|
|
29
|
-
export declare function detectContentType(buffer: Uint8Array): "image/svg+xml" | "image/jpeg" | "image/png" | "image/gif" | "image/webp" | "image/avif" | "image/x-icon" | "image/x-icns" | "image/tiff" | "image/bmp" | undefined;
|
|
29
|
+
export declare function detectContentType(buffer: Uint8Array): "image/svg+xml" | "image/jpeg" | "image/png" | "image/gif" | "image/webp" | "image/avif" | "image/x-icon" | "image/x-icns" | "image/tiff" | "image/bmp" | "image/jxl" | "image/heic" | "application/pdf" | "image/jp2" | undefined;
|
|
30
30
|
declare global {
|
|
31
31
|
var __IMAGES_REMOTE_PATTERNS__: RemotePattern[];
|
|
32
32
|
var __IMAGES_LOCAL_PATTERNS__: LocalPattern[];
|
|
@@ -65,12 +65,15 @@ export async function fetchImage(fetcher, imageUrl, ctx) {
|
|
|
65
65
|
contentType = detectContentType(value);
|
|
66
66
|
}
|
|
67
67
|
if (!contentType) {
|
|
68
|
-
// Fallback to
|
|
68
|
+
// Fallback to upstream header when the type can not be detected
|
|
69
69
|
// https://github.com/vercel/next.js/blob/d76f0b1/packages/next/src/server/image-optimizer.ts#L748
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
contentType = imgResponse.headers.get("content-type") ?? "";
|
|
71
|
+
}
|
|
72
|
+
// Sanitize the content type:
|
|
73
|
+
// - Accept images only
|
|
74
|
+
// - Reject multiple content types
|
|
75
|
+
if (!contentType.startsWith("image/") || contentType.includes(",")) {
|
|
76
|
+
contentType = undefined;
|
|
74
77
|
}
|
|
75
78
|
if (contentType && !(contentType === SVG && !__IMAGES_ALLOW_SVG__)) {
|
|
76
79
|
const headers = new Headers(imgResponse.headers);
|
|
@@ -126,12 +129,17 @@ const AVIF = "image/avif";
|
|
|
126
129
|
const WEBP = "image/webp";
|
|
127
130
|
const PNG = "image/png";
|
|
128
131
|
const JPEG = "image/jpeg";
|
|
132
|
+
const JXL = "image/jxl";
|
|
133
|
+
const JP2 = "image/jp2";
|
|
134
|
+
const HEIC = "image/heic";
|
|
129
135
|
const GIF = "image/gif";
|
|
130
136
|
const SVG = "image/svg+xml";
|
|
131
137
|
const ICO = "image/x-icon";
|
|
132
138
|
const ICNS = "image/x-icns";
|
|
133
139
|
const TIFF = "image/tiff";
|
|
134
140
|
const BMP = "image/bmp";
|
|
141
|
+
// pdf will be rejected (not an `image/...` type)
|
|
142
|
+
const PDF = "application/pdf";
|
|
135
143
|
/**
|
|
136
144
|
* Detects the content type by looking at the first few bytes of a file
|
|
137
145
|
*
|
|
@@ -174,4 +182,19 @@ export function detectContentType(buffer) {
|
|
|
174
182
|
if ([0x42, 0x4d].every((b, i) => buffer[i] === b)) {
|
|
175
183
|
return BMP;
|
|
176
184
|
}
|
|
185
|
+
if ([0xff, 0x0a].every((b, i) => buffer[i] === b)) {
|
|
186
|
+
return JXL;
|
|
187
|
+
}
|
|
188
|
+
if ([0x00, 0x00, 0x00, 0x0c, 0x4a, 0x58, 0x4c, 0x20, 0x0d, 0x0a, 0x87, 0x0a].every((b, i) => buffer[i] === b)) {
|
|
189
|
+
return JXL;
|
|
190
|
+
}
|
|
191
|
+
if ([0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63].every((b, i) => !b || buffer[i] === b)) {
|
|
192
|
+
return HEIC;
|
|
193
|
+
}
|
|
194
|
+
if ([0x25, 0x50, 0x44, 0x46, 0x2d].every((b, i) => buffer[i] === b)) {
|
|
195
|
+
return PDF;
|
|
196
|
+
}
|
|
197
|
+
if ([0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a].every((b, i) => buffer[i] === b)) {
|
|
198
|
+
return JP2;
|
|
199
|
+
}
|
|
177
200
|
}
|
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.6.
|
|
4
|
+
"version": "1.6.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"opennextjs-cloudflare": "dist/cli/index.js"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"homepage": "https://github.com/opennextjs/opennextjs-cloudflare",
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@dotenvx/dotenvx": "1.31.0",
|
|
46
|
-
"@opennextjs/aws": "3.7.
|
|
46
|
+
"@opennextjs/aws": "3.7.4",
|
|
47
47
|
"cloudflare": "^4.4.1",
|
|
48
48
|
"enquirer": "^2.4.1",
|
|
49
49
|
"glob": "^11.0.0",
|