Skip to content

Commit d87c9c1

Browse files
committed
fix up node module loader rule and merge with require page plugin
1 parent 6c84a10 commit d87c9c1

File tree

4 files changed

+147
-162
lines changed

4 files changed

+147
-162
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@ import { patchFetchCacheSetMissingWaitUntil } from "./patches/plugins/fetch-cach
1616
import { inlineFindDir } from "./patches/plugins/find-dir.js";
1717
import { patchInstrumentation } from "./patches/plugins/instrumentation.js";
1818
import { inlineLoadManifest } from "./patches/plugins/load-manifest.js";
19-
import { inlineNodeModuleLoader } from "./patches/plugins/node-module-loader.js";
19+
import { inlineDynamicRequires } from "./patches/plugins/dynamic-requires.js";
2020
import { handleOptionalDependencies } from "./patches/plugins/optional-deps.js";
2121
import { patchDepdDeprecations } from "./patches/plugins/patch-depd-deprecations.js";
2222
import { fixRequire } from "./patches/plugins/require.js";
2323
import { shimRequireHook } from "./patches/plugins/require-hook.js";
24-
import { inlineRequirePage } from "./patches/plugins/require-page.js";
2524
import { setWranglerExternal } from "./patches/plugins/wrangler-external.js";
2625
import { normalizePath, patchCodeWithValidations } from "./utils/index.js";
2726

