diff --git a/.changeset/ignore-external-vite-server-environments.md b/.changeset/ignore-external-vite-server-environments.md new file mode 100644 index 0000000000..22218c029f --- /dev/null +++ b/.changeset/ignore-external-vite-server-environments.md @@ -0,0 +1,5 @@ +--- +"@react-router/dev": patch +--- + +Avoid running React Router's server build cleanup hooks for unrelated Vite server environments when `future.v8_viteEnvironmentApi` is enabled. diff --git a/contributors.yml b/contributors.yml index 6a7f04d055..ea3160d39a 100644 --- a/contributors.yml +++ b/contributors.yml @@ -347,6 +347,7 @@ - pyitphyoaung - qu0b - QzCurious +- raashish1601 - redabacha - refusado - remorses diff --git a/packages/react-router-dev/__tests__/vite-plugin-test.ts b/packages/react-router-dev/__tests__/vite-plugin-test.ts new file mode 100644 index 0000000000..817863de96 --- /dev/null +++ b/packages/react-router-dev/__tests__/vite-plugin-test.ts @@ -0,0 +1,56 @@ +import { + getServerEnvironmentKeys, + isReactRouterServerEnvironmentName, +} from "../vite/plugin"; + +describe("React Router Vite server environment detection", () => { + it("only treats ssr as a React Router server environment without server bundles", () => { + let ctx = { + buildManifest: { + routes: {}, + }, + } as any; + + expect(isReactRouterServerEnvironmentName(ctx, "ssr")).toBe(true); + expect(isReactRouterServerEnvironmentName(ctx, "client")).toBe(false); + expect(isReactRouterServerEnvironmentName(ctx, "nitro")).toBe(false); + + expect( + getServerEnvironmentKeys(ctx, { + client: {}, + ssr: {}, + nitro: {}, + }), + ).toEqual(["ssr"]); + }); + + it("ignores external server environments when server bundles are enabled", () => { + let ctx = { + buildManifest: { + routes: {}, + routeIdToServerBundleId: {}, + serverBundles: { + admin: { + id: "admin", + file: "build/server/admin/index.js", + }, + }, + }, + } as any; + + expect(isReactRouterServerEnvironmentName(ctx, "ssrBundle_admin")).toBe( + true, + ); + expect(isReactRouterServerEnvironmentName(ctx, "ssr")).toBe(false); + expect(isReactRouterServerEnvironmentName(ctx, "nitro")).toBe(false); + + expect( + getServerEnvironmentKeys(ctx, { + client: {}, + ssr: {}, + ssrBundle_admin: {}, + nitro: {}, + }), + ).toEqual(["ssrBundle_admin"]); + }); +}); diff --git a/packages/react-router-dev/vite/plugin.ts b/packages/react-router-dev/vite/plugin.ts index 66db51ca51..2db7c20007 100644 --- a/packages/react-router-dev/vite/plugin.ts +++ b/packages/react-router-dev/vite/plugin.ts @@ -179,14 +179,21 @@ export type EnvironmentBuildContext = { resolveOptions: EnvironmentOptionsResolver; }; +export function isReactRouterServerEnvironmentName( + ctx: Pick, + name: string, +): name is SsrEnvironmentName { + return ctx.buildManifest?.serverBundles + ? isSsrBundleEnvironmentName(name) + : name === "ssr"; +} + function getServerEnvironmentEntries( ctx: ReactRouterPluginContext, record: Record, ): [SsrEnvironmentName, T][] { return Object.entries(record).filter(([name]) => - ctx.buildManifest?.serverBundles - ? isSsrBundleEnvironmentName(name) - : name === "ssr", + isReactRouterServerEnvironmentName(ctx, name), ) as [SsrEnvironmentName, T][]; } @@ -1458,9 +1465,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => { configEnvironment(name, options) { if ( ctx.reactRouterConfig.future.v8_viteEnvironmentApi && - (ctx.buildManifest?.serverBundles - ? isSsrBundleEnvironmentName(name) - : name === "ssr") + isReactRouterServerEnvironmentName(ctx, name) ) { const vite = getVite(); @@ -1855,12 +1860,11 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => { // the SSR build and move server-only assets to client assets directory async handler() { let { future } = ctx.reactRouterConfig; + let isReactRouterServerBuild = future.v8_viteEnvironmentApi + ? isReactRouterServerEnvironmentName(ctx, this.environment.name) + : viteConfigEnv.isSsrBuild; - if ( - future.v8_viteEnvironmentApi - ? this.environment.name === "client" - : !viteConfigEnv.isSsrBuild - ) { + if (!isReactRouterServerBuild) { return; } invariant(viteConfig);