Skip to content

Commit c9705e5

Browse files
sommeeeervicb
andauthored
Update the patches for Next 15.4 (#833)
Co-authored-by: Victor Berchet <[email protected]>
1 parent cb577a1 commit c9705e5

File tree

14 files changed

+839
-222
lines changed

14 files changed

+839
-222
lines changed

.changeset/rude-sloths-march.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@opennextjs/cloudflare": patch
3+
---
4+
5+
Update the patches to support Next.js 15.4"

examples/e2e/app-router/e2e/og.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { expect, test } from "@playwright/test";
22
import { validateMd5 } from "../../utils";
33

44
// This is the md5sums of the expected PNGs generated with `md5sum <file>`
5-
const OG_MD5 = "6e5e794ac0c27598a331690f96f05d00";
6-
const API_OG_MD5 = "cac95fc3e2d4d52870c0536bb18ba85b";
5+
const OG_MD5 = "83cfda4e78b037aa3d9ab465292550ef";
6+
const API_OG_MD5 = "6a22b4ff74e0dd8c377e2640dafe3e40";
77

88
test("Open-graph image to be in metatags and present", async ({ page, request }) => {
99
await page.goto("/og");

examples/e2e/experimental/next.config.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@ const nextConfig: NextConfig = {
1212
ignoreBuildErrors: true,
1313
},
1414
experimental: {
15-
ppr: "incremental",
16-
// Node middleware is not supported yet in cloudflare
17-
// See https://github.com/opennextjs/opennextjs-cloudflare/issues/617
18-
// nodeMiddleware: true,
19-
dynamicIO: true,
15+
cacheComponents: true,
2016
},
2117
};
2218

examples/e2e/experimental/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
},
1616
"dependencies": {
1717
"@opennextjs/cloudflare": "workspace:*",
18-
"next": "15.4.0-canary.14",
18+
"next": "15.4.2-canary.29",
1919
"react": "catalog:e2e",
2020
"react-dom": "catalog:e2e"
2121
},

examples/playground15/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"cf-typegen": "wrangler types --env-interface CloudflareEnv"
1717
},
1818
"dependencies": {
19-
"next": "^15.3.5",
19+
"next": "^15.4.5",
2020
"react": "^19.0.0",
2121
"react-dom": "^19.0.0"
2222
},

packages/cloudflare/src/cli/build/build.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,4 @@ function ensureNextjsVersionSupported(options: buildHelper.BuildOptions) {
9797
logger.error("Next.js version unsupported, please upgrade to version 14.2 or greater.");
9898
process.exit(1);
9999
}
100-
// TODO: remove when 15.4 is supported
101-
// Note: `e2e/experimental` is on 15.4.0-canary.14 which works
102-
if (
103-
!options.appPath.endsWith("opennextjs-cloudflare/examples/e2e/experimental") &&
104-
buildHelper.compareSemver(options.nextVersion, ">=", "15.4.0")
105-
) {
106-
logger.error("Next.js version unsupported, the latest supported version is 15.3");
107-
process.exit(1);
108-
}
109100
}

packages/cloudflare/src/cli/build/bundle-server.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { patchPagesRouterContext } from "./patches/plugins/pages-router-context.
2222
import { patchDepdDeprecations } from "./patches/plugins/patch-depd-deprecations.js";
2323
import { fixRequire } from "./patches/plugins/require.js";
2424
import { shimRequireHook } from "./patches/plugins/require-hook.js";
25+
import { patchRouteModules } from "./patches/plugins/route-module.js";
2526
import { setWranglerExternal } from "./patches/plugins/wrangler-external.js";
2627
import { copyPackageCliFiles, needsExperimentalReact, normalizePath } from "./utils/index.js";
2728

