@opennextjs/cloudflare 0.3.4 → 0.3.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/cli/build/index.js +7 -0
- package/dist/cli/build/open-next/createServerBundle.js +1 -2
- package/dist/cli/build/patches/to-investigate/patch-exception-bubbling.js +9 -1
- package/dist/cli/build/patches/to-investigate/wrangler-deps.js +92 -0
- package/dist/cli/templates/worker.js +0 -3
- package/package.json +2 -2
package/dist/cli/build/index.js
CHANGED
|
@@ -42,6 +42,7 @@ export async function build(projectOpts) {
|
|
|
42
42
|
buildHelper.checkRunningInsideNextjsApp(options);
|
|
43
43
|
logger.info(`App directory: ${options.appPath}`);
|
|
44
44
|
buildHelper.printNextjsVersion(options);
|
|
45
|
+
ensureNextjsVersionSupported(options);
|
|
45
46
|
buildHelper.printOpenNextVersion(options);
|
|
46
47
|
if (projectOpts.skipNextBuild) {
|
|
47
48
|
logger.warn("Skipping Next.js build");
|
|
@@ -209,3 +210,9 @@ export async function getLatestCompatDate() {
|
|
|
209
210
|
/* empty */
|
|
210
211
|
}
|
|
211
212
|
}
|
|
213
|
+
function ensureNextjsVersionSupported(options) {
|
|
214
|
+
if (buildHelper.compareSemver(options.nextVersion, "14.0.0") < 0) {
|
|
215
|
+
logger.error("Next.js version unsupported, please upgrade to version 14 or greater.");
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -127,8 +127,7 @@ async function generateBundle(name, options, fnOptions) {
|
|
|
127
127
|
target: /core(\/|\\)util\.js/g,
|
|
128
128
|
deletes: [
|
|
129
129
|
...(disableNextPrebundledReact ? ["requireHooks"] : []),
|
|
130
|
-
...(
|
|
131
|
-
...(!isBefore13413 ? ["requestHandlerHost"] : []),
|
|
130
|
+
...(isBefore13413 ? ["trustHostHeader"] : ["requestHandlerHost"]),
|
|
132
131
|
...(isAfter141 ? ["experimentalIncrementalCacheHandler"] : ["stableIncrementalCache"]),
|
|
133
132
|
],
|
|
134
133
|
}),
|
|
@@ -5,5 +5,13 @@
|
|
|
5
5
|
* promises.
|
|
6
6
|
*/
|
|
7
7
|
export function patchExceptionBubbling(code) {
|
|
8
|
-
|
|
8
|
+
// The code before had: `query._nextBubbleNoFallback = '1'`, that has ben refactored to
|
|
9
|
+
// `addRequestMeta(req, 'bubbleNoFallback', true)` in https://github.com/vercel/next.js/pull/74100
|
|
10
|
+
// we need to support both for backward compatibility, that's why we have the following if statement
|
|
11
|
+
if (code.includes("_nextBubbleNoFallback")) {
|
|
12
|
+
return code.replace('_nextBubbleNoFallback = "1"', "_nextBubbleNoFallback = undefined");
|
|
13
|
+
}
|
|
14
|
+
// The Next.js transpiled code contains something like `(0, _requestmeta.addRequestMeta)(req, "bubbleNoFallback", true);`
|
|
15
|
+
// and we want to update it to `(0, _requestmeta.addRequestMeta)(req, "bubbleNoFallback", false);`
|
|
16
|
+
return code.replace(/\((.*?.addRequestMeta\)\(.*?,\s+"bubbleNoFallback"),\s+true\)/, "($1, false)");
|
|
9
17
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import * as ts from "ts-morph";
|
|
4
|
+
import { tsParseFile } from "../../utils/index.js";
|
|
3
5
|
export function patchWranglerDeps(config) {
|
|
4
6
|
console.log("# patchWranglerDeps");
|
|
5
7
|
const distPath = getDistPath(config);
|
|
@@ -13,6 +15,7 @@ export function patchWranglerDeps(config) {
|
|
|
13
15
|
const pagesRuntimeFile = join(distPath, "compiled", "next-server", "pages.runtime.prod.js");
|
|
14
16
|
const patchedPagesRuntime = readFileSync(pagesRuntimeFile, "utf-8").replace(`e.exports=require("critters")`, `e.exports={}`);
|
|
15
17
|
writeFileSync(pagesRuntimeFile, patchedPagesRuntime);
|
|
18
|
+
patchRequireReactDomServerEdge(config);
|
|
16
19
|
// Patch .next/standalone/node_modules/next/dist/server/lib/trace/tracer.js
|
|
17
20
|
//
|
|
18
21
|
// Remove the need for an alias in wrangler.toml:
|
|
@@ -52,3 +55,92 @@ function getDistPath(config) {
|
|
|
52
55
|
}
|
|
53
56
|
throw new Error("Unexpected error: unable to detect the node_modules/next/dist directory");
|
|
54
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* `react-dom` v>=19 has a `server.edge` export: https://github.com/facebook/react/blob/a160102f3/packages/react-dom/package.json#L79
|
|
60
|
+
* but version of `react-dom` <= 18 do not have this export but have a `server.browser` export instead: https://github.com/facebook/react/blob/8a015b68/packages/react-dom/package.json#L49
|
|
61
|
+
*
|
|
62
|
+
* Next.js also try-catches importing the `server.edge` export:
|
|
63
|
+
* https://github.com/vercel/next.js/blob/6784575/packages/next/src/server/ReactDOMServerPages.js
|
|
64
|
+
*
|
|
65
|
+
* The issue here is that in the `.next/standalone/node_modules/next/dist/compiled/next-server/pages.runtime.prod.js`
|
|
66
|
+
* file for whatever reason there is a non `try-catch`ed require for the `server.edge` export
|
|
67
|
+
*
|
|
68
|
+
* This functions fixes this issue by wrapping the require in a try-catch block in the same way Next.js does it
|
|
69
|
+
* (note: this will make the build succeed but doesn't guarantee that everything will necessarily work at runtime since
|
|
70
|
+
* it's not clear what code and how might be rely on this require call)
|
|
71
|
+
*
|
|
72
|
+
*/
|
|
73
|
+
function patchRequireReactDomServerEdge(config) {
|
|
74
|
+
const distPath = getDistPath(config);
|
|
75
|
+
// Patch .next/standalone/node_modules/next/dist/compiled/next-server/pages.runtime.prod.js
|
|
76
|
+
const pagesRuntimeFile = join(distPath, "compiled", "next-server", "pages.runtime.prod.js");
|
|
77
|
+
const code = readFileSync(pagesRuntimeFile, "utf-8");
|
|
78
|
+
const file = tsParseFile(code);
|
|
79
|
+
// we need to update this function: `e=>{"use strict";e.exports=require("react-dom/server.edge")}`
|
|
80
|
+
file.getDescendantsOfKind(ts.SyntaxKind.ArrowFunction).forEach((arrowFunction) => {
|
|
81
|
+
// the function has a single parameter
|
|
82
|
+
const p = arrowFunction.getParameters();
|
|
83
|
+
if (p.length !== 1) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const parameterName = p[0].getName();
|
|
87
|
+
const bodyChildren = arrowFunction.getBody().getChildren();
|
|
88
|
+
if (!(bodyChildren.length === 3 &&
|
|
89
|
+
bodyChildren[0].getFullText() === "{" &&
|
|
90
|
+
bodyChildren[2].getFullText() === "}")) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const bodyStatements = bodyChildren[1]?.getChildren();
|
|
94
|
+
// the function has only two statements: "use strict" and e.exports=require("react-dom/server.edge")
|
|
95
|
+
if (!(bodyStatements?.length === 2 &&
|
|
96
|
+
bodyStatements.every((statement) => statement.isKind(ts.SyntaxKind.ExpressionStatement)))) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const bodyExpressionStatements = bodyStatements;
|
|
100
|
+
const stringLiteralExpression = bodyExpressionStatements[0].getExpressionIfKind(ts.SyntaxKind.StringLiteral);
|
|
101
|
+
// the first statement needs to be "use strict"
|
|
102
|
+
if (stringLiteralExpression?.getText() !== '"use strict"') {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// the second statement (e.exports=require("react-dom/server.edge")) needs to be a binary expression
|
|
106
|
+
const binaryExpression = bodyExpressionStatements[1].getExpressionIfKind(ts.SyntaxKind.BinaryExpression);
|
|
107
|
+
if (!binaryExpression?.getOperatorToken().isKind(ts.SyntaxKind.EqualsToken)) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
// on the left we have `${parameterName}.exports`
|
|
111
|
+
const binaryLeft = binaryExpression.getLeft();
|
|
112
|
+
if (!binaryLeft.isKind(ts.SyntaxKind.PropertyAccessExpression) ||
|
|
113
|
+
binaryLeft.getExpressionIfKind(ts.SyntaxKind.Identifier)?.getText() !== parameterName ||
|
|
114
|
+
binaryLeft.getName() !== "exports") {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// on the right we have `require("react-dom/server.edge")`
|
|
118
|
+
const binaryRight = binaryExpression.getRight();
|
|
119
|
+
if (!binaryRight.isKind(ts.SyntaxKind.CallExpression) ||
|
|
120
|
+
binaryRight.getExpressionIfKind(ts.SyntaxKind.Identifier)?.getText() !== "require") {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const requireArgs = binaryRight.getArguments();
|
|
124
|
+
if (requireArgs.length !== 1 || requireArgs[0].getText() !== '"react-dom/server.edge"') {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
arrowFunction.setBodyText(`
|
|
128
|
+
"use strict";
|
|
129
|
+
let ReactDOMServer;
|
|
130
|
+
try {
|
|
131
|
+
ReactDOMServer = require('react-dom/server.edge');
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (
|
|
134
|
+
error.code !== 'MODULE_NOT_FOUND' &&
|
|
135
|
+
error.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED'
|
|
136
|
+
) {
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
ReactDOMServer = require('react-dom/server.browser');
|
|
140
|
+
}
|
|
141
|
+
${parameterName}.exports = ReactDOMServer;
|
|
142
|
+
}`.replace(/\ns*/g, " "));
|
|
143
|
+
});
|
|
144
|
+
const updatedCode = file.print();
|
|
145
|
+
writeFileSync(pagesRuntimeFile, updatedCode);
|
|
146
|
+
}
|
|
@@ -45,9 +45,6 @@ export default {
|
|
|
45
45
|
* Note that cloudflare env string values are copied by the middleware handler.
|
|
46
46
|
*/
|
|
47
47
|
async function populateProcessEnv(url, nextJsEnv) {
|
|
48
|
-
if (process.env.__PROCESS_ENV_POPULATED === "1") {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
48
|
// @ts-expect-error: resolved by wrangler build
|
|
52
49
|
const nextEnvVars = await import("./.env.mjs");
|
|
53
50
|
const mode = nextJsEnv ?? "production";
|
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": "0.3.
|
|
4
|
+
"version": "0.3.6",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"opennextjs-cloudflare": "dist/cli/index.js"
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"globals": "^15.9.0",
|
|
56
56
|
"mock-fs": "^5.4.1",
|
|
57
57
|
"next": "14.2.11",
|
|
58
|
+
"rimraf": "^6.0.1",
|
|
58
59
|
"typescript-eslint": "^8.7.0",
|
|
59
60
|
"typescript": "^5.5.4",
|
|
60
61
|
"vitest": "^2.1.1"
|
|
@@ -63,7 +64,6 @@
|
|
|
63
64
|
"@dotenvx/dotenvx": "1.31.0",
|
|
64
65
|
"@opennextjs/aws": "https://pkg.pr.new/@opennextjs/aws@688",
|
|
65
66
|
"glob": "^11.0.0",
|
|
66
|
-
"rimraf": "^6.0.1",
|
|
67
67
|
"ts-morph": "^23.0.0",
|
|
68
68
|
"enquirer": "^2.4.1"
|
|
69
69
|
},
|