@react-router/dev 8.5.0 → 8.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # `@react-router/dev`
2
2
 
3
+ ## v8.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Use resolved Vite environment output directories when reading and writing build artifacts ([#15480](https://github.com/remix-run/react-router/pull/15480))
8
+ - Finalize server-bundle manifest paths after asynchronous Vite configuration hooks complete
9
+ - Preserve output-directory overrides applied when creating a Vite build environment
10
+ - Run prerendering after other Vite plugins finish their application build hooks ([#15481](https://github.com/remix-run/react-router/pull/15481))
11
+ - Close React Router's build resources when another plugin's application build hook fails during `react-router build`
12
+ - Updated dependencies:
13
+ - [`react-router@8.5.1`](https://github.com/remix-run/react-router/releases/tag/react-router@8.5.1)
14
+ - [`@react-router/node@8.5.1`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.5.1)
15
+ - [`@react-router/serve@8.5.1`](https://github.com/remix-run/react-router/releases/tag/@react-router/serve@8.5.1)
16
+
3
17
  ## v8.5.0
4
18
 
5
19
  ### Patch Changes
@@ -11,7 +25,7 @@
11
25
 
12
26
  ### Unstable Changes
13
27
 
14
- ⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
28
+ ⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
15
29
 
16
30
  - Add `ssr: "unstable_api-only"` to retain a runtime server for loaders, actions, and route discovery while disabling production document rendering ([#15601](https://github.com/remix-run/react-router/pull/15601))
17
31
  - Generate a root-only SPA shell when prerendering is disabled
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.5.0
2
+ * @react-router/dev v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,12 +8,12 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { _ as getVite, v as preloadVite } from "./typegen-CiHN93zF.js";
11
+ import { _ as getVite, v as preloadVite } from "./typegen-CqlAVM2O.js";
12
12
  //#region vite/build.ts
13
13
  async function build(root, viteBuildOptions) {
14
14
  await preloadVite();
15
15
  let { assetsInlineLimit, clearScreen, config: configFile, emptyOutDir, force, logLevel, minify, mode, sourcemapClient, sourcemapServer } = viteBuildOptions;
16
- await (await getVite().createBuilder({
16
+ let builder = await getVite().createBuilder({
17
17
  root,
18
18
  mode,
19
19
  configFile,
@@ -35,7 +35,13 @@ async function build(root, viteBuildOptions) {
35
35
  if (!config.plugins.find((plugin) => plugin.name === "react-router" || plugin.name === "react-router/rsc")) throw new Error("React Router Vite plugin not found in Vite config");
36
36
  }
37
37
  }]
38
- })).buildApp();
38
+ });
39
+ try {
40
+ await builder.buildApp();
41
+ } finally {
42
+ let { __reactRouterBuildContext: buildContext } = builder.config;
43
+ await buildContext?.close();
44
+ }
39
45
  }
40
46
  //#endregion
41
47
  export { build };
package/dist/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * @react-router/dev v8.5.0
3
+ * @react-router/dev v8.5.1
4
4
  *
5
5
  * Copyright (c) Remix Software Inc.
6
6
  *
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * @license MIT
11
11
  */
12
- import { _ as getVite, l as hasNodeDependency, n as watch, t as run$1, u as loadConfig, v as preloadVite } from "../typegen-CiHN93zF.js";
12
+ import { _ as getVite, l as hasNodeDependency, n as watch, t as run$1, u as loadConfig, v as preloadVite } from "../typegen-CqlAVM2O.js";
13
13
  import { createRequire } from "node:module";
14
14
  import { parseArgs } from "node:util";
15
15
  import semver from "semver";
@@ -172,7 +172,7 @@ async function routes(rootDirectory, flags = {}) {
172
172
  }
173
173
  async function build(root, options = {}) {
174
174
  root = resolveRootDirectory(root, options);
175
- let { build } = await import("../build-ZbZgdE7Y.js");
175
+ let { build } = await import("../build-DjEus3HZ.js");
176
176
  if (options.profile) await start();
177
177
  try {
178
178
  await build(root, options);
@@ -182,7 +182,7 @@ async function build(root, options = {}) {
182
182
  }
183
183
  async function dev(root, options = {}) {
184
184
  if (developmentConditionEnabled) {
185
- let { dev } = await import("../dev-DGFm0uWr.js");
185
+ let { dev } = await import("../dev-LVfdDvQH.js");
186
186
  if (options.profile) await start();
187
187
  exitHook(() => stop(console.info));
188
188
  root = resolveRootDirectory(root, options);
package/dist/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.5.0
2
+ * @react-router/dev v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.5.0
2
+ * @react-router/dev v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { _ as getVite, v as preloadVite } from "./typegen-CiHN93zF.js";
11
+ import { _ as getVite, v as preloadVite } from "./typegen-CqlAVM2O.js";
12
12
  import { n as start, r as stop, t as getSession } from "./cli/index.js";
13
13
  import colors from "picocolors";
14
14
  //#region vite/dev.ts
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.5.0
2
+ * @react-router/dev v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/routes.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.5.0
2
+ * @react-router/dev v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { a as prefix, i as layout, n as getAppDirectory, o as relative, r as index, s as route } from "./routes-Cyup1Gnm.js";
11
+ import { a as prefix, i as layout, n as getAppDirectory, o as relative, r as index, s as route } from "./routes-DAb9gz9-.js";
12
12
  export { getAppDirectory, index, layout, prefix, relative, route };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.5.0
2
+ * @react-router/dev v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { c as setAppDirectory, l as validateRouteConfig, t as configRoutesToRouteManifest, u as invariant } from "./routes-Cyup1Gnm.js";
11
+ import { c as setAppDirectory, l as validateRouteConfig, t as configRoutesToRouteManifest, u as invariant } from "./routes-DAb9gz9-.js";
12
12
  import { createRequire } from "node:module";
13
13
  import colors from "picocolors";
14
14
  import fs from "node:fs";
package/dist/vite.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.5.0
2
+ * @react-router/dev v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,8 +8,8 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { _ as getVite, a as t, c as createConfigLoader, d as resolveEntryFiles, f as resolveRSCEntryFiles, g as getUserBuildRollupOptions, h as defineOptimizeDepsCompilerOptions, i as parse$1, l as hasNodeDependency, m as defineCompilerOptions, n as watch, o as traverse, p as ssrExternals, r as generate, s as configRouteToBranchRoute, v as preloadVite } from "./typegen-CiHN93zF.js";
12
- import { u as invariant } from "./routes-Cyup1Gnm.js";
11
+ import { _ as getVite, a as t, c as createConfigLoader, d as resolveEntryFiles, f as resolveRSCEntryFiles, g as getUserBuildRollupOptions, h as defineOptimizeDepsCompilerOptions, i as parse$1, l as hasNodeDependency, m as defineCompilerOptions, n as watch, o as traverse, p as ssrExternals, r as generate, s as configRouteToBranchRoute, v as preloadVite } from "./typegen-CqlAVM2O.js";
12
+ import { u as invariant } from "./routes-DAb9gz9-.js";
13
13
  import { createRequire } from "node:module";
14
14
  import colors from "picocolors";
15
15
  import { existsSync, readFileSync, readdirSync } from "node:fs";
@@ -789,90 +789,91 @@ function normalizePostProcessResult(result) {
789
789
  * Vite plugin for prerendering using the preview server
790
790
  */
791
791
  function prerender(options) {
792
- const { config, requests, postProcess = defaultPostProcess, handleError = defaultHandleError, logFile, finalize } = options;
792
+ const { config, requests, postProcess = defaultPostProcess, handleError = defaultHandleError, logFile, finalize, cleanup } = options;
793
793
  let viteConfig;
794
794
  return {
795
795
  name: "prerender",
796
+ enforce: "post",
796
797
  sharedDuringBuild: true,
797
- config: {
798
+ buildApp: {
798
799
  order: "post",
799
- handler({ builder: { buildApp } = {} }) {
800
- return { builder: { async buildApp(builder) {
801
- await buildApp?.(builder);
800
+ async handler() {
801
+ let ogIsBuildRequest = process.env.IS_RR_BUILD_REQUEST;
802
+ try {
802
803
  const prerenderRequests = (typeof requests === "function" ? await requests() : requests).map(normalizePrerenderRequest);
803
804
  if (prerenderRequests.length === 0) return;
804
- const { buildDirectory = viteConfig.environments.client.build.outDir, concurrency = 1, retryCount = 0, retryDelay = 500, maxRedirects = 0, timeout = 1e4 } = (typeof config === "function" ? await config() : config) ?? {};
805
- let ogIsBuildRequest = process.env.IS_RR_BUILD_REQUEST;
805
+ const { buildDirectory = path.resolve(viteConfig.root, viteConfig.environments.client.build.outDir), concurrency = 1, retryCount = 0, retryDelay = 500, maxRedirects = 0, timeout = 1e4 } = (typeof config === "function" ? await config() : config) ?? {};
806
806
  process.env.IS_RR_BUILD_REQUEST = "yes";
807
+ const previewServer = await startPreviewServer(viteConfig);
807
808
  try {
808
- const previewServer = await startPreviewServer(viteConfig);
809
- try {
810
- const baseUrl = getResolvedUrl(previewServer);
811
- async function prerenderRequest(input, metadata) {
812
- let attemptCount = 0;
813
- let redirectCount = 0;
814
- const request = new Request(input);
815
- const url = new URL(request.url);
816
- if (url.origin !== baseUrl.origin) {
817
- url.hostname = baseUrl.hostname;
818
- url.protocol = baseUrl.protocol;
819
- url.port = baseUrl.port;
820
- }
821
- async function attempt(url) {
822
- try {
823
- const signal = AbortSignal.timeout(timeout);
824
- const response = await nodeHttpFetch(new Request(url, request), { signal });
825
- if (response.status >= 300 && response.status < 400 && response.headers.has("location") && ++redirectCount <= maxRedirects) {
826
- const location = response.headers.get("location");
827
- const responseURL = new URL(response.url);
828
- const locationUrl = new URL(location, response.url);
829
- if (responseURL.origin !== locationUrl.origin) return await postProcess(request, response, metadata);
830
- return await attempt(new URL(location, url));
831
- }
832
- if (response.status >= 500 && ++attemptCount <= retryCount) {
833
- await new Promise((resolve) => setTimeout(resolve, retryDelay));
834
- return attempt(url);
835
- }
836
- return await postProcess(request, response, metadata);
837
- } catch (error) {
838
- if (++attemptCount <= retryCount) {
839
- await new Promise((resolve) => setTimeout(resolve, retryDelay));
840
- return attempt(url);
841
- }
842
- handleError(request, error instanceof Error ? error : new Error(error?.toString() ?? "Unknown error"), metadata);
843
- return [];
844
- }
845
- }
846
- return attempt(url);
809
+ const baseUrl = getResolvedUrl(previewServer);
810
+ async function prerenderRequest(input, metadata) {
811
+ let attemptCount = 0;
812
+ let redirectCount = 0;
813
+ const request = new Request(input);
814
+ const url = new URL(request.url);
815
+ if (url.origin !== baseUrl.origin) {
816
+ url.hostname = baseUrl.hostname;
817
+ url.protocol = baseUrl.protocol;
818
+ url.port = baseUrl.port;
847
819
  }
848
- async function prerender(input, metadata) {
849
- const { files, requests } = normalizePostProcessResult(await prerenderRequest(input, metadata));
850
- for (const file of files) await writePrerenderFile(file, metadata);
851
- for (const followUp of requests) {
852
- const normalized = normalizePrerenderRequest(followUp);
853
- await prerender(normalized.request, normalized.metadata);
820
+ async function attempt(url) {
821
+ try {
822
+ const signal = AbortSignal.timeout(timeout);
823
+ const response = await nodeHttpFetch(new Request(url, request), { signal });
824
+ if (response.status >= 300 && response.status < 400 && response.headers.has("location") && ++redirectCount <= maxRedirects) {
825
+ const location = response.headers.get("location");
826
+ const responseURL = new URL(response.url);
827
+ const locationUrl = new URL(location, response.url);
828
+ if (responseURL.origin !== locationUrl.origin) return await postProcess(request, response, metadata);
829
+ return await attempt(new URL(location, url));
830
+ }
831
+ if (response.status >= 500 && ++attemptCount <= retryCount) {
832
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
833
+ return attempt(url);
834
+ }
835
+ return await postProcess(request, response, metadata);
836
+ } catch (error) {
837
+ if (++attemptCount <= retryCount) {
838
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
839
+ return attempt(url);
840
+ }
841
+ handleError(request, error instanceof Error ? error : new Error(error?.toString() ?? "Unknown error"), metadata);
842
+ return [];
854
843
  }
855
844
  }
856
- async function writePrerenderFile(file, metadata) {
857
- const normalizedPath = file.path.startsWith("/") ? file.path.slice(1) : file.path;
858
- const outputPath = path.join(buildDirectory, ...normalizedPath.split("/"));
859
- await mkdir(path.dirname(outputPath), { recursive: true });
860
- await writeFile(outputPath, file.contents);
861
- const relativePath = path.relative(viteConfig.root, outputPath);
862
- if (logFile) logFile(relativePath, metadata);
863
- return relativePath;
845
+ return attempt(url);
846
+ }
847
+ async function prerender(input, metadata) {
848
+ const { files, requests } = normalizePostProcessResult(await prerenderRequest(input, metadata));
849
+ for (const file of files) await writePrerenderFile(file, metadata);
850
+ for (const followUp of requests) {
851
+ const normalized = normalizePrerenderRequest(followUp);
852
+ await prerender(normalized.request, normalized.metadata);
864
853
  }
865
- await (await import("p-map")).default(prerenderRequests, async ({ request, metadata }) => {
866
- await prerender(request, metadata);
867
- }, { concurrency });
868
- if (finalize) await finalize(buildDirectory);
869
- } finally {
870
- await previewServer.close();
871
854
  }
855
+ async function writePrerenderFile(file, metadata) {
856
+ const normalizedPath = file.path.startsWith("/") ? file.path.slice(1) : file.path;
857
+ const outputPath = path.join(buildDirectory, ...normalizedPath.split("/"));
858
+ await mkdir(path.dirname(outputPath), { recursive: true });
859
+ await writeFile(outputPath, file.contents);
860
+ const relativePath = path.relative(viteConfig.root, outputPath);
861
+ if (logFile) logFile(relativePath, metadata);
862
+ return relativePath;
863
+ }
864
+ await (await import("p-map")).default(prerenderRequests, async ({ request, metadata }) => {
865
+ await prerender(request, metadata);
866
+ }, { concurrency });
867
+ if (finalize) await finalize(buildDirectory);
872
868
  } finally {
873
- process.env.IS_RR_BUILD_REQUEST = ogIsBuildRequest;
869
+ await previewServer.close();
874
870
  }
875
- } } };
871
+ } catch (error) {
872
+ await cleanup?.();
873
+ throw error;
874
+ } finally {
875
+ process.env.IS_RR_BUILD_REQUEST = ogIsBuildRequest;
876
+ }
876
877
  }
877
878
  },
878
879
  configResolved(resolvedConfig) {
@@ -1158,8 +1159,14 @@ const getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRout
1158
1159
  if (!viteChildCompiler) throw new Error("Vite child compiler not found");
1159
1160
  return getExportNames(await compileRouteFile(viteChildCompiler, ctx, routeFile, readRouteFile));
1160
1161
  };
1161
- let getServerBuildDirectory = (reactRouterConfig, { serverBundleId } = {}) => path$2.join(reactRouterConfig.buildDirectory, "server", ...serverBundleId ? [serverBundleId] : []);
1162
- let getClientBuildDirectory$1 = (reactRouterConfig) => path$2.join(reactRouterConfig.buildDirectory, "client");
1162
+ let getDefaultServerBuildDirectory = (reactRouterConfig, { serverBundleId } = {}) => path$2.join(reactRouterConfig.buildDirectory, "server", ...serverBundleId ? [serverBundleId] : []);
1163
+ let getDefaultClientBuildDirectory = (reactRouterConfig) => path$2.join(reactRouterConfig.buildDirectory, "client");
1164
+ let getClientBuildDirectory$1 = (viteConfig) => path$2.resolve(viteConfig.root, viteConfig.environments.client.build.outDir);
1165
+ let getServerBuildDirectory = (viteConfig, environmentName = "ssr") => {
1166
+ let environment = viteConfig.environments[environmentName];
1167
+ invariant(environment, `Vite environment "${environmentName}" not found`);
1168
+ return path$2.resolve(viteConfig.root, environment.build.outDir);
1169
+ };
1163
1170
  let getServerBundleRouteIds = (vitePluginContext, ctx) => {
1164
1171
  if (!ctx.buildManifest) return;
1165
1172
  let environmentName = vitePluginContext.environment.name;
@@ -1189,9 +1196,12 @@ const reactRouterVitePlugin = () => {
1189
1196
  let logger;
1190
1197
  let firstLoad = true;
1191
1198
  let ctx;
1192
- let closePluginResources = async () => {
1199
+ let closeChildCompiler = async () => {
1193
1200
  await viteChildCompiler?.close();
1194
1201
  viteChildCompiler = null;
1202
+ };
1203
+ let closePluginResources = async () => {
1204
+ await closeChildCompiler();
1195
1205
  await reactRouterConfigLoader.close();
1196
1206
  await (await typegenWatcherPromise)?.close();
1197
1207
  typegenWatcherPromise = void 0;
@@ -1233,6 +1243,12 @@ const reactRouterVitePlugin = () => {
1233
1243
  buildManifest
1234
1244
  };
1235
1245
  };
1246
+ let updateServerBundlePaths = () => {
1247
+ if (!ctx.buildManifest?.serverBundles) return;
1248
+ invariant(viteConfig);
1249
+ let { normalizePath } = getVite();
1250
+ for (let bundle of Object.values(ctx.buildManifest.serverBundles)) bundle.file = normalizePath(path$2.join(path$2.relative(ctx.rootDirectory, getServerBuildDirectory(viteConfig, `${SSR_BUNDLE_PREFIX}${bundle.id}`)), ctx.reactRouterConfig.serverBuildFile));
1251
+ };
1236
1252
  let getServerEntry = async ({ routeIds }) => {
1237
1253
  invariant(viteConfig, "viteconfig required to generate the server entry");
1238
1254
  let routes = routeIds ? pick(ctx.reactRouterConfig.routes, routeIds) : ctx.reactRouterConfig.routes;
@@ -1248,7 +1264,7 @@ const reactRouterVitePlugin = () => {
1248
1264
  else return `import * as route${index} from ${JSON.stringify(resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig), { publicPath: ctx.publicPath }))};`;
1249
1265
  }).join("\n")}
1250
1266
  export { default as assets } from ${JSON.stringify(virtual$1.serverManifest.id)};
1251
- export const assetsBuildDirectory = ${JSON.stringify(path$2.relative(ctx.rootDirectory, getClientBuildDirectory$1(ctx.reactRouterConfig)))};
1267
+ export const assetsBuildDirectory = ${JSON.stringify(path$2.relative(ctx.rootDirectory, getClientBuildDirectory$1(viteConfig)))};
1252
1268
  export const basename = ${JSON.stringify(ctx.reactRouterConfig.basename)};
1253
1269
  export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
1254
1270
  export const ssr = ${Boolean(ctx.reactRouterConfig.ssr)};
@@ -1292,8 +1308,8 @@ const reactRouterVitePlugin = () => {
1292
1308
  let chunkAssetPaths = Object.values(viteManifest).flatMap((chunk) => chunk.assets ?? []);
1293
1309
  return new Set([...cssUrlPaths, ...chunkAssetPaths]);
1294
1310
  };
1295
- let generateSriManifest = async (ctx) => {
1296
- let clientBuildDirectory = getClientBuildDirectory$1(ctx.reactRouterConfig);
1311
+ let generateSriManifest = async (ctx, viteConfig) => {
1312
+ let clientBuildDirectory = getClientBuildDirectory$1(viteConfig);
1297
1313
  let entries = readdirSync(clientBuildDirectory, {
1298
1314
  withFileTypes: true,
1299
1315
  recursive: true
@@ -1316,7 +1332,7 @@ const reactRouterVitePlugin = () => {
1316
1332
  };
1317
1333
  let generateReactRouterManifestsForBuild = async ({ viteConfig, routeIds }) => {
1318
1334
  invariant(viteConfig);
1319
- let viteManifest = await loadViteManifest(getClientBuildDirectory$1(ctx.reactRouterConfig));
1335
+ let viteManifest = await loadViteManifest(getClientBuildDirectory$1(viteConfig));
1320
1336
  let allDynamicCssFiles = getAllDynamicCssFiles(ctx, viteManifest);
1321
1337
  let entry = getReactRouterManifestBuildAssets(ctx, viteConfig, viteManifest, allDynamicCssFiles, ctx.entryClientFilePath, null);
1322
1338
  let browserRoutes = {};
@@ -1381,9 +1397,9 @@ const reactRouterVitePlugin = () => {
1381
1397
  ...nonFingerprintedValues,
1382
1398
  sri: void 0
1383
1399
  };
1384
- await writeFileSafe(path$2.join(getClientBuildDirectory$1(ctx.reactRouterConfig), manifestPath), `window.__reactRouterManifest=${JSON.stringify(reactRouterBrowserManifest)};`);
1400
+ await writeFileSafe(path$2.join(getClientBuildDirectory$1(viteConfig), manifestPath), `window.__reactRouterManifest=${JSON.stringify(reactRouterBrowserManifest)};`);
1385
1401
  let sri = void 0;
1386
- if (ctx.reactRouterConfig.subResourceIntegrity) sri = await generateSriManifest(ctx);
1402
+ if (ctx.reactRouterConfig.subResourceIntegrity) sri = await generateSriManifest(ctx, viteConfig);
1387
1403
  return {
1388
1404
  reactRouterBrowserManifest,
1389
1405
  reactRouterServerManifest: {
@@ -1494,11 +1510,16 @@ const reactRouterVitePlugin = () => {
1494
1510
  watch: viteCommand === "serve"
1495
1511
  });
1496
1512
  await updatePluginContext();
1513
+ if (_viteConfigEnv.isPreview && ctx.reactRouterConfig.serverBundles) ctx.buildManifest = await getBuildManifest({
1514
+ reactRouterConfig: ctx.reactRouterConfig,
1515
+ rootDirectory: ctx.rootDirectory
1516
+ });
1497
1517
  let environments = await getEnvironmentsOptions(ctx, viteCommand, { viteUserConfig });
1498
1518
  let serverEnvironment = getServerEnvironmentValues(ctx, environments)[0];
1499
1519
  invariant(serverEnvironment);
1500
1520
  return {
1501
1521
  __reactRouterPluginContext: ctx,
1522
+ __reactRouterBuildContext: { close: closePluginResources },
1502
1523
  appType: viteCommand === "serve" && _viteConfigEnv.mode === "production" && (!ctx.reactRouterConfig.ssr || ctx.reactRouterConfig.ssr === "unstable_api-only") ? isApiOnlyMode(ctx.reactRouterConfig) ? "mpa" : "spa" : "custom",
1503
1524
  ssr: {
1504
1525
  external: serverEnvironment.resolve?.external,
@@ -1552,7 +1573,7 @@ const reactRouterVitePlugin = () => {
1552
1573
  await builder.build(builder.environments.client);
1553
1574
  let serverEnvironments = getServerEnvironmentValues(ctx, builder.environments);
1554
1575
  await Promise.all(serverEnvironments.map(builder.build));
1555
- await cleanViteManifests(environments, ctx);
1576
+ await cleanViteManifests([builder.environments.client, ...serverEnvironments], ctx);
1556
1577
  }
1557
1578
  }
1558
1579
  };
@@ -1685,11 +1706,10 @@ const reactRouterVitePlugin = () => {
1685
1706
  let cachedHandler = null;
1686
1707
  async function getHandler() {
1687
1708
  if (cachedHandler) return cachedHandler;
1709
+ invariant(viteConfig);
1710
+ updateServerBundlePaths();
1688
1711
  let bundledHandlers = [];
1689
- let buildManifest = ctx.buildManifest ?? (ctx.reactRouterConfig.serverBundles ? await getBuildManifest({
1690
- reactRouterConfig: ctx.reactRouterConfig,
1691
- rootDirectory: ctx.rootDirectory
1692
- }) : null);
1712
+ let { buildManifest } = ctx;
1693
1713
  if (buildManifest?.serverBundles) {
1694
1714
  let routesByServerBundleId = getRoutesByServerBundleId(buildManifest);
1695
1715
  for (let bundle of Object.values(buildManifest.serverBundles)) {
@@ -1700,7 +1720,7 @@ const reactRouterVitePlugin = () => {
1700
1720
  });
1701
1721
  }
1702
1722
  } else {
1703
- let serverEntryPath = path$2.resolve(getServerBuildDirectory(ctx.reactRouterConfig), "index.js");
1723
+ let serverEntryPath = path$2.resolve(getServerBuildDirectory(viteConfig), "index.js");
1704
1724
  let build = await import(url.pathToFileURL(serverEntryPath).href);
1705
1725
  bundledHandlers.push({
1706
1726
  handler: createRequestHandler(build, "production"),
@@ -1737,7 +1757,7 @@ const reactRouterVitePlugin = () => {
1737
1757
  let manifestPath = routeDiscovery?.mode === "lazy" ? path$2.posix.join(basename, routeDiscovery.manifestPath ?? "/__manifest") : void 0;
1738
1758
  let pathname = new URL(req.originalUrl ?? req.url ?? "/", "http://localhost").pathname;
1739
1759
  if (!pathname.endsWith(".data") && pathname !== manifestPath) {
1740
- let clientBuildDirectory = getClientBuildDirectory$1(ctx.reactRouterConfig);
1760
+ let clientBuildDirectory = getClientBuildDirectory$1(previewServer.config);
1741
1761
  let previewPathname = decodeURIComponent(new URL(req.url ?? "/", "http://localhost").pathname);
1742
1762
  if (previewPathname.endsWith(".html") && existsSync(path$2.join(clientBuildDirectory, previewPathname))) return next();
1743
1763
  let fallbackFile = path$2.join(clientBuildDirectory, "__spa-fallback.html");
@@ -1759,9 +1779,8 @@ const reactRouterVitePlugin = () => {
1759
1779
  writeBundle: { async handler() {
1760
1780
  if (!isReactRouterServerEnvironment(ctx, this.environment.name)) return;
1761
1781
  invariant(viteConfig);
1762
- let clientBuildDirectory = getClientBuildDirectory$1(ctx.reactRouterConfig);
1763
- let serverBuildDirectory = this.environment.config?.build?.outDir;
1764
- invariant(serverBuildDirectory);
1782
+ let clientBuildDirectory = getClientBuildDirectory$1(viteConfig);
1783
+ let serverBuildDirectory = path$2.resolve(this.environment.config.root, this.environment.config.build.outDir);
1765
1784
  let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
1766
1785
  let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
1767
1786
  let userSsrEmitAssets = viteUserConfig.environments?.ssr?.build?.ssrEmitAssets ?? viteUserConfig.environments?.ssr?.build?.emitAssets ?? viteUserConfig.build?.ssrEmitAssets ?? false;
@@ -1819,8 +1838,8 @@ const reactRouterVitePlugin = () => {
1819
1838
  logHandledAssets(copiedAssetPaths, `${copiedAssetPaths.length} asset${copiedAssetPaths.length > 1 ? "s" : ""} copied from React Router server build to client assets.`);
1820
1839
  if (handledAssetPaths.length) viteConfig.logger.info("");
1821
1840
  } },
1822
- async buildEnd() {
1823
- if (viteConfig?.command !== "build") await closePluginResources();
1841
+ async buildEnd(error) {
1842
+ if (viteConfig?.command !== "build" || error) await closePluginResources();
1824
1843
  }
1825
1844
  },
1826
1845
  {
@@ -2118,10 +2137,7 @@ const reactRouterVitePlugin = () => {
2118
2137
  prerender({
2119
2138
  config() {
2120
2139
  process.env.IS_RR_BUILD_REQUEST = "yes";
2121
- return {
2122
- buildDirectory: getClientBuildDirectory$1(ctx.reactRouterConfig),
2123
- concurrency: getPrerenderConcurrencyConfig$1(ctx.reactRouterConfig)
2124
- };
2140
+ return { concurrency: getPrerenderConcurrencyConfig$1(ctx.reactRouterConfig) };
2125
2141
  },
2126
2142
  async requests() {
2127
2143
  invariant(viteConfig);
@@ -2207,6 +2223,9 @@ const reactRouterVitePlugin = () => {
2207
2223
  if (metadata.type === "spa") return;
2208
2224
  viteConfig.logger.info(`Prerender (${metadata.type}): ${metadata.path} -> ${colors.bold(outputPath)}`);
2209
2225
  },
2226
+ cleanup() {
2227
+ return closePluginResources();
2228
+ },
2210
2229
  async finalize(buildDirectory) {
2211
2230
  invariant(viteConfig);
2212
2231
  let { ssr } = ctx.reactRouterConfig;
@@ -2228,6 +2247,7 @@ const reactRouterVitePlugin = () => {
2228
2247
  }),
2229
2248
  {
2230
2249
  name: "react-router-build-end",
2250
+ enforce: "post",
2231
2251
  sharedDuringBuild: true,
2232
2252
  config: {
2233
2253
  order: "post",
@@ -2235,19 +2255,31 @@ const reactRouterVitePlugin = () => {
2235
2255
  return { builder: { async buildApp(builder) {
2236
2256
  try {
2237
2257
  await buildApp?.(builder);
2238
- invariant(viteConfig);
2239
- let { buildManifest, reactRouterConfig } = ctx;
2240
- invariant(buildManifest, "Expected build manifest");
2241
- await reactRouterConfig.buildEnd?.({
2242
- buildManifest,
2243
- reactRouterConfig,
2244
- viteConfig
2245
- });
2246
- } finally {
2258
+ } catch (error) {
2247
2259
  await closePluginResources();
2260
+ throw error;
2248
2261
  }
2262
+ await closeChildCompiler();
2249
2263
  } } };
2250
2264
  }
2265
+ },
2266
+ buildApp: {
2267
+ order: "post",
2268
+ async handler() {
2269
+ try {
2270
+ invariant(viteConfig);
2271
+ let { buildManifest, reactRouterConfig } = ctx;
2272
+ invariant(buildManifest, "Expected build manifest");
2273
+ updateServerBundlePaths();
2274
+ await reactRouterConfig.buildEnd?.({
2275
+ buildManifest,
2276
+ reactRouterConfig,
2277
+ viteConfig
2278
+ });
2279
+ } finally {
2280
+ await closePluginResources();
2281
+ }
2282
+ }
2251
2283
  }
2252
2284
  },
2253
2285
  validatePluginOrder(),
@@ -2541,12 +2573,8 @@ async function cleanBuildDirectory(viteConfig, ctx) {
2541
2573
  recursive: true
2542
2574
  });
2543
2575
  }
2544
- async function cleanViteManifests(environmentsOptions, ctx) {
2545
- let viteManifestPaths = Object.entries(environmentsOptions).map(([environmentName, options]) => {
2546
- let outDir = options.build?.outDir;
2547
- invariant(outDir, `Expected build.outDir for ${environmentName}`);
2548
- return path$2.join(outDir, ".vite/manifest.json");
2549
- });
2576
+ async function cleanViteManifests(environments, ctx) {
2577
+ let viteManifestPaths = environments.map(({ config }) => path$2.resolve(config.root, config.build.outDir, ".vite/manifest.json"));
2550
2578
  await Promise.all(viteManifestPaths.map(async (viteManifestPath) => {
2551
2579
  if (!existsSync(viteManifestPath)) return;
2552
2580
  if (!ctx.viteManifestEnabled) await rm(viteManifestPath, {
@@ -2564,7 +2592,7 @@ async function getBuildManifest({ reactRouterConfig, rootDirectory }) {
2564
2592
  let { routes, serverBundles, appDirectory } = reactRouterConfig;
2565
2593
  if (!serverBundles) return { routes };
2566
2594
  let { normalizePath } = await import("vite");
2567
- let serverBuildDirectory = getServerBuildDirectory(reactRouterConfig);
2595
+ let serverBuildDirectory = getDefaultServerBuildDirectory(reactRouterConfig);
2568
2596
  let resolvedAppDirectory = path$2.resolve(rootDirectory, appDirectory);
2569
2597
  let buildManifest = {
2570
2598
  serverBundles: {},
@@ -2663,14 +2691,14 @@ async function getEnvironmentOptionsResolvers(ctx, viteCommand) {
2663
2691
  return path$2.posix.join(assetsDir, `[name]${routeChunkSuffix}-[hash].js`);
2664
2692
  } }
2665
2693
  },
2666
- outDir: getClientBuildDirectory$1(ctx.reactRouterConfig)
2694
+ outDir: getDefaultClientBuildDirectory(ctx.reactRouterConfig)
2667
2695
  } }) };
2668
2696
  let serverBundleIds = getServerBundleIds(ctx);
2669
2697
  if (serverBundleIds) for (let serverBundleId of serverBundleIds) {
2670
2698
  const environmentName = `${SSR_BUNDLE_PREFIX}${serverBundleId}`;
2671
- environmentOptionsResolvers[environmentName] = ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseServerOptions({ viteUserConfig }), { build: { outDir: getServerBuildDirectory(ctx.reactRouterConfig, { serverBundleId }) } }, viteUserConfig.environments?.ssr ?? {});
2699
+ environmentOptionsResolvers[environmentName] = ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseServerOptions({ viteUserConfig }), { build: { outDir: getDefaultServerBuildDirectory(ctx.reactRouterConfig, { serverBundleId }) } }, viteUserConfig.environments?.ssr ?? {});
2672
2700
  }
2673
- else environmentOptionsResolvers.ssr = ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseServerOptions({ viteUserConfig }), { build: { outDir: getServerBuildDirectory(ctx.reactRouterConfig) } });
2701
+ else environmentOptionsResolvers.ssr = ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseServerOptions({ viteUserConfig }), { build: { outDir: getDefaultServerBuildDirectory(ctx.reactRouterConfig) } });
2674
2702
  return environmentOptionsResolvers;
2675
2703
  }
2676
2704
  function resolveEnvironmentsOptions(environmentResolvers, resolverOptions) {
@@ -3305,6 +3333,7 @@ function reactRouterRSCVitePlugin() {
3305
3333
  });
3306
3334
  let routeFiles = new Set(Object.values(config.routes).map((route) => resolveRelativeRouteFilePath(route, config)));
3307
3335
  return {
3336
+ __reactRouterBuildContext: { close: () => configLoader.close() },
3308
3337
  resolve: { dedupe: [
3309
3338
  "react",
3310
3339
  "react/jsx-runtime",
@@ -3420,7 +3449,7 @@ format: config.serverModuleFormat }
3420
3449
  });
3421
3450
  },
3422
3451
  configurePreviewServer(previewServer) {
3423
- const clientBuildDirectory = getClientBuildDirectory(config);
3452
+ const clientBuildDirectory = getClientBuildDirectory(resolvedViteConfig);
3424
3453
  if ((config.prerender || config.ssr === false) && process.env.IS_RR_BUILD_REQUEST !== "yes") {
3425
3454
  previewServer.middlewares.use(async (req, res, next) => {
3426
3455
  try {
@@ -3455,11 +3484,8 @@ format: config.serverModuleFormat }
3455
3484
  };
3456
3485
  }
3457
3486
  },
3458
- buildApp: {
3459
- order: "post",
3460
- async handler() {
3461
- await configLoader.close();
3462
- }
3487
+ async buildEnd(error) {
3488
+ if (error) await configLoader.close();
3463
3489
  }
3464
3490
  },
3465
3491
  (() => {
@@ -3626,12 +3652,10 @@ export default assetsManifest.clientVersion;
3626
3652
  warnOnClientSourceMaps(),
3627
3653
  prerender({
3628
3654
  config() {
3629
- return {
3630
- buildDirectory: getClientBuildDirectory(config),
3631
- concurrency: getPrerenderConcurrencyConfig(config)
3632
- };
3655
+ return { concurrency: getPrerenderConcurrencyConfig(config) };
3633
3656
  },
3634
3657
  logFile: (path) => logger.info(`Prerendered ${colors.bold(path)}`),
3658
+ cleanup: () => configLoader.close(),
3635
3659
  async requests() {
3636
3660
  const prerenderPaths = new Set(await getPrerenderPaths(config.prerender, config.ssr, config.routes, true));
3637
3661
  let basename = !config.basename || config.basename === "/" ? "/" : config.basename.endsWith("/") ? config.basename : config.basename + "/";
@@ -3687,7 +3711,18 @@ export default assetsManifest.clientVersion;
3687
3711
  }
3688
3712
  return files;
3689
3713
  }
3690
- })
3714
+ }),
3715
+ {
3716
+ name: "react-router/rsc/build-end",
3717
+ enforce: "post",
3718
+ sharedDuringBuild: true,
3719
+ buildApp: {
3720
+ order: "post",
3721
+ async handler() {
3722
+ await configLoader.close();
3723
+ }
3724
+ }
3725
+ }
3691
3726
  ];
3692
3727
  }
3693
3728
  const virtual = {
@@ -3727,7 +3762,7 @@ function createRSCOptimizeDepsRouteModulesPlugin({ routeFiles, transformToJs })
3727
3762
  }
3728
3763
  };
3729
3764
  }
3730
- const getClientBuildDirectory = (reactRouterConfig) => path$1.join(reactRouterConfig.buildDirectory, "client");
3765
+ const getClientBuildDirectory = (viteConfig) => path$1.resolve(viteConfig.root, viteConfig.environments.client.build.outDir);
3731
3766
  function getPrerenderConcurrencyConfig(reactRouterConfig) {
3732
3767
  let concurrency = 1;
3733
3768
  let { prerender } = reactRouterConfig;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@react-router/dev",
3
3
  "type": "module",
4
- "version": "8.5.0",
4
+ "version": "8.5.1",
5
5
  "description": "Dev tools and CLI for React Router",
6
6
  "keywords": [
7
7
  "react",
@@ -107,7 +107,7 @@
107
107
  "semver": "^7.8.1",
108
108
  "tinyglobby": "^0.2.16",
109
109
  "valibot": "^1.4.1",
110
- "@react-router/node": "8.5.0"
110
+ "@react-router/node": "8.5.1"
111
111
  },
112
112
  "devDependencies": {
113
113
  "@babel/plugin-syntax-jsx": "^7.29.7",
@@ -132,8 +132,8 @@
132
132
  "vite": "^7.0.0",
133
133
  "wireit": "0.14.12",
134
134
  "wrangler": "^4.95.0",
135
- "react-router": "^8.5.0",
136
- "@react-router/serve": "8.5.0"
135
+ "@react-router/serve": "8.5.1",
136
+ "react-router": "^8.5.1"
137
137
  },
138
138
  "peerDependencies": {
139
139
  "@vitejs/plugin-rsc": "~0.5.26",
@@ -141,8 +141,8 @@
141
141
  "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0",
142
142
  "vite": "^7.0.0 || ^8.0.0",
143
143
  "wrangler": "^4.0.0",
144
- "@react-router/serve": "^8.5.0",
145
- "react-router": "^8.5.0"
144
+ "@react-router/serve": "^8.5.1",
145
+ "react-router": "^8.5.1"
146
146
  },
147
147
  "peerDependenciesMeta": {
148
148
  "@vitejs/plugin-rsc": {