@@ -103,6 +104,7 @@ export async function bundleServer(buildOpts: BuildOptions, projectOpts: Project
103104
inlineFindDir(updater, buildOpts),
104105
inlineLoadManifest(updater, buildOpts),
105106
patchNextServer(updater, buildOpts),
107+
patchRouteModules(updater, buildOpts),
106108
patchDepdDeprecations(updater),
107109
patchResolveCache(updater, buildOpts),
108110
// Apply updater updates, must be the last plugin
@@ -147,6 +149,8 @@ export async function bundleServer(buildOpts: BuildOptions, projectOpts: Project
147149
"process.env.TURBOPACK": "false",
148150
// This define should be safe to use for Next 14.2+, earlier versions (13.5 and less) will cause trouble
149151
"process.env.__NEXT_EXPERIMENTAL_REACT": `${needsExperimentalReact(nextConfig)}`,
152+
// Fix `res.validate` in Next 15.4 (together with the `route-module` patch)
153+
"process.env.__NEXT_TRUST_HOST_HEADER": "true",
150154
},
151155
banner: {
152156
// We need to import them here, assigning them to `globalThis` does not work because node:timers use `globalThis` and thus create an infinite loop

packages/cloudflare/src/cli/build/patches/plugins/load-manifest.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ function loadManifest($PATH, $$$ARGS) {
6262
fix: `
6363
function loadManifest($PATH, $$$ARGS) {
6464
$PATH = $PATH.replaceAll(${JSON.stringify(sep)}, ${JSON.stringify(posix.sep)});
65-
if ($PATH === "/.next/BUILD_ID") {
66-
return process.env.NEXT_BUILD_ID;
65+
if ($PATH.endsWith(".next/BUILD_ID")) {
66+
return process.env.NEXT_BUILD_ID;
6767
}
6868
${returnManifests}
6969
throw new Error(\`Unexpected loadManifest(\${$PATH}) call!\`);

packages/cloudflare/src/cli/build/patches/plugins/next-server.spec.ts

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { describe, expect, test } from "vitest";
22

33
import { computePatchDiff } from "../../utils/test-patch.js";
4-
import { buildIdRule, createCacheHandlerRule, createComposableCacheHandlersRule } from "./next-server.js";
4+
import {
5+
buildIdRule,
6+
createCacheHandlerRule,
7+
createComposableCacheHandlersRule,
8+
disableNodeMiddlewareRule,
9+
} from "./next-server.js";
510

611
describe("Next Server", () => {
712
const nextServerCode = `
@@ -85,6 +90,22 @@ class NextNodeServer extends _baseserver.default {
8590
pages: (0, _findpagesdir.findDir)(dir, "pages") ? true : false
8691
};
8792
}
93+
async loadNodeMiddleware() {
94+
if (!process.env.NEXT_MINIMAL) {
95+
try {
96+
var _functionsConfig_functions;
97+
const functionsConfig = this.renderOpts.dev ? {} : require((0, _path.join)(this.distDir, 'server', _constants.FUNCTIONS_CONFIG_MANIFEST));
98+
if (this.renderOpts.dev || (functionsConfig == null ? void 0 : (_functionsConfig_functions = functionsConfig.functions) == null ? void 0 : _functionsConfig_functions['/_middleware'])) {
99+
// if used with top level await, this will be a promise
100+
return require((0, _path.join)(this.distDir, 'server', 'middleware.js'));
101+
}
102+
} catch (err) {
103+
if ((0, _iserror.default)(err) && err.code !== 'ENOENT' && err.code !== 'MODULE_NOT_FOUND') {
104+
throw err;
105+
}
106+
}
107+
}
108+
}
88109
// ...
89110
}`;
90111

@@ -187,4 +208,46 @@ class NextNodeServer extends _baseserver.default {
187208
"
188209
`);
189210
});
211+
212+
test("disable node middleware", () => {
213+
expect(computePatchDiff("next-server.js", nextServerCode, disableNodeMiddlewareRule))
214+
.toMatchInlineSnapshot(`
215+
"Index: next-server.js
216+
===================================================================
217+
--- next-server.js
218+
+++ next-server.js
219+
@@ -1,5 +1,4 @@
220+
-
221+
class NextNodeServer extends _baseserver.default {
222+
constructor(options){
223+
// Initialize super class
224+
super(options);
225+
@@ -79,21 +78,8 @@
226+
pages: (0, _findpagesdir.findDir)(dir, "pages") ? true : false
227+
};
228+
}
229+
async loadNodeMiddleware() {
230+
- if (!process.env.NEXT_MINIMAL) {
231+
- try {
232+
- var _functionsConfig_functions;
233+
- const functionsConfig = this.renderOpts.dev ? {} : require((0, _path.join)(this.distDir, 'server', _constants.FUNCTIONS_CONFIG_MANIFEST));
234+
- if (this.renderOpts.dev || (functionsConfig == null ? void 0 : (_functionsConfig_functions = functionsConfig.functions) == null ? void 0 : _functionsConfig_functions['/_middleware'])) {
235+
- // if used with top level await, this will be a promise
236+
- return require((0, _path.join)(this.distDir, 'server', 'middleware.js'));
237+
- }
238+
- } catch (err) {
239+
- if ((0, _iserror.default)(err) && err.code !== 'ENOENT' && err.code !== 'MODULE_NOT_FOUND') {
240+
- throw err;
241+
- }
242+
- }
243+
- }
244+
- }
245+
+ // patched by open next
246+
+}
247+
// ...
248+
}
249+
\\ No newline at end of file
250+
"
251+
`);
252+
});
190253
});

packages/cloudflare/src/cli/build/patches/plugins/next-server.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,28 @@ export function patchNextServer(updater: ContentUpdater, buildOpts: BuildOptions
3838
"composable-cache.cjs"
3939
);
4040
contents = patchCode(contents, createComposableCacheHandlersRule(composableCacheHandler));
41+
42+
// Node middleware are not supported on Cloudflare yet
43+
contents = patchCode(contents, disableNodeMiddlewareRule);
44+
4145
return contents;
4246
},
4347
},
4448
]);
4549
}
4650

51+
// Do not try to load Node middlewares
52+
export const disableNodeMiddlewareRule = `
53+
rule:
54+
pattern:
55+
selector: method_definition
56+
context: "class { async loadNodeMiddleware($$$PARAMS) { $$$_ } }"
57+
fix: |-
58+
async loadNodeMiddleware($$$PARAMS) {
59+
// patched by open next
60+
}
61+
`;
62+
4763
export const buildIdRule = `
4864
rule:
4965
pattern:

0 commit comments

Comments
 (0)