diff --git a/packages/cloudflare/src/cli/build/bundle-server.ts b/packages/cloudflare/src/cli/build/bundle-server.ts index 68b790ca..ce2d2b68 100644 --- a/packages/cloudflare/src/cli/build/bundle-server.ts +++ b/packages/cloudflare/src/cli/build/bundle-server.ts @@ -9,6 +9,7 @@ import { build } from "esbuild"; import { patchVercelOgLibrary } from "./patches/ast/patch-vercel-og-library.js"; import { patchWebpackRuntime } from "./patches/ast/webpack-runtime.js"; import * as patches from "./patches/index.js"; +import { inlineBuildId } from "./patches/plugins/build-id.js"; import { ContentUpdater } from "./patches/plugins/content-updater.js"; import { inlineEvalManifest } from "./patches/plugins/eval-manifest.js"; import { patchFetchCacheSetMissingWaitUntil } from "./patches/plugins/fetch-cache-wait-until.js"; @@ -95,6 +96,7 @@ export async function bundleServer(buildOpts: BuildOptions): Promise { inlineEvalManifest(updater, buildOpts), inlineFindDir(updater, buildOpts), inlineLoadManifest(updater, buildOpts), + inlineBuildId(updater), // Apply updater updaters, must be the last plugin updater.plugin, ], @@ -197,7 +199,6 @@ export async function updateWorkerBundledCode( const patchedCode = await patchCodeWithValidations(code, [ ["require", patches.patchRequire], - ["`buildId` function", (code) => patches.patchBuildId(code, buildOpts)], ["cacheHandler", (code) => patches.patchCache(code, buildOpts)], [ "'require(this.middlewareManifestPath)'", diff --git a/packages/cloudflare/src/cli/build/patches/index.ts b/packages/cloudflare/src/cli/build/patches/index.ts index d556d6cb..dd308a05 100644 --- a/packages/cloudflare/src/cli/build/patches/index.ts +++ b/packages/cloudflare/src/cli/build/patches/index.ts @@ -1,2 +1,2 @@ export * from "./investigated/index.js"; -export * from "./to-investigate/index.js"; +export * from "./to-investigate/inline-middleware-manifest.js"; diff --git a/packages/cloudflare/src/cli/build/patches/plugins/build-id.ts b/packages/cloudflare/src/cli/build/patches/plugins/build-id.ts new file mode 100644 index 00000000..242b69ab --- /dev/null +++ b/packages/cloudflare/src/cli/build/patches/plugins/build-id.ts @@ -0,0 +1,31 @@ +/** + * Inline `getBuildId` as it relies on `readFileSync` that is not supported by workerd. + */ + +import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js"; + +import { patchCode } from "../ast/util.js"; +import type { ContentUpdater } from "./content-updater.js"; + +export function inlineBuildId(updater: ContentUpdater) { + return updater.updateContent( + "inline-build-id", + { + filter: getCrossPlatformPathRegex(String.raw`/next/dist/server/next-server\.js$`, { escape: false }), + contentFilter: /getBuildId\(/, + }, + async ({ contents }) => patchCode(contents, rule) + ); +} + +export const rule = ` +rule: + kind: method_definition + has: + field: name + regex: ^getBuildId$ +fix: |- + getBuildId() { + return process.env.NEXT_BUILD_ID; + } +`; diff --git a/packages/cloudflare/src/cli/build/patches/plugins/find-dir.spec.ts b/packages/cloudflare/src/cli/build/patches/plugins/find-dir.spec.ts new file mode 100644 index 00000000..6a532a5f --- /dev/null +++ b/packages/cloudflare/src/cli/build/patches/plugins/find-dir.spec.ts @@ -0,0 +1,85 @@ +import { describe, expect, test } from "vitest"; + +import { patchCode } from "../ast/util.js"; +import { rule } from "./build-id.js"; + +describe("getBuildId", () => { + test("patch", () => { + const code = ` +class NextNodeServer extends _baseserver.default { + constructor(options){ + // Initialize super class + super(options); + this.handleNextImageRequest = async (req, res, parsedUrl) => { /* ... */ }; + } + async handleUpgrade() { + // The web server does not support web sockets, it's only used for HMR in + // development. + } + loadEnvConfig({ dev, forceReload, silent }) { + (0, _env.loadEnvConfig)(this.dir, dev, silent ? { + info: ()=>{}, + error: ()=>{} + } : _log, forceReload); + } + async hasPage(pathname) { + var _this_nextConfig_i18n; + return !!(0, _require.getMaybePagePath)(pathname, this.distDir, (_this_nextConfig_i18n = this.nextConfig.i18n) == null ? void 0 : _this_nextConfig_i18n.locales, this.enabledDirectories.app); + } + getBuildId() { + const buildIdFile = (0, _path.join)(this.distDir, _constants.BUILD_ID_FILE); + try { + return _fs.default.readFileSync(buildIdFile, "utf8").trim(); + } catch (err) { + if (err.code === "ENOENT") { + throw new Error(\`Could not find a production build in the '\${this.distDir}' directory. Try building your app with 'next build' before starting the production server. https://nextjs.org/docs/messages/production-start-no-build-id\`); + } + throw err; + } + } + getEnabledDirectories(dev) { + const dir = dev ? this.dir : this.serverDistDir; + return { + app: (0, _findpagesdir.findDir)(dir, "app") ? true : false, + pages: (0, _findpagesdir.findDir)(dir, "pages") ? true : false + }; + } + // ... +}`; + + expect(patchCode(code, rule)).toMatchInlineSnapshot(` + "class NextNodeServer extends _baseserver.default { + constructor(options){ + // Initialize super class + super(options); + this.handleNextImageRequest = async (req, res, parsedUrl) => { /* ... */ }; + } + async handleUpgrade() { + // The web server does not support web sockets, it's only used for HMR in + // development. + } + loadEnvConfig({ dev, forceReload, silent }) { + (0, _env.loadEnvConfig)(this.dir, dev, silent ? { + info: ()=>{}, + error: ()=>{} + } : _log, forceReload); + } + async hasPage(pathname) { + var _this_nextConfig_i18n; + return !!(0, _require.getMaybePagePath)(pathname, this.distDir, (_this_nextConfig_i18n = this.nextConfig.i18n) == null ? void 0 : _this_nextConfig_i18n.locales, this.enabledDirectories.app); + } + getBuildId() { + return process.env.NEXT_BUILD_ID; + } + getEnabledDirectories(dev) { + const dir = dev ? this.dir : this.serverDistDir; + return { + app: (0, _findpagesdir.findDir)(dir, "app") ? true : false, + pages: (0, _findpagesdir.findDir)(dir, "pages") ? true : false + }; + } + // ... + }" + `); + }); +}); diff --git a/packages/cloudflare/src/cli/build/patches/plugins/load-manifest.ts b/packages/cloudflare/src/cli/build/patches/plugins/load-manifest.ts index 7689e0c1..9d2fef04 100644 --- a/packages/cloudflare/src/cli/build/patches/plugins/load-manifest.ts +++ b/packages/cloudflare/src/cli/build/patches/plugins/load-manifest.ts @@ -1,5 +1,5 @@ /** - * Inline `loadManifest` as it relies on `readFileSync`that is not supported by workerd. + * Inline `loadManifest` as it relies on `readFileSync` that is not supported by workerd. */ import { readFile } from "node:fs/promises"; diff --git a/packages/cloudflare/src/cli/build/patches/to-investigate/index.ts b/packages/cloudflare/src/cli/build/patches/to-investigate/index.ts deleted file mode 100644 index c3e5da37..00000000 --- a/packages/cloudflare/src/cli/build/patches/to-investigate/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./inline-middleware-manifest-require.js"; -export * from "./patch-read-file.js"; diff --git a/packages/cloudflare/src/cli/build/patches/to-investigate/inline-middleware-manifest-require.ts b/packages/cloudflare/src/cli/build/patches/to-investigate/inline-middleware-manifest.ts similarity index 100% rename from packages/cloudflare/src/cli/build/patches/to-investigate/inline-middleware-manifest-require.ts rename to packages/cloudflare/src/cli/build/patches/to-investigate/inline-middleware-manifest.ts 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 deleted file mode 100644 index 950c1794..00000000 --- a/packages/cloudflare/src/cli/build/patches/to-investigate/patch-read-file.ts +++ /dev/null @@ -1,11 +0,0 @@ -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. - return code.replace( - "getBuildId() {", - `getBuildId() { - return ${JSON.stringify(getBuildId(buildOpts))}; - ` - ); -}