@react-router/dev 7.13.1-pre.0 → 7.13.2-pre.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 +53 -4
- package/dist/cli/index.js +26 -8
- package/dist/config.d.ts +1 -0
- package/dist/config.js +1 -1
- package/dist/routes.js +1 -1
- package/dist/vite/cloudflare.js +26 -8
- package/dist/vite.js +49 -16
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,62 @@
|
|
|
1
1
|
# `@react-router/dev`
|
|
2
2
|
|
|
3
|
-
## 7.13.
|
|
3
|
+
## 7.13.2-pre.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fix `react-router dev` crash when Unix socket files exist in the project root ([#14854](https://github.com/remix-run/react-router/pull/14854))
|
|
8
|
+
- Escape redirect locations in prerendered redirect HTML ([#14880](https://github.com/remix-run/react-router/pull/14880))
|
|
9
|
+
- Add `future.unstable_passThroughRequests` flag ([#14775](https://github.com/remix-run/react-router/pull/14775))
|
|
10
|
+
|
|
11
|
+
By default, React Router normalizes the `request.url` passed to your `loader`, `action`, and `middleware` functions by removing React Router's internal implementation details (`.data` suffixes, `index` + `_routes` query params).
|
|
12
|
+
|
|
13
|
+
Enabling this flag removes that normalization and passes the raw HTTP `request` instance to your handlers. This provides a few benefits:
|
|
14
|
+
- Reduces server-side overhead by eliminating multiple `new Request()` calls on the critical path
|
|
15
|
+
- Allows you to distinguish document from data requests in your handlers base don the presence of a `.data` suffix (useful for observability purposes)
|
|
16
|
+
|
|
17
|
+
If you were previously relying on the normalization of `request.url`, you can switch to use the new sibling `unstable_url` parameter which contains a `URL` instance representing the normalized location:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
// ❌ Before: you could assume there was no `.data` suffix in `request.url`
|
|
21
|
+
export async function loader({ request }: Route.LoaderArgs) {
|
|
22
|
+
let url = new URL(request.url);
|
|
23
|
+
if (url.pathname === "/path") {
|
|
24
|
+
// This check will fail with the flag enabled because the `.data` suffix will
|
|
25
|
+
// exist on data requests
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ✅ After: use `unstable_url` for normalized routing logic and `request.url`
|
|
30
|
+
// for raw routing logic
|
|
31
|
+
export async function loader({ request, unstable_url }: Route.LoaderArgs) {
|
|
32
|
+
if (unstable_url.pathname === "/path") {
|
|
33
|
+
// This will always have the `.data` suffix stripped
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// And now you can distinguish between document versus data requests
|
|
37
|
+
let isDataRequest = new URL(request.url).pathname.endsWith(".data");
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- Add a new `unstable_url: URL` parameter to route handler methods (`loader`, `action`, `middleware`, etc.) representing the normalized URL the application is navigating to or fetching, with React Router implementation details removed (`.data`suffix, `index`/`_routes` query params) ([#14775](https://github.com/remix-run/react-router/pull/14775))
|
|
42
|
+
|
|
43
|
+
This is being added alongside the new `future.unstable_passthroughRequests` future flag so that users still have a way to access the normalized URL when that flag is enabled and non-normalized `request`'s are being passed to your handlers. When adopting this flag, you will only need to start leveraging this new parameter if you are relying on the normalization of `request.url` in your application code.
|
|
44
|
+
|
|
45
|
+
If you don't have the flag enabled, then `unstable_url` will match `request.url`.
|
|
46
|
+
|
|
47
|
+
- Updated dependencies:
|
|
48
|
+
- `react-router@7.13.2-pre.0`
|
|
49
|
+
- `@react-router/node@7.13.2-pre.0`
|
|
50
|
+
- `@react-router/serve@7.13.2-pre.0`
|
|
51
|
+
|
|
52
|
+
## 7.13.1
|
|
4
53
|
|
|
5
54
|
### Patch Changes
|
|
6
55
|
|
|
7
56
|
- Updated dependencies:
|
|
8
|
-
- `react-router@7.13.1
|
|
9
|
-
- `@react-router/node@7.13.1
|
|
10
|
-
- `@react-router/serve@7.13.1
|
|
57
|
+
- `react-router@7.13.1`
|
|
58
|
+
- `@react-router/node@7.13.1`
|
|
59
|
+
- `@react-router/serve@7.13.1`
|
|
11
60
|
|
|
12
61
|
## 7.13.0
|
|
13
62
|
|
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @react-router/dev v7.13.
|
|
3
|
+
* @react-router/dev v7.13.2-pre.0
|
|
4
4
|
*
|
|
5
5
|
* Copyright (c) Remix Software Inc.
|
|
6
6
|
*
|
|
@@ -505,6 +505,7 @@ async function resolveConfig({
|
|
|
505
505
|
}
|
|
506
506
|
let future = {
|
|
507
507
|
unstable_optimizeDeps: userAndPresetConfigs.future?.unstable_optimizeDeps ?? false,
|
|
508
|
+
unstable_passThroughRequests: userAndPresetConfigs.future?.unstable_passThroughRequests ?? false,
|
|
508
509
|
unstable_subResourceIntegrity: userAndPresetConfigs.future?.unstable_subResourceIntegrity ?? false,
|
|
509
510
|
unstable_trailingSlashAwareDataRequests: userAndPresetConfigs.future?.unstable_trailingSlashAwareDataRequests ?? false,
|
|
510
511
|
unstable_previewServerPrerendering: userAndPresetConfigs.future?.unstable_previewServerPrerendering ?? false,
|
|
@@ -586,13 +587,11 @@ async function createConfigLoader({
|
|
|
586
587
|
if (!fsWatcher) {
|
|
587
588
|
fsWatcher = import_chokidar.default.watch([root, appDirectory], {
|
|
588
589
|
ignoreInitial: true,
|
|
589
|
-
ignored: (path10) => {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
dirname5 !== root;
|
|
595
|
-
}
|
|
590
|
+
ignored: (path10) => isIgnoredByWatcher(path10, { root, appDirectory })
|
|
591
|
+
});
|
|
592
|
+
fsWatcher.on("error", (error) => {
|
|
593
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
594
|
+
console.warn(import_picocolors.default.yellow(`File watcher error: ${message}`));
|
|
596
595
|
});
|
|
597
596
|
fsWatcher.on("all", async (...args) => {
|
|
598
597
|
let [event, rawFilepath] = args;
|
|
@@ -733,6 +732,25 @@ function isEntryFileDependency(moduleGraph, entryFilepath, filepath, visited = /
|
|
|
733
732
|
}
|
|
734
733
|
return false;
|
|
735
734
|
}
|
|
735
|
+
function isIgnoredByWatcher(path10, { root, appDirectory }) {
|
|
736
|
+
let dirname5 = import_pathe3.default.dirname(path10);
|
|
737
|
+
let ignoredByPath = !dirname5.startsWith(appDirectory) && // Ensure we're only watching files outside of the app directory
|
|
738
|
+
// that are at the root level, not nested in subdirectories
|
|
739
|
+
path10 !== root && // Watch the root directory itself
|
|
740
|
+
dirname5 !== root;
|
|
741
|
+
if (ignoredByPath) {
|
|
742
|
+
return true;
|
|
743
|
+
}
|
|
744
|
+
try {
|
|
745
|
+
let stat = import_node_fs.default.statSync(path10, { throwIfNoEntry: false });
|
|
746
|
+
if (stat && !stat.isFile() && !stat.isDirectory()) {
|
|
747
|
+
return true;
|
|
748
|
+
}
|
|
749
|
+
} catch {
|
|
750
|
+
return true;
|
|
751
|
+
}
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
736
754
|
var import_node_fs, import_node_child_process, import_pathe3, import_chokidar, import_picocolors, import_pick2, import_omit, import_cloneDeep, import_isEqual, excludedConfigPresetKeys, mergeReactRouterConfig, deepFreeze, entryExts;
|
|
737
755
|
var init_config = __esm({
|
|
738
756
|
"config/config.ts"() {
|
package/dist/config.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ type ServerBundlesBuildManifest = BaseBuildManifest & {
|
|
|
38
38
|
type ServerModuleFormat = "esm" | "cjs";
|
|
39
39
|
interface FutureConfig {
|
|
40
40
|
unstable_optimizeDeps: boolean;
|
|
41
|
+
unstable_passThroughRequests: boolean;
|
|
41
42
|
unstable_subResourceIntegrity: boolean;
|
|
42
43
|
unstable_trailingSlashAwareDataRequests: boolean;
|
|
43
44
|
/**
|
package/dist/config.js
CHANGED
package/dist/routes.js
CHANGED
package/dist/vite/cloudflare.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/dev v7.13.
|
|
2
|
+
* @react-router/dev v7.13.2-pre.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -531,6 +531,7 @@ async function resolveConfig({
|
|
|
531
531
|
}
|
|
532
532
|
let future = {
|
|
533
533
|
unstable_optimizeDeps: userAndPresetConfigs.future?.unstable_optimizeDeps ?? false,
|
|
534
|
+
unstable_passThroughRequests: userAndPresetConfigs.future?.unstable_passThroughRequests ?? false,
|
|
534
535
|
unstable_subResourceIntegrity: userAndPresetConfigs.future?.unstable_subResourceIntegrity ?? false,
|
|
535
536
|
unstable_trailingSlashAwareDataRequests: userAndPresetConfigs.future?.unstable_trailingSlashAwareDataRequests ?? false,
|
|
536
537
|
unstable_previewServerPrerendering: userAndPresetConfigs.future?.unstable_previewServerPrerendering ?? false,
|
|
@@ -612,13 +613,11 @@ async function createConfigLoader({
|
|
|
612
613
|
if (!fsWatcher) {
|
|
613
614
|
fsWatcher = import_chokidar.default.watch([root, appDirectory], {
|
|
614
615
|
ignoreInitial: true,
|
|
615
|
-
ignored: (path3) => {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
dirname !== root;
|
|
621
|
-
}
|
|
616
|
+
ignored: (path3) => isIgnoredByWatcher(path3, { root, appDirectory })
|
|
617
|
+
});
|
|
618
|
+
fsWatcher.on("error", (error) => {
|
|
619
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
620
|
+
console.warn(import_picocolors.default.yellow(`File watcher error: ${message}`));
|
|
622
621
|
});
|
|
623
622
|
fsWatcher.on("all", async (...args) => {
|
|
624
623
|
let [event, rawFilepath] = args;
|
|
@@ -760,6 +759,25 @@ function isEntryFileDependency(moduleGraph, entryFilepath, filepath, visited = /
|
|
|
760
759
|
}
|
|
761
760
|
return false;
|
|
762
761
|
}
|
|
762
|
+
function isIgnoredByWatcher(path3, { root, appDirectory }) {
|
|
763
|
+
let dirname = import_pathe3.default.dirname(path3);
|
|
764
|
+
let ignoredByPath = !dirname.startsWith(appDirectory) && // Ensure we're only watching files outside of the app directory
|
|
765
|
+
// that are at the root level, not nested in subdirectories
|
|
766
|
+
path3 !== root && // Watch the root directory itself
|
|
767
|
+
dirname !== root;
|
|
768
|
+
if (ignoredByPath) {
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
try {
|
|
772
|
+
let stat = import_node_fs.default.statSync(path3, { throwIfNoEntry: false });
|
|
773
|
+
if (stat && !stat.isFile() && !stat.isDirectory()) {
|
|
774
|
+
return true;
|
|
775
|
+
}
|
|
776
|
+
} catch {
|
|
777
|
+
return true;
|
|
778
|
+
}
|
|
779
|
+
return false;
|
|
780
|
+
}
|
|
763
781
|
|
|
764
782
|
// vite/cloudflare-dev-proxy.ts
|
|
765
783
|
var serverBuildId = "virtual:react-router/server-build";
|
package/dist/vite.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/dev v7.13.
|
|
2
|
+
* @react-router/dev v7.13.2-pre.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -560,6 +560,7 @@ async function resolveConfig({
|
|
|
560
560
|
}
|
|
561
561
|
let future = {
|
|
562
562
|
unstable_optimizeDeps: userAndPresetConfigs.future?.unstable_optimizeDeps ?? false,
|
|
563
|
+
unstable_passThroughRequests: userAndPresetConfigs.future?.unstable_passThroughRequests ?? false,
|
|
563
564
|
unstable_subResourceIntegrity: userAndPresetConfigs.future?.unstable_subResourceIntegrity ?? false,
|
|
564
565
|
unstable_trailingSlashAwareDataRequests: userAndPresetConfigs.future?.unstable_trailingSlashAwareDataRequests ?? false,
|
|
565
566
|
unstable_previewServerPrerendering: userAndPresetConfigs.future?.unstable_previewServerPrerendering ?? false,
|
|
@@ -641,13 +642,11 @@ async function createConfigLoader({
|
|
|
641
642
|
if (!fsWatcher) {
|
|
642
643
|
fsWatcher = import_chokidar.default.watch([root, appDirectory], {
|
|
643
644
|
ignoreInitial: true,
|
|
644
|
-
ignored: (path10) => {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
dirname4 !== root;
|
|
650
|
-
}
|
|
645
|
+
ignored: (path10) => isIgnoredByWatcher(path10, { root, appDirectory })
|
|
646
|
+
});
|
|
647
|
+
fsWatcher.on("error", (error) => {
|
|
648
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
649
|
+
console.warn(import_picocolors.default.yellow(`File watcher error: ${message}`));
|
|
651
650
|
});
|
|
652
651
|
fsWatcher.on("all", async (...args) => {
|
|
653
652
|
let [event, rawFilepath] = args;
|
|
@@ -856,6 +855,25 @@ function isEntryFileDependency(moduleGraph, entryFilepath, filepath, visited = /
|
|
|
856
855
|
}
|
|
857
856
|
return false;
|
|
858
857
|
}
|
|
858
|
+
function isIgnoredByWatcher(path10, { root, appDirectory }) {
|
|
859
|
+
let dirname4 = import_pathe3.default.dirname(path10);
|
|
860
|
+
let ignoredByPath = !dirname4.startsWith(appDirectory) && // Ensure we're only watching files outside of the app directory
|
|
861
|
+
// that are at the root level, not nested in subdirectories
|
|
862
|
+
path10 !== root && // Watch the root directory itself
|
|
863
|
+
dirname4 !== root;
|
|
864
|
+
if (ignoredByPath) {
|
|
865
|
+
return true;
|
|
866
|
+
}
|
|
867
|
+
try {
|
|
868
|
+
let stat = import_node_fs.default.statSync(path10, { throwIfNoEntry: false });
|
|
869
|
+
if (stat && !stat.isFile() && !stat.isDirectory()) {
|
|
870
|
+
return true;
|
|
871
|
+
}
|
|
872
|
+
} catch {
|
|
873
|
+
return true;
|
|
874
|
+
}
|
|
875
|
+
return false;
|
|
876
|
+
}
|
|
859
877
|
|
|
860
878
|
// typegen/context.ts
|
|
861
879
|
async function createContext2({
|
|
@@ -4523,15 +4541,17 @@ ${new TextDecoder().decode(contents)}`
|
|
|
4523
4541
|
if (redirectStatusCodes.has(response.status)) {
|
|
4524
4542
|
let location = response.headers.get("Location");
|
|
4525
4543
|
let delay = response.status === 302 ? 2 : 0;
|
|
4544
|
+
let escapedLocation = escapeHtml(location ?? "");
|
|
4545
|
+
let escapedPathname = escapeHtml(pathname);
|
|
4526
4546
|
html = `<!doctype html>
|
|
4527
4547
|
<head>
|
|
4528
|
-
<title>Redirecting to: ${
|
|
4529
|
-
<meta http-equiv="refresh" content="${delay};url=${
|
|
4548
|
+
<title>Redirecting to: ${escapedLocation}</title>
|
|
4549
|
+
<meta http-equiv="refresh" content="${delay};url=${escapedLocation}">
|
|
4530
4550
|
<meta name="robots" content="noindex">
|
|
4531
4551
|
</head>
|
|
4532
4552
|
<body>
|
|
4533
|
-
<a href="${
|
|
4534
|
-
Redirecting from <code>${
|
|
4553
|
+
<a href="${escapedLocation}">
|
|
4554
|
+
Redirecting from <code>${escapedPathname}</code> to <code>${escapedLocation}</code>
|
|
4535
4555
|
</a>
|
|
4536
4556
|
</body>
|
|
4537
4557
|
</html>`;
|
|
@@ -4940,15 +4960,17 @@ async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reac
|
|
|
4940
4960
|
if (redirectStatusCodes.has(response.status)) {
|
|
4941
4961
|
let location = response.headers.get("Location");
|
|
4942
4962
|
let delay = response.status === 302 ? 2 : 0;
|
|
4963
|
+
let escapedLocation = escapeHtml(location ?? "");
|
|
4964
|
+
let escapedNormalizedPath = escapeHtml(normalizedPath);
|
|
4943
4965
|
html = `<!doctype html>
|
|
4944
4966
|
<head>
|
|
4945
|
-
<title>Redirecting to: ${
|
|
4946
|
-
<meta http-equiv="refresh" content="${delay};url=${
|
|
4967
|
+
<title>Redirecting to: ${escapedLocation}</title>
|
|
4968
|
+
<meta http-equiv="refresh" content="${delay};url=${escapedLocation}">
|
|
4947
4969
|
<meta name="robots" content="noindex">
|
|
4948
4970
|
</head>
|
|
4949
4971
|
<body>
|
|
4950
|
-
<a href="${
|
|
4951
|
-
Redirecting from <code>${
|
|
4972
|
+
<a href="${escapedLocation}">
|
|
4973
|
+
Redirecting from <code>${escapedNormalizedPath}</code> to <code>${escapedLocation}</code>
|
|
4952
4974
|
</a>
|
|
4953
4975
|
</body>
|
|
4954
4976
|
</html>`;
|
|
@@ -5590,6 +5612,17 @@ function createSpaModeRequest(reactRouterConfig) {
|
|
|
5590
5612
|
metadata: { type: "spa", path: "/" }
|
|
5591
5613
|
};
|
|
5592
5614
|
}
|
|
5615
|
+
var ESCAPE_REGEX = /[&><\u2028\u2029]/g;
|
|
5616
|
+
var ESCAPE_LOOKUP = {
|
|
5617
|
+
"&": "\\u0026",
|
|
5618
|
+
">": "\\u003e",
|
|
5619
|
+
"<": "\\u003c",
|
|
5620
|
+
"\u2028": "\\u2028",
|
|
5621
|
+
"\u2029": "\\u2029"
|
|
5622
|
+
};
|
|
5623
|
+
function escapeHtml(html) {
|
|
5624
|
+
return html.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
|
|
5625
|
+
}
|
|
5593
5626
|
|
|
5594
5627
|
// vite/rsc/plugin.ts
|
|
5595
5628
|
var import_es_module_lexer3 = require("es-module-lexer");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-router/dev",
|
|
3
|
-
"version": "7.13.
|
|
3
|
+
"version": "7.13.2-pre.0",
|
|
4
4
|
"description": "Dev tools and CLI for React Router",
|
|
5
5
|
"homepage": "https://reactrouter.com",
|
|
6
6
|
"bugs": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"tinyglobby": "^0.2.14",
|
|
93
93
|
"valibot": "^1.2.0",
|
|
94
94
|
"vite-node": "^3.2.2",
|
|
95
|
-
"@react-router/node": "7.13.
|
|
95
|
+
"@react-router/node": "7.13.2-pre.0"
|
|
96
96
|
},
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@types/babel__core": "^7.20.5",
|
|
@@ -116,8 +116,8 @@
|
|
|
116
116
|
"vite": "^6.3.0",
|
|
117
117
|
"wireit": "0.14.9",
|
|
118
118
|
"wrangler": "^4.23.0",
|
|
119
|
-
"@react-router/serve": "7.13.
|
|
120
|
-
"react-router": "^7.13.
|
|
119
|
+
"@react-router/serve": "7.13.2-pre.0",
|
|
120
|
+
"react-router": "^7.13.2-pre.0"
|
|
121
121
|
},
|
|
122
122
|
"peerDependencies": {
|
|
123
123
|
"@vitejs/plugin-rsc": "~0.5.7",
|
|
@@ -125,8 +125,8 @@
|
|
|
125
125
|
"typescript": "^5.1.0",
|
|
126
126
|
"vite": "^5.1.0 || ^6.0.0 || ^7.0.0",
|
|
127
127
|
"wrangler": "^3.28.2 || ^4.0.0",
|
|
128
|
-
"@react-router/serve": "^7.13.
|
|
129
|
-
"react-router": "^7.13.
|
|
128
|
+
"@react-router/serve": "^7.13.2-pre.0",
|
|
129
|
+
"react-router": "^7.13.2-pre.0"
|
|
130
130
|
},
|
|
131
131
|
"peerDependenciesMeta": {
|
|
132
132
|
"@vitejs/plugin-rsc": {
|