diff --git a/.changeset/fix-vite-node-condition.md b/.changeset/fix-vite-node-condition.md new file mode 100644 index 0000000000..53bc6236b6 --- /dev/null +++ b/.changeset/fix-vite-node-condition.md @@ -0,0 +1,7 @@ +--- +"@react-router/dev": patch +--- + +fix(vite): do not force `node` condition in non-Node environments + +When `v8_viteEnvironmentApi` is enabled, the `"node"` condition is no longer unconditionally added to `externalConditions` for all SSR environments. Instead, it is set per-environment in the `configEnvironment` hook, using `noExternal: true` as the signal that the target runtime is not Node.js (e.g. Cloudflare Workers). This fixes builds for non-Node runtimes that cannot import Node builtins like `http` and `https`. diff --git a/contributors.yml b/contributors.yml index 6a7f04d055..fc9f80ef8c 100644 --- a/contributors.yml +++ b/contributors.yml @@ -215,6 +215,7 @@ - justjavac - kachun333 - Kakamotobi +- Kanevry - kantuni - kaoths - kapil-patel diff --git a/packages/react-router-dev/vite/plugin.ts b/packages/react-router-dev/vite/plugin.ts index 66db51ca51..54300a43d5 100644 --- a/packages/react-router-dev/vite/plugin.ts +++ b/packages/react-router-dev/vite/plugin.ts @@ -1474,6 +1474,18 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => { // impact consumers because for them `ssrExternals` is undefined and // Cloudflare's "noExternal: true" config remains intact. options.resolve?.noExternal === true ? undefined : ssrExternals, + // Only add "node" to externalConditions for Node.js environments. + // Non-Node runtimes like Cloudflare Workers signal via + // `noExternal: true` and their adapter plugins set their own + // conditions (e.g. "workerd", "worker"). + ...(options.resolve?.noExternal !== true + ? { + externalConditions: [ + ...(options.resolve?.externalConditions ?? []), + "node", + ], + } + : {}), }, optimizeDeps: options.optimizeDeps?.noDiscovery === false @@ -4059,7 +4071,10 @@ export async function getEnvironmentOptionsResolvers( // There is no helpful export with the default external conditions (see // https://github.com/vitejs/vite/pull/20279 for more details). So, for now, - // we are hardcording the default here. + // we are hardcoding the default here. When `v8_viteEnvironmentApi` is + // enabled, external conditions are set per-environment in the + // `configEnvironment` hook so that non-Node runtimes (e.g. Cloudflare + // Workers) are not forced to use the "node" condition. let defaultExternalConditions = ["node"]; let baseConditions = [ @@ -4075,7 +4090,9 @@ export async function getEnvironmentOptionsResolvers( ? undefined : ssrExternals, conditions: [...baseConditions, ...maybeDefaultServerConditions], - externalConditions: [...baseConditions, ...defaultExternalConditions], + externalConditions: ctx.reactRouterConfig.future.v8_viteEnvironmentApi + ? [...baseConditions] + : [...baseConditions, ...defaultExternalConditions], }, build: { // We move SSR-only assets to client assets. Note that the