@react-router/dev 8.2.0 → 8.3.0

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,45 @@
1
1
  # `@react-router/dev`
2
2
 
3
+ ## v8.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Restart `react-router dev` with `--conditions=development` when not already configured ([#15291](https://github.com/remix-run/react-router/pull/15291))
8
+
9
+ ### Patch Changes
10
+
11
+ - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
12
+
13
+ ### Unstable Changes
14
+
15
+ ⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
16
+
17
+ - Add `unstable_rsc/client-version` client build version virtual module ([#15318](https://github.com/remix-run/react-router/pull/15318))
18
+
19
+ - Support the `subResourceIntegrity` config option in RSC Framework Mode ([#15321](https://github.com/remix-run/react-router/pull/15321))
20
+
21
+ #### Migration guide
22
+
23
+ No changes are required when using the default RSC SSR entry. If you maintain a custom `app/entry.ssr.tsx`, import the new virtual module and pass its hashes to React's `importMap` render option:
24
+
25
+ ```diff
26
+ +import subResourceIntegrity from "virtual:react-router/unstable_rsc/subresource-integrity";
27
+
28
+ return renderToReadableStream(<RSCStaticRouter getPayload={getPayload} />, {
29
+ ...options,
30
+ bootstrapScriptContent,
31
+ formState,
32
+ + importMap: subResourceIntegrity
33
+ + ? { integrity: subResourceIntegrity }
34
+ + : undefined,
35
+ signal: request.signal,
36
+ });
37
+ ```
38
+ - Updated dependencies:
39
+ - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0)
40
+ - [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0)
41
+ - [`@react-router/serve@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/serve@8.3.0)
42
+
3
43
  ## v8.2.0
4
44
 
5
45
  ### Minor Changes
@@ -16,7 +56,7 @@
16
56
 
17
57
  ### Unstable Changes
18
58
 
19
- ⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
59
+ ⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
20
60
 
21
61
  - Add the [`future.unstable_enableNodeReadableStream`](https://reactrouter.com/upgrading/future#futureunstable_enablenodereadablestream) flag to opt Node Framework mode apps into using `renderToReadableStream` instead of `renderToPipeableStream` ([#15290](https://github.com/remix-run/react-router/pull/15290))
22
62
  - This flag has no effect if you have your own `entry.server.tsx`
@@ -0,0 +1,2 @@
1
+ declare const developmentConditionEnabled: boolean;
2
+ export default developmentConditionEnabled;
@@ -0,0 +1,2 @@
1
+ const developmentConditionEnabled = false;
2
+ export default developmentConditionEnabled;
@@ -0,0 +1,2 @@
1
+ declare const developmentConditionEnabled: boolean;
2
+ export default developmentConditionEnabled;
@@ -0,0 +1,2 @@
1
+ const developmentConditionEnabled = true;
2
+ export default developmentConditionEnabled;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.2.0
2
+ * @react-router/dev v8.3.0
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-CNpfI4aI.js";
11
+ import { _ as getVite, v as preloadVite } from "./typegen-C6qQ4fuP.js";
12
12
  //#region vite/build.ts
13
13
  async function build(root, viteBuildOptions) {
14
14
  await preloadVite();
package/dist/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * @react-router/dev v8.2.0
3
+ * @react-router/dev v8.3.0
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-CNpfI4aI.js";
12
+ import { _ as getVite, l as hasNodeDependency, n as watch, t as run$1, u as loadConfig, v as preloadVite } from "../typegen-C6qQ4fuP.js";
13
13
  import { createRequire } from "node:module";
14
14
  import { parseArgs } from "node:util";
15
15
  import semver from "semver";
@@ -21,10 +21,13 @@ import path from "node:path";
21
21
  import exitHook from "exit-hook";
22
22
  import { readPackageJSON } from "pkg-types";
23
23
  import "react-router";
24
+ import developmentConditionEnabled from "#development-condition-enabled";
25
+ import { spawn } from "node:child_process";
24
26
  import * as babel from "@babel/core";
25
27
  import babelPluginSyntaxJSX from "@babel/plugin-syntax-jsx";
26
28
  import babelPresetTypeScript from "@babel/preset-typescript";
27
29
  import prettier from "prettier";
30
+ import process$1 from "node:process";
28
31
  import packageJson from "@react-router/dev/package.json" with { type: "json" };
29
32
  //#region config/format.ts
30
33
  function formatRoutes(routeManifest, format) {
@@ -124,6 +127,42 @@ async function hasReactRouterRscPlugin({ root, viteBuildOptions: { config, logLe
124
127
  }, "build", "production", "production")).plugins.some((plugin) => plugin?.name === "react-router/rsc");
125
128
  }
126
129
  //#endregion
130
+ //#region restart-with-conditions.ts
131
+ /**
132
+ * Restarts the current Node process, appending new flags to the
133
+ * existing NODE_OPTIONS. SIGINT/SIGTERM are always forwarded to the child.
134
+ */
135
+ function restartWithMergedOptions(nodeOptions) {
136
+ if (process$1.env.REACT_ROUTER_DEV_RESTARTED === "true") throw new Error("restartWithMergedOptions() was called, but the process has already been restarted. This is likely a bug in @react-router/dev.");
137
+ const mergedOptions = [process$1.env.NODE_OPTIONS, nodeOptions].filter(Boolean).join(" ").trim();
138
+ console.log(`[restart] Relaunching with NODE_OPTIONS: ${mergedOptions}`);
139
+ const [cmd, ...args] = process$1.argv;
140
+ const child = spawn(cmd, args, {
141
+ env: {
142
+ ...process$1.env,
143
+ NODE_OPTIONS: mergedOptions,
144
+ REACT_ROUTER_DEV_RESTARTED: "true"
145
+ },
146
+ stdio: "inherit"
147
+ });
148
+ let signalHandlers = ["SIGINT", "SIGTERM"].map((sig) => {
149
+ let handler = () => {
150
+ child.kill(sig);
151
+ };
152
+ process$1.on(sig, handler);
153
+ return [sig, handler];
154
+ });
155
+ child.on("exit", (code, signal) => {
156
+ for (let [sig, handler] of signalHandlers) process$1.off(sig, handler);
157
+ if (signal) process$1.kill(process$1.pid, signal);
158
+ else process$1.exit(code ?? 0);
159
+ });
160
+ child.on("error", (err) => {
161
+ console.error("[restart] Failed to spawn child process:", err);
162
+ process$1.exit(1);
163
+ });
164
+ }
165
+ //#endregion
127
166
  //#region cli/commands.ts
128
167
  const nodeRequire = createRequire(import.meta.url);
129
168
  async function routes(rootDirectory, flags = {}) {
@@ -141,7 +180,7 @@ async function routes(rootDirectory, flags = {}) {
141
180
  }
142
181
  async function build(root, options = {}) {
143
182
  root = resolveRootDirectory(root, options);
144
- let { build } = await import("../build-r3D94V53.js");
183
+ let { build } = await import("../build-B8O1OXuF.js");
145
184
  if (options.profile) await start();
146
185
  try {
147
186
  await build(root, options);
@@ -150,11 +189,13 @@ async function build(root, options = {}) {
150
189
  }
151
190
  }
152
191
  async function dev(root, options = {}) {
153
- let { dev } = await import("../dev-BfZiothP.js");
154
- if (options.profile) await start();
155
- exitHook(() => stop(console.info));
156
- root = resolveRootDirectory(root, options);
157
- await dev(root, options);
192
+ if (developmentConditionEnabled) {
193
+ let { dev } = await import("../dev-CznbsRZe.js");
194
+ if (options.profile) await start();
195
+ exitHook(() => stop(console.info));
196
+ root = resolveRootDirectory(root, options);
197
+ await dev(root, options);
198
+ } else restartWithMergedOptions("--conditions=development");
158
199
  await new Promise(() => {});
159
200
  }
160
201
  let clientEntries = [
@@ -15,6 +15,7 @@ import {
15
15
  import routes from "virtual:react-router/unstable_rsc/routes";
16
16
  import routeDiscovery from "virtual:react-router/unstable_rsc/route-discovery";
17
17
  import basename from "virtual:react-router/unstable_rsc/basename";
18
+ import clientVersion from "virtual:react-router/unstable_rsc/client-version";
18
19
  import unstable_reactRouterServeConfig from "virtual:react-router/unstable_rsc/react-router-serve-config";
19
20
 
20
21
  export { unstable_reactRouterServeConfig };
@@ -31,6 +32,8 @@ export function fetchServer(
31
32
  decodeFormState,
32
33
  decodeReply,
33
34
  loadServerAction,
35
+ // Detect stale clients after a new deployment.
36
+ clientVersion,
34
37
  // The incoming request.
35
38
  request,
36
39
  requestContext,
@@ -4,6 +4,7 @@ import {
4
4
  unstable_routeRSCServerRequest as routeRSCServerRequest,
5
5
  unstable_RSCStaticRouter as RSCStaticRouter,
6
6
  } from "react-router";
7
+ import subResourceIntegrity from "virtual:react-router/unstable_rsc/subresource-integrity";
7
8
 
8
9
  export async function generateHTML(
9
10
  request: Request,
@@ -31,6 +32,9 @@ export async function generateHTML(
31
32
  ...options,
32
33
  bootstrapScriptContent,
33
34
  formState,
35
+ importMap: subResourceIntegrity
36
+ ? { integrity: subResourceIntegrity }
37
+ : undefined,
34
38
  signal: request.signal,
35
39
  },
36
40
  );
package/dist/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.2.0
2
+ * @react-router/dev v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.2.0
2
+ * @react-router/dev v8.3.0
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-CNpfI4aI.js";
11
+ import { _ as getVite, v as preloadVite } from "./typegen-C6qQ4fuP.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.2.0
2
+ * @react-router/dev v8.3.0
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.2.0
2
+ * @react-router/dev v8.3.0
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-CdiIrVIn.js";
11
+ import { a as prefix, i as layout, n as getAppDirectory, o as relative, r as index, s as route } from "./routes-BwOSW5AT.js";
12
12
  export { getAppDirectory, index, layout, prefix, relative, route };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v8.2.0
2
+ * @react-router/dev v8.3.0
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-CdiIrVIn.js";
11
+ import { c as setAppDirectory, l as validateRouteConfig, t as configRoutesToRouteManifest, u as invariant } from "./routes-BwOSW5AT.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.2.0
2
+ * @react-router/dev v8.3.0
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-CNpfI4aI.js";
12
- import { u as invariant } from "./routes-CdiIrVIn.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-C6qQ4fuP.js";
12
+ import { u as invariant } from "./routes-BwOSW5AT.js";
13
13
  import { createRequire } from "node:module";
14
14
  import colors from "picocolors";
15
15
  import { existsSync, readFileSync, readdirSync } from "node:fs";
@@ -3184,6 +3184,10 @@ function reactRouterRSCVitePlugin() {
3184
3184
  jsxDev: viteCommand !== "build"
3185
3185
  })).code;
3186
3186
  }
3187
+ async function getClientVersion(source) {
3188
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(source));
3189
+ return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, 8);
3190
+ }
3187
3191
  return [
3188
3192
  {
3189
3193
  name: "react-router/rsc",
@@ -3207,7 +3211,6 @@ function reactRouterRSCVitePlugin() {
3207
3211
  if (userConfig.buildEnd) errors.push("buildEnd");
3208
3212
  if (userConfig.presets?.length) errors.push("presets");
3209
3213
  if (userConfig.serverBundles) errors.push("serverBundles");
3210
- if (userConfig.subResourceIntegrity) errors.push("subResourceIntegrity");
3211
3214
  if (errors.length) return `RSC Framework Mode does not currently support the following React Router config:\n${errors.map((x) => ` - ${x}`).join("\n")}\n`;
3212
3215
  }
3213
3216
  });
@@ -3412,6 +3415,29 @@ format: config.serverModuleFormat }
3412
3415
  (await typegenWatcherPromise)?.close();
3413
3416
  }
3414
3417
  } : null,
3418
+ (() => {
3419
+ let sri;
3420
+ return {
3421
+ name: "react-router/rsc/subresource-integrity",
3422
+ sharedDuringBuild: true,
3423
+ resolveId(id) {
3424
+ if (id === virtual.subResourceIntegrity.id) return virtual.subResourceIntegrity.resolvedId;
3425
+ },
3426
+ load(id) {
3427
+ if (id === virtual.subResourceIntegrity.resolvedId) return `export default ${JSON.stringify(sri)};`;
3428
+ },
3429
+ writeBundle(_options, bundle) {
3430
+ if (this.environment.name !== "client" || !config.subResourceIntegrity) return;
3431
+ sri = {};
3432
+ for (let output of Object.values(bundle)) {
3433
+ if (!output.fileName.endsWith(".js")) continue;
3434
+ let contents = output.type === "chunk" ? output.code : output.source;
3435
+ let hash = createHash("sha384").update(contents).digest("base64");
3436
+ sri[`${resolvedViteConfig.base}${output.fileName}`] = `sha384-${hash}`;
3437
+ }
3438
+ }
3439
+ };
3440
+ })(),
3415
3441
  {
3416
3442
  name: "react-router/rsc/virtual-route-config",
3417
3443
  resolveId(id) {
@@ -3456,6 +3482,27 @@ format: config.serverModuleFormat }
3456
3482
  if (id === virtual.routeDiscovery.resolvedId) return `export default ${JSON.stringify(config.ssr === false ? { mode: "initial" } : config.routeDiscovery ?? { mode: "lazy" })};`;
3457
3483
  }
3458
3484
  },
3485
+ {
3486
+ name: "react-router/rsc/virtual-client-version",
3487
+ resolveId(id) {
3488
+ if (id === virtual.clientVersion.id) return virtual.clientVersion.resolvedId;
3489
+ },
3490
+ load(id) {
3491
+ if (id === virtual.clientVersion.resolvedId) return viteCommand === "build" ? `
3492
+ import assetsManifest from "virtual:vite-rsc/assets-manifest";
3493
+ export default assetsManifest.clientVersion;
3494
+ ` : `export default "development";`;
3495
+ },
3496
+ generateBundle: {
3497
+ order: "post",
3498
+ async handler() {
3499
+ if (this.environment.name !== "client") return;
3500
+ const assetsManifest = resolvedViteConfig.plugins.find((plugin) => plugin.name === "rsc:minimal")?.api?.manager?.buildAssetsManifest;
3501
+ invariant(assetsManifest, "Vite RSC assets manifest not found");
3502
+ assetsManifest.clientVersion = await getClientVersion(JSON.stringify(assetsManifest));
3503
+ }
3504
+ }
3505
+ },
3459
3506
  {
3460
3507
  name: "react-router/rsc/hmr/inject-runtime",
3461
3508
  enforce: "pre",
@@ -3568,7 +3615,9 @@ format: config.serverModuleFormat }
3568
3615
  }
3569
3616
  const virtual = {
3570
3617
  routeConfig: create("unstable_rsc/routes"),
3618
+ subResourceIntegrity: create("unstable_rsc/subresource-integrity"),
3571
3619
  routeDiscovery: create("unstable_rsc/route-discovery"),
3620
+ clientVersion: create("unstable_rsc/client-version"),
3572
3621
  injectHmrRuntime: create("unstable_rsc/inject-hmr-runtime"),
3573
3622
  basename: create("unstable_rsc/basename"),
3574
3623
  reactRouterServeConfig: create("unstable_rsc/react-router-serve-config")
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@react-router/dev",
3
3
  "type": "module",
4
- "version": "8.2.0",
4
+ "version": "8.3.0",
5
5
  "description": "Dev tools and CLI for React Router",
6
6
  "keywords": [
7
7
  "react",
@@ -40,6 +40,10 @@
40
40
  "./package.json": "./package.json"
41
41
  },
42
42
  "imports": {
43
+ "#development-condition-enabled": {
44
+ "development": "./development-condition-enabled/true.mjs",
45
+ "default": "./development-condition-enabled/false.mjs"
46
+ },
43
47
  "#module-sync-enabled": {
44
48
  "module-sync": "./module-sync-enabled/true.mjs",
45
49
  "default": "./module-sync-enabled/false.cjs"
@@ -66,6 +70,7 @@
66
70
  "../../pnpm-workspace.yaml",
67
71
  "cli/**",
68
72
  "config/**",
73
+ "development-condition-enabled/**",
69
74
  "module-sync-enabled/**",
70
75
  "typegen/**",
71
76
  "vite/**",
@@ -105,7 +110,7 @@
105
110
  "semver": "^7.8.1",
106
111
  "tinyglobby": "^0.2.16",
107
112
  "valibot": "^1.4.1",
108
- "@react-router/node": "8.2.0"
113
+ "@react-router/node": "8.3.0"
109
114
  },
110
115
  "devDependencies": {
111
116
  "@types/babel__core": "^7.20.5",
@@ -127,17 +132,17 @@
127
132
  "vite": "^7.0.0",
128
133
  "wireit": "0.14.12",
129
134
  "wrangler": "^4.95.0",
130
- "@react-router/serve": "8.2.0",
131
- "react-router": "^8.2.0"
135
+ "react-router": "^8.3.0",
136
+ "@react-router/serve": "8.3.0"
132
137
  },
133
138
  "peerDependencies": {
134
139
  "@vitejs/plugin-rsc": "~0.5.26",
135
140
  "react-server-dom-webpack": "^19.2.7",
136
- "typescript": "^5.1.0 || ^6.0.0",
141
+ "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0",
137
142
  "vite": "^7.0.0 || ^8.0.0",
138
143
  "wrangler": "^4.0.0",
139
- "@react-router/serve": "^8.2.0",
140
- "react-router": "^8.2.0"
144
+ "react-router": "^8.3.0",
145
+ "@react-router/serve": "^8.3.0"
141
146
  },
142
147
  "peerDependenciesMeta": {
143
148
  "@vitejs/plugin-rsc": {
@@ -161,6 +166,7 @@
161
166
  },
162
167
  "files": [
163
168
  "dist/",
169
+ "development-condition-enabled/",
164
170
  "module-sync-enabled/",
165
171
  "bin.cjs",
166
172
  "rsc-types.d.ts",
package/rsc-types.d.ts CHANGED
@@ -15,6 +15,11 @@ declare module "virtual:react-router/unstable_rsc/ssr" {
15
15
  export default ssr;
16
16
  }
17
17
 
18
+ declare module "virtual:react-router/unstable_rsc/subresource-integrity" {
19
+ const subResourceIntegrity: Record<string, string> | undefined;
20
+ export default subResourceIntegrity;
21
+ }
22
+
18
23
  declare module "virtual:react-router/unstable_rsc/react-router-serve-config" {
19
24
  const unstable_reactRouterServeConfig: {
20
25
  publicPath: string;
@@ -35,4 +40,9 @@ declare module "virtual:react-router/unstable_rsc/route-discovery" {
35
40
  export default routeDiscovery;
36
41
  }
37
42
 
43
+ declare module "virtual:react-router/unstable_rsc/client-version" {
44
+ const clientVersion: string;
45
+ export default clientVersion;
46
+ }
47
+
38
48
  declare module "virtual:react-router/unstable_rsc/inject-hmr-runtime" {}