diff --git a/packages/cloudflare/src/cli/build/bundle-server.ts b/packages/cloudflare/src/cli/build/bundle-server.ts index 3e185f6a..663c9cd1 100644 --- a/packages/cloudflare/src/cli/build/bundle-server.ts +++ b/packages/cloudflare/src/cli/build/bundle-server.ts @@ -14,6 +14,7 @@ import { inlineEvalManifest } from "./patches/plugins/eval-manifest.js"; import { patchFetchCacheSetMissingWaitUntil } from "./patches/plugins/fetch-cache-wait-until.js"; import { inlineFindDir } from "./patches/plugins/find-dir.js"; import { patchLoadInstrumentation } from "./patches/plugins/load-instrumentation.js"; +import { inlineLoadManifest } from "./patches/plugins/load-manifest.js"; import { handleOptionalDependencies } from "./patches/plugins/optional-deps.js"; import { fixRequire } from "./patches/plugins/require.js"; import { shimRequireHook } from "./patches/plugins/require-hook.js"; @@ -93,6 +94,7 @@ export async function bundleServer(buildOpts: BuildOptions): Promise { patchFetchCacheSetMissingWaitUntil(updater), inlineEvalManifest(updater, buildOpts), inlineFindDir(updater, buildOpts), + inlineLoadManifest(updater, buildOpts), // Apply updater updaters, must be the last plugin updater.plugin, ], @@ -196,7 +198,6 @@ export async function updateWorkerBundledCode( const patchedCode = await patchCodeWithValidations(code, [ ["require", patches.patchRequire], ["`buildId` function", (code) => patches.patchBuildId(code, buildOpts)], - ["`loadManifest` function", (code) => patches.patchLoadManifest(code, buildOpts)], ["cacheHandler", (code) => patches.patchCache(code, buildOpts)], [ "'require(this.middlewareManifestPath)'", diff --git a/packages/cloudflare/src/cli/build/patches/plugins/eval-manifest.ts b/packages/cloudflare/src/cli/build/patches/plugins/eval-manifest.ts index aeb679b0..63fffe45 100644 --- a/packages/cloudflare/src/cli/build/patches/plugins/eval-manifest.ts +++ b/packages/cloudflare/src/cli/build/patches/plugins/eval-manifest.ts @@ -61,7 +61,7 @@ function evalManifest($PATH, $$$ARGS) { fix: ` function evalManifest($PATH, $$$ARGS) { ${returnManifests} - throw new Error("Unknown evalManifest: " + $PATH); + throw new Error(\`Unexpected evalManifest(\${$PATH}) call!\`); }`, } satisfies RuleConfig; } diff --git a/packages/cloudflare/src/cli/build/patches/plugins/load-manifest.ts b/packages/cloudflare/src/cli/build/patches/plugins/load-manifest.ts new file mode 100644 index 00000000..c31c4b70 --- /dev/null +++ b/packages/cloudflare/src/cli/build/patches/plugins/load-manifest.ts @@ -0,0 +1,60 @@ +/** + * Inline `loadManifest` as it relies on `readFileSync`that is not supported by workerd. + */ + +import { readFile } from "node:fs/promises"; +import { join, relative } from "node:path"; + +import { type BuildOptions, getPackagePath } from "@opennextjs/aws/build/helper.js"; +import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js"; +import { glob } from "glob"; + +import { normalizePath } from "../../utils/normalize-path.js"; +import { patchCode, type RuleConfig } from "../ast/util.js"; +import type { ContentUpdater } from "./content-updater.js"; + +export function inlineLoadManifest(updater: ContentUpdater, buildOpts: BuildOptions) { + return updater.updateContent( + "inline-load-manifest", + { + filter: getCrossPlatformPathRegex(String.raw`/next/dist/server/load-manifest\.js$`, { escape: false }), + contentFilter: /function loadManifest\(/, + }, + async ({ contents }) => patchCode(contents, await getRule(buildOpts)) + ); +} + +async function getRule(buildOpts: BuildOptions) { + const { outputDir } = buildOpts; + + const baseDir = join(outputDir, "server-functions/default", getPackagePath(buildOpts)); + const dotNextDir = join(baseDir, ".next"); + + const manifests = await glob(join(dotNextDir, "**/*-manifest.json")); + + const returnManifests = ( + await Promise.all( + manifests.map( + async (manifest) => ` + if ($PATH.endsWith("${normalizePath("/" + relative(dotNextDir, manifest))}")) { + return ${await readFile(manifest, "utf-8")}; + } + ` + ) + ) + ).join("\n"); + + return { + rule: { + pattern: ` +function loadManifest($PATH, $$$ARGS) { + $$$_ +}`, + }, + fix: ` +function loadManifest($PATH, $$$ARGS) { + ${returnManifests} + throw new Error(\`Unexpected loadManifest(\${$PATH}) call!\`); +}`, + } satisfies RuleConfig; +} diff --git a/packages/cloudflare/src/cli/build/patches/to-investigate/patch-read-file.ts b/packages/cloudflare/src/cli/build/patches/to-investigate/patch-read-file.ts index 83ba4cf2..950c1794 100644 --- a/packages/cloudflare/src/cli/build/patches/to-investigate/patch-read-file.ts +++ b/packages/cloudflare/src/cli/build/patches/to-investigate/patch-read-file.ts @@ -1,10 +1,4 @@ -import { readFileSync } from "node:fs"; -import { join, relative } from "node:path"; - -import { type BuildOptions, getBuildId, getPackagePath } from "@opennextjs/aws/build/helper.js"; -import { globSync } from "glob"; - -import { normalizePath } from "../../utils/index.js"; +import { type BuildOptions, getBuildId } from "@opennextjs/aws/build/helper.js"; export function patchBuildId(code: string, buildOpts: BuildOptions): string { // The Next code gets the buildId from the filesystem so we hardcode the value at build time. @@ -15,30 +9,3 @@ export function patchBuildId(code: string, buildOpts: BuildOptions): string { ` ); } - -export function patchLoadManifest(code: string, buildOpts: BuildOptions): string { - // Inline manifest that Next would otherwise retrieve from the file system. - - const { outputDir } = buildOpts; - - const baseDir = join(outputDir, "server-functions/default", getPackagePath(buildOpts)); - const dotNextDir = join(baseDir, ".next"); - - const manifests = globSync(join(dotNextDir, "**/*-manifest.json")); - - return code.replace( - /function loadManifest\((.+?), .+?\) {/, - `$& - ${manifests - .map( - (manifest) => ` - if ($1.endsWith("${normalizePath("/" + relative(dotNextDir, manifest))}")) { - return ${readFileSync(manifest, "utf-8")}; - } - ` - ) - .join("\n")} - throw new Error("Unknown loadManifest: " + $1); - ` - ); -}