@@ -89,8 +88,7 @@ export async function bundleServer(buildOpts: BuildOptions): Promise<void> {
8988
conditions: [],
9089
plugins: [
9190
shimRequireHook(buildOpts),
92-
inlineRequirePage(updater, buildOpts),
93-
inlineNodeModuleLoader(updater, buildOpts),
91+
inlineDynamicRequires(updater, buildOpts),
9492
setWranglerExternal(),
9593
fixRequire(updater),
9694
handleOptionalDependencies(optionalDependencies),
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import { readFile } from "node:fs/promises";
2+
import { join } from "node:path";
3+
4+
import { type BuildOptions, getPackagePath } from "@opennextjs/aws/build/helper.js";
5+
import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js";
6+
7+
import { normalizePath } from "../../utils/normalize-path.js";
8+
import { patchCode, type RuleConfig } from "../ast/util.js";
9+
import type { ContentUpdater } from "./content-updater.js";
10+
import { posix, sep } from "node:path";
11+
import type { Plugin } from "esbuild";
12+
13+
async function getPagesManifests(serverDir: string): Promise<string[]> {
14+
try {
15+
return Object.values(JSON.parse(await readFile(join(serverDir, "pages-manifest.json"), "utf-8")));
16+
} catch {
17+
// The file does not exist
18+
return [];
19+
}
20+
}
21+
22+
async function getAppPathsManifests(serverDir: string): Promise<string[]> {
23+
try {
24+
return Object.values(JSON.parse(await readFile(join(serverDir, "app-paths-manifest.json"), "utf-8")));
25+
} catch {
26+
// The file does not exist
27+
return [];
28+
}
29+
}
30+
31+
function getServerDir(buildOpts: BuildOptions) {
32+
return join(buildOpts.outputDir, "server-functions/default", getPackagePath(buildOpts), ".next/server");
33+
}
34+
35+
function getRequires(idVariable: string, files: string[], serverDir: string) {
36+
// Inline fs access and dynamic requires that are not supported by workerd.
37+
return files
38+
.map(
39+
(
40+
file
41+
) => `if (${idVariable}.replaceAll(${JSON.stringify(sep)}, ${JSON.stringify(posix.sep)}).endsWith(${JSON.stringify(normalizePath(file))})) {
42+
return require(${JSON.stringify(join(serverDir, file))});
43+
}`
44+
)
45+
.join("\n");
46+
}
47+
48+
export function inlineDynamicRequires(updater: ContentUpdater, buildOpts: BuildOptions): Plugin {
49+
updater.updateContent(
50+
"inline-node-module-loader",
51+
{
52+
filter: getCrossPlatformPathRegex(
53+
String.raw`/next/dist/server/lib/module-loader/node-module-loader\.js$`,
54+
{ escape: false }
55+
),
56+
contentFilter: /class NodeModuleLoader {/,
57+
},
58+
async ({ contents }) => patchCode(contents, await getNodeModuleLoaderRule(buildOpts))
59+
);
60+
updater.updateContent(
61+
"inline-require-page",
62+
{
63+
filter: getCrossPlatformPathRegex(String.raw`/next/dist/server/require\.js$`, { escape: false }),
64+
contentFilter: /function requirePage\(/,
65+
},
66+
async ({ contents }) => patchCode(contents, await getRequirePageRule(buildOpts))
67+
);
68+
return { name: "inline-dynamic-requires", setup() {} };
69+
}
70+
71+
async function getNodeModuleLoaderRule(buildOpts: BuildOptions) {
72+
const serverDir = getServerDir(buildOpts);
73+
74+
let manifests = await getPagesManifests(serverDir);
75+
76+
const files = manifests.filter((file) => file.endsWith(".js"));
77+
78+
return `
79+
rule:
80+
kind: method_definition
81+
all:
82+
- has:
83+
field: name
84+
regex: ^load$
85+
- has:
86+
field: parameters
87+
has:
88+
kind: identifier
89+
pattern: $ID
90+
inside:
91+
stopBy:
92+
kind: class_declaration
93+
has:
94+
field: name
95+
regex: ^NodeModuleLoader$
96+
fix: |
97+
async load($ID) {
98+
${getRequires("$ID", files, serverDir)}
99+
}`;
100+
}
101+
102+
async function getRequirePageRule(buildOpts: BuildOptions) {
103+
const serverDir = getServerDir(buildOpts);
104+
105+
const pagesManifests = await getPagesManifests(serverDir);
106+
const appPathsManifests = await getAppPathsManifests(serverDir);
107+
108+
const manifests = pagesManifests.concat(appPathsManifests);
109+
110+
const htmlFiles = manifests.filter((file) => file.endsWith(".html"));
111+
const jsFiles = manifests.filter((file) => file.endsWith(".js"));
112+
113+
return {
114+
rule: {
115+
pattern: `
116+
function requirePage($PAGE, $DIST_DIR, $IS_APP_PATH) {
117+
const $_ = getPagePath($$$ARGS);
118+
$$$_BODY
119+
}`,
120+
}, // Inline fs access and dynamic require that are not supported by workerd.
121+
fix: `
122+
function requirePage($PAGE, $DIST_DIR, $IS_APP_PATH) {
123+
const { platform } = require('process');
124+
const pagePath = platform === 'win32' ? getPagePath($$$ARGS).replaceAll('\\\\', '/') : getPagePath($$$ARGS);
125+
126+
// html
127+
${(
128+
await Promise.all(
129+
htmlFiles.map(
130+
async (file) => `if (pagePath.endsWith(${JSON.stringify(normalizePath(file))})) {
131+
return ${JSON.stringify(await readFile(join(serverDir, file), "utf-8"))};
132+
}`
133+
)
134+
)
135+
).join("\n")}
136+
// js
137+
process.env.__NEXT_PRIVATE_RUNTIME_TYPE = $IS_APP_PATH ? 'app' : 'pages';
138+
try {
139+
${getRequires("pagePath", jsFiles, serverDir)}
140+
} finally {
141+
process.env.__NEXT_PRIVATE_RUNTIME_TYPE = '';
142+
}
143+
}`,
144+
} satisfies RuleConfig;
145+
}

packages/cloudflare/src/cli/build/patches/plugins/node-module-loader.ts

Lines changed: 0 additions & 66 deletions
This file was deleted.

packages/cloudflare/src/cli/build/patches/plugins/require-page.ts

Lines changed: 0 additions & 92 deletions
This file was deleted.

0 commit comments

Comments
 (0)