@react-router/dev 8.2.0 → 8.3.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 +54 -1
- package/development-condition-enabled/false.d.mts +2 -0
- package/development-condition-enabled/false.mjs +2 -0
- package/development-condition-enabled/true.d.mts +2 -0
- package/development-condition-enabled/true.mjs +2 -0
- package/dist/{build-r3D94V53.js → build-Ou3B3epu.js} +2 -2
- package/dist/cli/index.js +60 -45
- package/dist/config/default-rsc-entries/entry.rsc.tsx +3 -0
- package/dist/config/default-rsc-entries/entry.ssr.tsx +4 -0
- package/dist/config/defaults/entry.client.jsx +12 -0
- package/dist/config/defaults/entry.server.node.jsx +82 -0
- package/dist/config/defaults/entry.server.web.jsx +53 -0
- package/dist/config.js +1 -1
- package/dist/{dev-BfZiothP.js → dev-DFccbHpq.js} +2 -2
- package/dist/{routes-CdiIrVIn.js → routes-C-NBxWG3.js} +1 -1
- package/dist/routes.js +2 -2
- package/dist/{typegen-CNpfI4aI.js → typegen-DxFMuBQP.js} +2 -2
- package/dist/vite.js +55 -6
- package/package.json +17 -11
- package/rsc-types.d.ts +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# `@react-router/dev`
|
|
2
2
|
|
|
3
|
+
## v8.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Bump `@remix-run/node-fetch-server` dependency ([#15447](https://github.com/remix-run/react-router/pull/15447))
|
|
8
|
+
- Generate JavaScript entry files at package build time so `react-router reveal --no-typescript` does not require Prettier at runtime ([#15373](https://github.com/remix-run/react-router/pull/15373))
|
|
9
|
+
- Deprecate the `--no-typescript` flag ahead of its removal in React Router v9
|
|
10
|
+
- Updated dependencies:
|
|
11
|
+
- [`react-router@8.3.1`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.1)
|
|
12
|
+
- [`@react-router/node@8.3.1`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.1)
|
|
13
|
+
- [`@react-router/serve@8.3.1`](https://github.com/remix-run/react-router/releases/tag/@react-router/serve@8.3.1)
|
|
14
|
+
|
|
15
|
+
## v8.3.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- Restart `react-router dev` with `--conditions=development` when not already configured ([#15291](https://github.com/remix-run/react-router/pull/15291))
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317))
|
|
24
|
+
|
|
25
|
+
### Unstable Changes
|
|
26
|
+
|
|
27
|
+
⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
|
|
28
|
+
|
|
29
|
+
- Add `unstable_rsc/client-version` client build version virtual module ([#15318](https://github.com/remix-run/react-router/pull/15318))
|
|
30
|
+
|
|
31
|
+
- Support the `subResourceIntegrity` config option in RSC Framework Mode ([#15321](https://github.com/remix-run/react-router/pull/15321))
|
|
32
|
+
|
|
33
|
+
#### Migration guide
|
|
34
|
+
|
|
35
|
+
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:
|
|
36
|
+
|
|
37
|
+
```diff
|
|
38
|
+
+import subResourceIntegrity from "virtual:react-router/unstable_rsc/subresource-integrity";
|
|
39
|
+
|
|
40
|
+
return renderToReadableStream(<RSCStaticRouter getPayload={getPayload} />, {
|
|
41
|
+
...options,
|
|
42
|
+
bootstrapScriptContent,
|
|
43
|
+
formState,
|
|
44
|
+
+ importMap: subResourceIntegrity
|
|
45
|
+
+ ? { integrity: subResourceIntegrity }
|
|
46
|
+
+ : undefined,
|
|
47
|
+
signal: request.signal,
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- Updated dependencies:
|
|
52
|
+
- [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0)
|
|
53
|
+
- [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0)
|
|
54
|
+
- [`@react-router/serve@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/serve@8.3.0)
|
|
55
|
+
|
|
3
56
|
## v8.2.0
|
|
4
57
|
|
|
5
58
|
### Minor Changes
|
|
@@ -16,7 +69,7 @@
|
|
|
16
69
|
|
|
17
70
|
### Unstable Changes
|
|
18
71
|
|
|
19
|
-
⚠️
|
|
72
|
+
⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_
|
|
20
73
|
|
|
21
74
|
- 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
75
|
- This flag has no effect if you have your own `entry.server.tsx`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/dev v8.
|
|
2
|
+
* @react-router/dev v8.3.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-
|
|
11
|
+
import { _ as getVite, v as preloadVite } from "./typegen-DxFMuBQP.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.
|
|
3
|
+
* @react-router/dev v8.3.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-
|
|
12
|
+
import { _ as getVite, l as hasNodeDependency, n as watch, t as run$1, u as loadConfig, v as preloadVite } from "../typegen-DxFMuBQP.js";
|
|
13
13
|
import { createRequire } from "node:module";
|
|
14
14
|
import { parseArgs } from "node:util";
|
|
15
15
|
import semver from "semver";
|
|
@@ -21,10 +21,9 @@ 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
|
|
25
|
-
import
|
|
26
|
-
import
|
|
27
|
-
import prettier from "prettier";
|
|
24
|
+
import developmentConditionEnabled from "#development-condition-enabled";
|
|
25
|
+
import { spawn } from "node:child_process";
|
|
26
|
+
import process$1 from "node:process";
|
|
28
27
|
import packageJson from "@react-router/dev/package.json" with { type: "json" };
|
|
29
28
|
//#region config/format.ts
|
|
30
29
|
function formatRoutes(routeManifest, format) {
|
|
@@ -69,24 +68,6 @@ function formatRoutesAsJsx(routeManifest) {
|
|
|
69
68
|
return output;
|
|
70
69
|
}
|
|
71
70
|
//#endregion
|
|
72
|
-
//#region cli/useJavascript.ts
|
|
73
|
-
async function transpile(tsx, options = {}) {
|
|
74
|
-
let mjs = babel.transformSync(tsx, {
|
|
75
|
-
compact: false,
|
|
76
|
-
cwd: options.cwd,
|
|
77
|
-
filename: options.filename,
|
|
78
|
-
plugins: [babelPluginSyntaxJSX],
|
|
79
|
-
presets: [[babelPresetTypeScript, { jsx: "preserve" }]],
|
|
80
|
-
retainLines: true
|
|
81
|
-
});
|
|
82
|
-
if (!mjs || !mjs.code) throw new Error("Could not parse TypeScript");
|
|
83
|
-
/**
|
|
84
|
-
* Babel's `compact` and `retainLines` options are both bad at formatting code.
|
|
85
|
-
* Use Prettier for nicer formatting.
|
|
86
|
-
*/
|
|
87
|
-
return await prettier.format(mjs.code, { parser: "babel" });
|
|
88
|
-
}
|
|
89
|
-
//#endregion
|
|
90
71
|
//#region vite/profiler.ts
|
|
91
72
|
const getSession = () => global.__reactRouter_profile_session;
|
|
92
73
|
const start = async (callback) => {
|
|
@@ -124,6 +105,42 @@ async function hasReactRouterRscPlugin({ root, viteBuildOptions: { config, logLe
|
|
|
124
105
|
}, "build", "production", "production")).plugins.some((plugin) => plugin?.name === "react-router/rsc");
|
|
125
106
|
}
|
|
126
107
|
//#endregion
|
|
108
|
+
//#region restart-with-conditions.ts
|
|
109
|
+
/**
|
|
110
|
+
* Restarts the current Node process, appending new flags to the
|
|
111
|
+
* existing NODE_OPTIONS. SIGINT/SIGTERM are always forwarded to the child.
|
|
112
|
+
*/
|
|
113
|
+
function restartWithMergedOptions(nodeOptions) {
|
|
114
|
+
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.");
|
|
115
|
+
const mergedOptions = [process$1.env.NODE_OPTIONS, nodeOptions].filter(Boolean).join(" ").trim();
|
|
116
|
+
console.log(`[restart] Relaunching with NODE_OPTIONS: ${mergedOptions}`);
|
|
117
|
+
const [cmd, ...args] = process$1.argv;
|
|
118
|
+
const child = spawn(cmd, args, {
|
|
119
|
+
env: {
|
|
120
|
+
...process$1.env,
|
|
121
|
+
NODE_OPTIONS: mergedOptions,
|
|
122
|
+
REACT_ROUTER_DEV_RESTARTED: "true"
|
|
123
|
+
},
|
|
124
|
+
stdio: "inherit"
|
|
125
|
+
});
|
|
126
|
+
let signalHandlers = ["SIGINT", "SIGTERM"].map((sig) => {
|
|
127
|
+
let handler = () => {
|
|
128
|
+
child.kill(sig);
|
|
129
|
+
};
|
|
130
|
+
process$1.on(sig, handler);
|
|
131
|
+
return [sig, handler];
|
|
132
|
+
});
|
|
133
|
+
child.on("exit", (code, signal) => {
|
|
134
|
+
for (let [sig, handler] of signalHandlers) process$1.off(sig, handler);
|
|
135
|
+
if (signal) process$1.kill(process$1.pid, signal);
|
|
136
|
+
else process$1.exit(code ?? 0);
|
|
137
|
+
});
|
|
138
|
+
child.on("error", (err) => {
|
|
139
|
+
console.error("[restart] Failed to spawn child process:", err);
|
|
140
|
+
process$1.exit(1);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
127
144
|
//#region cli/commands.ts
|
|
128
145
|
const nodeRequire = createRequire(import.meta.url);
|
|
129
146
|
async function routes(rootDirectory, flags = {}) {
|
|
@@ -141,7 +158,7 @@ async function routes(rootDirectory, flags = {}) {
|
|
|
141
158
|
}
|
|
142
159
|
async function build(root, options = {}) {
|
|
143
160
|
root = resolveRootDirectory(root, options);
|
|
144
|
-
let { build } = await import("../build-
|
|
161
|
+
let { build } = await import("../build-Ou3B3epu.js");
|
|
145
162
|
if (options.profile) await start();
|
|
146
163
|
try {
|
|
147
164
|
await build(root, options);
|
|
@@ -150,11 +167,13 @@ async function build(root, options = {}) {
|
|
|
150
167
|
}
|
|
151
168
|
}
|
|
152
169
|
async function dev(root, options = {}) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
170
|
+
if (developmentConditionEnabled) {
|
|
171
|
+
let { dev } = await import("../dev-DFccbHpq.js");
|
|
172
|
+
if (options.profile) await start();
|
|
173
|
+
exitHook(() => stop(console.info));
|
|
174
|
+
root = resolveRootDirectory(root, options);
|
|
175
|
+
await dev(root, options);
|
|
176
|
+
} else restartWithMergedOptions("--conditions=development");
|
|
158
177
|
await new Promise(() => {});
|
|
159
178
|
}
|
|
160
179
|
let clientEntries = [
|
|
@@ -232,20 +251,13 @@ async function generateEntry(entry, rootDirectory, flags = {}) {
|
|
|
232
251
|
await copyFile(defaultEntry, outputFile);
|
|
233
252
|
} else {
|
|
234
253
|
let pkgJson = await readPackageJSON(rootDirectory);
|
|
235
|
-
let
|
|
236
|
-
let
|
|
237
|
-
let
|
|
238
|
-
let contents =
|
|
239
|
-
let
|
|
240
|
-
let outputEntry = `${entry}.${useTypeScript ? "tsx" : "jsx"}`;
|
|
254
|
+
let outputExtension = flags.typescript ?? true ? "tsx" : "jsx";
|
|
255
|
+
let defaultEntryClient = path$1.resolve(defaultsDirectory, `entry.client.${outputExtension}`);
|
|
256
|
+
let defaultEntryServer = path$1.resolve(defaultsDirectory, hasNodeDependency(pkgJson.dependencies) && !configResult.value.future.unstable_enableNodeReadableStream ? `entry.server.node.${outputExtension}` : `entry.server.web.${outputExtension}`);
|
|
257
|
+
let contents = entry === "entry.server" ? await createServerEntry(rootDirectory, appDirectory, defaultEntryServer) : await createClientEntry(rootDirectory, appDirectory, defaultEntryClient);
|
|
258
|
+
let outputEntry = `${entry}.${outputExtension}`;
|
|
241
259
|
outputFile = path$1.resolve(appDirectory, outputEntry);
|
|
242
|
-
|
|
243
|
-
let javascript = await transpile(contents, {
|
|
244
|
-
cwd: rootDirectory,
|
|
245
|
-
filename: isServerEntry ? defaultEntryServer : defaultEntryClient
|
|
246
|
-
});
|
|
247
|
-
await writeFile(outputFile, javascript, "utf-8");
|
|
248
|
-
} else await writeFile(outputFile, contents, "utf-8");
|
|
260
|
+
await writeFile(outputFile, contents, "utf-8");
|
|
249
261
|
}
|
|
250
262
|
console.log(colors.blue(`Entry file ${entry} created at ${path$1.relative(rootDirectory, outputFile)}.`));
|
|
251
263
|
}
|
|
@@ -338,7 +350,7 @@ ${colors.blueBright("react-router")}
|
|
|
338
350
|
--json Print the routes as JSON
|
|
339
351
|
\`reveal\` Options:
|
|
340
352
|
--config, -c Use specified Vite config file (string)
|
|
341
|
-
--no-typescript Generate plain JavaScript files
|
|
353
|
+
--no-typescript Generate plain JavaScript files (deprecated; will be removed in v9)
|
|
342
354
|
\`typegen\` Options:
|
|
343
355
|
--watch Automatically regenerate types whenever route config (\`routes.ts\`) or route modules change
|
|
344
356
|
|
|
@@ -475,7 +487,10 @@ async function run(argv = process.argv.slice(2), { isMain = false } = {}) {
|
|
|
475
487
|
return;
|
|
476
488
|
}
|
|
477
489
|
flags.interactive = flags.interactive ?? isMain;
|
|
478
|
-
if (values["no-typescript"])
|
|
490
|
+
if (values["no-typescript"]) {
|
|
491
|
+
console.warn(colors.yellow("The --no-typescript flag is deprecated and will be removed in React Router v9."));
|
|
492
|
+
flags.typescript = false;
|
|
493
|
+
}
|
|
479
494
|
switch (input[0]) {
|
|
480
495
|
case "routes":
|
|
481
496
|
await routes(input[1], flags);
|
|
@@ -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
|
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { startTransition, StrictMode } from "react";
|
|
2
|
+
import { hydrateRoot } from "react-dom/client";
|
|
3
|
+
import { HydratedRouter } from "react-router/dom";
|
|
4
|
+
|
|
5
|
+
startTransition(() => {
|
|
6
|
+
hydrateRoot(
|
|
7
|
+
document,
|
|
8
|
+
<StrictMode>
|
|
9
|
+
<HydratedRouter />
|
|
10
|
+
</StrictMode>,
|
|
11
|
+
);
|
|
12
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { PassThrough } from "node:stream";
|
|
2
|
+
|
|
3
|
+
import { createReadableStreamFromReadable } from "@react-router/node";
|
|
4
|
+
import { ServerRouter } from "react-router";
|
|
5
|
+
import { isbot } from "isbot";
|
|
6
|
+
|
|
7
|
+
import { renderToPipeableStream } from "react-dom/server";
|
|
8
|
+
|
|
9
|
+
export const streamTimeout = 5_000;
|
|
10
|
+
|
|
11
|
+
export default function handleRequest(
|
|
12
|
+
request,
|
|
13
|
+
responseStatusCode,
|
|
14
|
+
responseHeaders,
|
|
15
|
+
routerContext,
|
|
16
|
+
loadContext,
|
|
17
|
+
) {
|
|
18
|
+
// https://httpwg.org/specs/rfc9110.html#HEAD
|
|
19
|
+
if (request.method.toUpperCase() === "HEAD") {
|
|
20
|
+
return new Response(null, {
|
|
21
|
+
status: responseStatusCode,
|
|
22
|
+
headers: responseHeaders,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
let shellRendered = false;
|
|
28
|
+
let userAgent = request.headers.get("user-agent");
|
|
29
|
+
|
|
30
|
+
// Ensure requests from bots and SPA Mode renders wait for all content to load before responding
|
|
31
|
+
// https://react.dev/reference/react-dom/server/renderToPipeableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation
|
|
32
|
+
let readyOption =
|
|
33
|
+
(userAgent && isbot(userAgent)) || routerContext.isSpaMode
|
|
34
|
+
? "onAllReady"
|
|
35
|
+
: "onShellReady";
|
|
36
|
+
|
|
37
|
+
// Abort the rendering stream after the `streamTimeout` so it has time to
|
|
38
|
+
// flush down the rejected boundaries
|
|
39
|
+
let timeoutId = setTimeout(() => abort(), streamTimeout + 1000);
|
|
40
|
+
|
|
41
|
+
const { pipe, abort } = renderToPipeableStream(
|
|
42
|
+
<ServerRouter context={routerContext} url={request.url} />,
|
|
43
|
+
{
|
|
44
|
+
[readyOption]() {
|
|
45
|
+
shellRendered = true;
|
|
46
|
+
const body = new PassThrough({
|
|
47
|
+
final(callback) {
|
|
48
|
+
// Clear the timeout to prevent retaining the closure and memory leak
|
|
49
|
+
clearTimeout(timeoutId);
|
|
50
|
+
timeoutId = undefined;
|
|
51
|
+
callback();
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
const stream = createReadableStreamFromReadable(body);
|
|
55
|
+
|
|
56
|
+
responseHeaders.set("Content-Type", "text/html");
|
|
57
|
+
|
|
58
|
+
pipe(body);
|
|
59
|
+
|
|
60
|
+
resolve(
|
|
61
|
+
new Response(stream, {
|
|
62
|
+
headers: responseHeaders,
|
|
63
|
+
status: responseStatusCode,
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
},
|
|
67
|
+
onShellError(error) {
|
|
68
|
+
reject(error);
|
|
69
|
+
},
|
|
70
|
+
onError(error) {
|
|
71
|
+
responseStatusCode = 500;
|
|
72
|
+
// Log streaming rendering errors from inside the shell. Don't log
|
|
73
|
+
// errors encountered during initial shell rendering since they'll
|
|
74
|
+
// reject and get logged in handleDocumentRequest.
|
|
75
|
+
if (shellRendered) {
|
|
76
|
+
console.error(error);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ServerRouter } from "react-router";
|
|
2
|
+
import { isbot } from "isbot";
|
|
3
|
+
import { renderToReadableStream } from "react-dom/server";
|
|
4
|
+
|
|
5
|
+
export const streamTimeout = 5_000;
|
|
6
|
+
|
|
7
|
+
export default async function handleRequest(
|
|
8
|
+
request,
|
|
9
|
+
responseStatusCode,
|
|
10
|
+
responseHeaders,
|
|
11
|
+
routerContext,
|
|
12
|
+
_loadContext,
|
|
13
|
+
) {
|
|
14
|
+
// https://httpwg.org/specs/rfc9110.html#HEAD
|
|
15
|
+
if (request.method.toUpperCase() === "HEAD") {
|
|
16
|
+
return new Response(null, {
|
|
17
|
+
status: responseStatusCode,
|
|
18
|
+
headers: responseHeaders,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let shellRendered = false;
|
|
23
|
+
let userAgent = request.headers.get("user-agent");
|
|
24
|
+
|
|
25
|
+
const body = await renderToReadableStream(
|
|
26
|
+
<ServerRouter context={routerContext} url={request.url} />,
|
|
27
|
+
{
|
|
28
|
+
signal: AbortSignal.timeout(streamTimeout + 1000),
|
|
29
|
+
onError(error) {
|
|
30
|
+
responseStatusCode = 500;
|
|
31
|
+
// Log streaming rendering errors from inside the shell. Don't log
|
|
32
|
+
// errors encountered during initial shell rendering since they'll
|
|
33
|
+
// reject and get logged in handleDocumentRequest.
|
|
34
|
+
if (shellRendered) {
|
|
35
|
+
console.error(error);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
shellRendered = true;
|
|
41
|
+
|
|
42
|
+
// Ensure requests from bots and SPA Mode renders wait for all content to load before responding
|
|
43
|
+
// https://react.dev/reference/react-dom/server/renderToPipeableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation
|
|
44
|
+
if ((userAgent && isbot(userAgent)) || routerContext.isSpaMode) {
|
|
45
|
+
await body.allReady;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
responseHeaders.set("Content-Type", "text/html");
|
|
49
|
+
return new Response(body, {
|
|
50
|
+
headers: responseHeaders,
|
|
51
|
+
status: responseStatusCode,
|
|
52
|
+
});
|
|
53
|
+
}
|
package/dist/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/dev v8.
|
|
2
|
+
* @react-router/dev v8.3.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-
|
|
11
|
+
import { _ as getVite, v as preloadVite } from "./typegen-DxFMuBQP.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
|
package/dist/routes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/dev v8.
|
|
2
|
+
* @react-router/dev v8.3.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-
|
|
11
|
+
import { a as prefix, i as layout, n as getAppDirectory, o as relative, r as index, s as route } from "./routes-C-NBxWG3.js";
|
|
12
12
|
export { getAppDirectory, index, layout, prefix, relative, route };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/dev v8.
|
|
2
|
+
* @react-router/dev v8.3.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-
|
|
11
|
+
import { c as setAppDirectory, l as validateRouteConfig, t as configRoutesToRouteManifest, u as invariant } from "./routes-C-NBxWG3.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
|
+
* @react-router/dev v8.3.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-
|
|
12
|
-
import { u as invariant } from "./routes-
|
|
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-DxFMuBQP.js";
|
|
12
|
+
import { u as invariant } from "./routes-C-NBxWG3.js";
|
|
13
13
|
import { createRequire } from "node:module";
|
|
14
14
|
import colors from "picocolors";
|
|
15
15
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
@@ -21,9 +21,9 @@ import { createRequestHandler, matchRoutes, unstable_setDevServerHooks } from "r
|
|
|
21
21
|
import * as Path from "pathe";
|
|
22
22
|
import path$1, { join } from "pathe";
|
|
23
23
|
import pick from "lodash/pick.js";
|
|
24
|
-
import * as babel from "@babel/core";
|
|
25
24
|
import { createHash } from "node:crypto";
|
|
26
25
|
import * as url from "node:url";
|
|
26
|
+
import * as babel from "@babel/core";
|
|
27
27
|
import { createRequest, sendResponse } from "@remix-run/node-fetch-server";
|
|
28
28
|
import { init, parse } from "es-module-lexer";
|
|
29
29
|
import jsesc from "jsesc";
|
|
@@ -2724,7 +2724,7 @@ const nodeRequire = createRequire(import.meta.url);
|
|
|
2724
2724
|
function hasDependency({ name, rootDirectory }) {
|
|
2725
2725
|
try {
|
|
2726
2726
|
return Boolean(nodeRequire.resolve(name, { paths: [rootDirectory] }));
|
|
2727
|
-
} catch
|
|
2727
|
+
} catch {
|
|
2728
2728
|
return false;
|
|
2729
2729
|
}
|
|
2730
2730
|
}
|
|
@@ -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.
|
|
4
|
+
"version": "8.3.1",
|
|
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/**",
|
|
@@ -83,11 +88,9 @@
|
|
|
83
88
|
"@babel/core": "^7.29.7",
|
|
84
89
|
"@babel/generator": "^7.29.7",
|
|
85
90
|
"@babel/parser": "^7.29.7",
|
|
86
|
-
"@babel/plugin-syntax-jsx": "^7.29.7",
|
|
87
|
-
"@babel/preset-typescript": "^7.29.7",
|
|
88
91
|
"@babel/traverse": "^7.29.7",
|
|
89
92
|
"@babel/types": "^7.29.7",
|
|
90
|
-
"@remix-run/node-fetch-server": "^0.
|
|
93
|
+
"@remix-run/node-fetch-server": "^0.14.1",
|
|
91
94
|
"babel-dead-code-elimination": "^1.0.12",
|
|
92
95
|
"chokidar": "^5.0.0",
|
|
93
96
|
"dedent": "^1.7.2",
|
|
@@ -100,14 +103,15 @@
|
|
|
100
103
|
"pathe": "^2.0.3",
|
|
101
104
|
"picocolors": "^1.1.1",
|
|
102
105
|
"pkg-types": "^2.3.1",
|
|
103
|
-
"prettier": "^3.8.3",
|
|
104
106
|
"react-refresh": "^0.18.0",
|
|
105
107
|
"semver": "^7.8.1",
|
|
106
108
|
"tinyglobby": "^0.2.16",
|
|
107
109
|
"valibot": "^1.4.1",
|
|
108
|
-
"@react-router/node": "8.
|
|
110
|
+
"@react-router/node": "8.3.1"
|
|
109
111
|
},
|
|
110
112
|
"devDependencies": {
|
|
113
|
+
"@babel/plugin-syntax-jsx": "^7.29.7",
|
|
114
|
+
"@babel/preset-typescript": "^7.29.7",
|
|
111
115
|
"@types/babel__core": "^7.20.5",
|
|
112
116
|
"@types/babel__generator": "^7.27.0",
|
|
113
117
|
"@types/babel__traverse": "^7.28.0",
|
|
@@ -122,22 +126,23 @@
|
|
|
122
126
|
"esbuild-register": "^3.6.0",
|
|
123
127
|
"execa": "9.6.1",
|
|
124
128
|
"fast-glob": "3.3.3",
|
|
129
|
+
"prettier": "^3.8.3",
|
|
125
130
|
"tsdown": "^0.22.0",
|
|
126
131
|
"typescript": "^6.0.3",
|
|
127
132
|
"vite": "^7.0.0",
|
|
128
133
|
"wireit": "0.14.12",
|
|
129
134
|
"wrangler": "^4.95.0",
|
|
130
|
-
"@react-router/serve": "8.
|
|
131
|
-
"react-router": "^8.
|
|
135
|
+
"@react-router/serve": "8.3.1",
|
|
136
|
+
"react-router": "^8.3.1"
|
|
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.
|
|
140
|
-
"react-router": "^8.
|
|
144
|
+
"@react-router/serve": "^8.3.1",
|
|
145
|
+
"react-router": "^8.3.1"
|
|
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" {}
|