diff --git a/.changeset/shy-news-wave.md b/.changeset/shy-news-wave.md new file mode 100644 index 000000000..e7508fa4a --- /dev/null +++ b/.changeset/shy-news-wave.md @@ -0,0 +1,7 @@ +--- +"@opennextjs/cloudflare": patch +--- + +drop unused react-dom modules + +This saves ~500kB on the output bundle diff --git a/packages/cloudflare/src/cli/build/bundle-server.ts b/packages/cloudflare/src/cli/build/bundle-server.ts index d38b5357a..6725c595c 100644 --- a/packages/cloudflare/src/cli/build/bundle-server.ts +++ b/packages/cloudflare/src/cli/build/bundle-server.ts @@ -23,6 +23,7 @@ import { patchDepdDeprecations } from "./patches/plugins/patch-depd-deprecations import { fixRequire } from "./patches/plugins/require.js"; import { shimRequireHook } from "./patches/plugins/require-hook.js"; import { patchRouteModules } from "./patches/plugins/route-module.js"; +import { shimReact } from "./patches/plugins/shim-react.js"; import { setWranglerExternal } from "./patches/plugins/wrangler-external.js"; import { copyPackageCliFiles, needsExperimentalReact, normalizePath } from "./utils/index.js"; @@ -92,6 +93,7 @@ export async function bundleServer(buildOpts: BuildOptions, projectOpts: Project conditions: getOpenNextConfig(buildOpts).cloudflare?.useWorkerdCondition === false ? [] : ["workerd"], plugins: [ shimRequireHook(buildOpts), + shimReact(buildOpts), inlineDynamicRequires(updater, buildOpts), setWranglerExternal(), fixRequire(updater), diff --git a/packages/cloudflare/src/cli/build/patches/plugins/require-hook.ts b/packages/cloudflare/src/cli/build/patches/plugins/require-hook.ts index 8e46b6342..1dc315a94 100644 --- a/packages/cloudflare/src/cli/build/patches/plugins/require-hook.ts +++ b/packages/cloudflare/src/cli/build/patches/plugins/require-hook.ts @@ -7,9 +7,9 @@ import type { Plugin } from "esbuild"; export function shimRequireHook(options: BuildOptions): Plugin { const emptyShimPath = join(options.outputDir, "cloudflare-templates/shims/empty.js"); return { - name: "replaceRelative", + name: "require-hook-shim", setup(build) { - // Note: we (empty) shim require-hook modules as they generate problematic code that uses requires + // We (empty) shim require-hook modules as they generate problematic code that uses requires build.onResolve( { filter: getCrossPlatformPathRegex(String.raw`^\./require-hook$`, { escape: false }) }, () => ({ diff --git a/packages/cloudflare/src/cli/build/patches/plugins/shim-react.ts b/packages/cloudflare/src/cli/build/patches/plugins/shim-react.ts new file mode 100644 index 000000000..6351c89aa --- /dev/null +++ b/packages/cloudflare/src/cli/build/patches/plugins/shim-react.ts @@ -0,0 +1,37 @@ +import { join } from "node:path"; + +import type { BuildOptions } from "@opennextjs/aws/build/helper.js"; +import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js"; +import type { Plugin } from "esbuild"; + +/** + * `react-dom/server.edge` requires: + * - `react-dom-server.edge.production.js` + * - `react-dom-server.browser.production.js` + * - `react-dom-server-legacy.browser.production.js` + * + * However only the first one is needed in the Cloudflare Workers environment. + * The other two can be shimmed to an empty module to reduce the bundle size. + * + * @param options Build options + * @returns An ESBuild plugin that shims unnecessary React modules + */ +export function shimReact(options: BuildOptions): Plugin { + const emptyShimPath = join(options.outputDir, "cloudflare-templates/shims/empty.js"); + return { + name: "react-shim", + setup(build) { + build.onResolve( + { + filter: getCrossPlatformPathRegex( + String.raw`(react-dom-server\.browser\.production\.js|react-dom-server-legacy\.browser\.production\.js)$`, + { escape: false } + ), + }, + () => ({ + path: emptyShimPath, + }) + ); + }, + }; +}