@react-router/dev 0.0.0-experimental-7a19e47ea → 0.0.0-experimental-8fdb14ec6
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 +30 -0
- package/bin.js +16 -1
- package/dist/build-7YIQVVYE.js +239 -0
- package/dist/chunk-6CEKSKVN.js +31 -0
- package/dist/chunk-6ZGYCLOA.js +57 -0
- package/dist/chunk-76RVI3VW.js +219 -0
- package/dist/chunk-ACXLX4EI.js +81 -0
- package/dist/chunk-NPNB22L5.js +49 -0
- package/dist/chunk-TLJPROZH.js +2626 -0
- package/dist/cli/index.js +84 -1385
- package/dist/config.js +1 -19
- package/dist/dev-BTYKYMMV.js +74 -0
- package/dist/routes.js +12 -179
- package/dist/vite/cloudflare.js +28 -125
- package/dist/vite.js +10 -2683
- package/package.json +17 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# `@react-router/dev`
|
|
2
2
|
|
|
3
|
+
## 7.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fix for a crash when optional args are passed to the CLI ([`5b1ca202f`](https://github.com/remix-run/react-router/commit/5b1ca202f77ef342db0109c6b791d33188077cd0))
|
|
8
|
+
- Updated dependencies:
|
|
9
|
+
- `react-router@7.1.1`
|
|
10
|
+
- `@react-router/node@7.1.1`
|
|
11
|
+
- `@react-router/serve@7.1.1`
|
|
12
|
+
|
|
13
|
+
## 7.1.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- Add support for Vite v6 ([#12469](https://github.com/remix-run/react-router/pull/12469))
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Properly initialize `NODE_ENV` if not already set for compatibility with React 19 ([#12578](https://github.com/remix-run/react-router/pull/12578))
|
|
22
|
+
|
|
23
|
+
- Remove the leftover/unused `abortDelay` prop from `ServerRouter` and update the default `entry.server.tsx` to use the new `streamTimeout` value for Single Fetch ([#12478](https://github.com/remix-run/react-router/pull/12478))
|
|
24
|
+
|
|
25
|
+
- The `abortDelay` functionality was removed in v7 as it was coupled to the `defer` implementation from Remix v2, but this removal of this prop was missed
|
|
26
|
+
- If you were still using this prop in your `entry.server` file, it's likely your app is not aborting streams as you would expect and you will need to adopt the new [`streamTimeout`](https://reactrouter.com/explanation/special-files#streamtimeout) value introduced with Single Fetch
|
|
27
|
+
|
|
28
|
+
- Updated dependencies:
|
|
29
|
+
- `react-router@7.1.0`
|
|
30
|
+
- `@react-router/node@7.1.0`
|
|
31
|
+
- `@react-router/serve@7.1.0`
|
|
32
|
+
|
|
3
33
|
## 7.0.2
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
package/bin.js
CHANGED
|
@@ -1,2 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
import arg from "arg";
|
|
3
|
+
|
|
4
|
+
// Minimal replication of our actual parsing in `run.ts`. If not already set,
|
|
5
|
+
// default `NODE_ENV` so React loads the proper version in it's CJS entry script.
|
|
6
|
+
// We have to do this before importing `run.ts` since that is what imports
|
|
7
|
+
// `react` (indirectly via `react-router`)
|
|
8
|
+
let args = arg({}, { argv: process.argv.slice(2), stopAtPositional: true });
|
|
9
|
+
if (args._[0] === "dev") {
|
|
10
|
+
process.env.NODE_ENV = process.env.NODE_ENV ?? "development";
|
|
11
|
+
} else {
|
|
12
|
+
process.env.NODE_ENV = process.env.NODE_ENV ?? "production";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
(async () => {
|
|
16
|
+
await import("./dist/cli/index.js");
|
|
17
|
+
})();
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @react-router/dev v0.0.0-experimental-8fdb14ec6
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
import {
|
|
12
|
+
configRouteToBranchRoute,
|
|
13
|
+
extractPluginContext,
|
|
14
|
+
getServerBuildDirectory,
|
|
15
|
+
resolveViteConfig
|
|
16
|
+
} from "./chunk-TLJPROZH.js";
|
|
17
|
+
import "./chunk-76RVI3VW.js";
|
|
18
|
+
import "./chunk-ACXLX4EI.js";
|
|
19
|
+
import {
|
|
20
|
+
getVite,
|
|
21
|
+
preloadVite
|
|
22
|
+
} from "./chunk-6ZGYCLOA.js";
|
|
23
|
+
import {
|
|
24
|
+
invariant
|
|
25
|
+
} from "./chunk-6CEKSKVN.js";
|
|
26
|
+
|
|
27
|
+
// vite/build.ts
|
|
28
|
+
import path from "node:path";
|
|
29
|
+
import fse from "fs-extra";
|
|
30
|
+
import colors from "picocolors";
|
|
31
|
+
function getAddressableRoutes(routes) {
|
|
32
|
+
let nonAddressableIds = /* @__PURE__ */ new Set();
|
|
33
|
+
for (let id in routes) {
|
|
34
|
+
let route = routes[id];
|
|
35
|
+
if (route.index) {
|
|
36
|
+
invariant(
|
|
37
|
+
route.parentId,
|
|
38
|
+
`Expected index route "${route.id}" to have "parentId" set`
|
|
39
|
+
);
|
|
40
|
+
nonAddressableIds.add(route.parentId);
|
|
41
|
+
}
|
|
42
|
+
if (typeof route.path !== "string" && !route.index) {
|
|
43
|
+
nonAddressableIds.add(id);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return Object.values(routes).filter(
|
|
47
|
+
(route) => !nonAddressableIds.has(route.id)
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
function getRouteBranch(routes, routeId) {
|
|
51
|
+
let branch = [];
|
|
52
|
+
let currentRouteId = routeId;
|
|
53
|
+
while (currentRouteId) {
|
|
54
|
+
let route = routes[currentRouteId];
|
|
55
|
+
invariant(route, `Missing route for ${currentRouteId}`);
|
|
56
|
+
branch.push(route);
|
|
57
|
+
currentRouteId = route.parentId;
|
|
58
|
+
}
|
|
59
|
+
return branch.reverse();
|
|
60
|
+
}
|
|
61
|
+
async function getServerBuilds(ctx) {
|
|
62
|
+
let { rootDirectory } = ctx;
|
|
63
|
+
const { routes, serverBuildFile, serverBundles, appDirectory } = ctx.reactRouterConfig;
|
|
64
|
+
let serverBuildDirectory = getServerBuildDirectory(ctx);
|
|
65
|
+
if (!serverBundles) {
|
|
66
|
+
return {
|
|
67
|
+
serverBuilds: [{ ssr: true }],
|
|
68
|
+
buildManifest: { routes }
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
let { normalizePath } = await import("vite");
|
|
72
|
+
let resolvedAppDirectory = path.resolve(rootDirectory, appDirectory);
|
|
73
|
+
let rootRelativeRoutes = Object.fromEntries(
|
|
74
|
+
Object.entries(routes).map(([id, route]) => {
|
|
75
|
+
let filePath = path.join(resolvedAppDirectory, route.file);
|
|
76
|
+
let rootRelativeFilePath = normalizePath(
|
|
77
|
+
path.relative(rootDirectory, filePath)
|
|
78
|
+
);
|
|
79
|
+
return [id, { ...route, file: rootRelativeFilePath }];
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
let buildManifest = {
|
|
83
|
+
serverBundles: {},
|
|
84
|
+
routeIdToServerBundleId: {},
|
|
85
|
+
routes: rootRelativeRoutes
|
|
86
|
+
};
|
|
87
|
+
let serverBundleBuildConfigById = /* @__PURE__ */ new Map();
|
|
88
|
+
await Promise.all(
|
|
89
|
+
getAddressableRoutes(routes).map(async (route) => {
|
|
90
|
+
let branch = getRouteBranch(routes, route.id);
|
|
91
|
+
let serverBundleId = await serverBundles({
|
|
92
|
+
branch: branch.map(
|
|
93
|
+
(route2) => configRouteToBranchRoute({
|
|
94
|
+
...route2,
|
|
95
|
+
// Ensure absolute paths are passed to the serverBundles function
|
|
96
|
+
file: path.join(resolvedAppDirectory, route2.file)
|
|
97
|
+
})
|
|
98
|
+
)
|
|
99
|
+
});
|
|
100
|
+
if (typeof serverBundleId !== "string") {
|
|
101
|
+
throw new Error(`The "serverBundles" function must return a string`);
|
|
102
|
+
}
|
|
103
|
+
if (!/^[a-zA-Z0-9-_]+$/.test(serverBundleId)) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
`The "serverBundles" function must only return strings containing alphanumeric characters, hyphens and underscores.`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;
|
|
109
|
+
let relativeServerBundleDirectory = path.relative(
|
|
110
|
+
rootDirectory,
|
|
111
|
+
path.join(serverBuildDirectory, serverBundleId)
|
|
112
|
+
);
|
|
113
|
+
let serverBuildConfig = serverBundleBuildConfigById.get(serverBundleId);
|
|
114
|
+
if (!serverBuildConfig) {
|
|
115
|
+
buildManifest.serverBundles[serverBundleId] = {
|
|
116
|
+
id: serverBundleId,
|
|
117
|
+
file: normalizePath(
|
|
118
|
+
path.join(relativeServerBundleDirectory, serverBuildFile)
|
|
119
|
+
)
|
|
120
|
+
};
|
|
121
|
+
serverBuildConfig = {
|
|
122
|
+
routes: {},
|
|
123
|
+
serverBundleId
|
|
124
|
+
};
|
|
125
|
+
serverBundleBuildConfigById.set(serverBundleId, serverBuildConfig);
|
|
126
|
+
}
|
|
127
|
+
for (let route2 of branch) {
|
|
128
|
+
serverBuildConfig.routes[route2.id] = route2;
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
);
|
|
132
|
+
let serverBuilds = Array.from(serverBundleBuildConfigById.values()).map(
|
|
133
|
+
(serverBundleBuildConfig) => {
|
|
134
|
+
let serverBuild = {
|
|
135
|
+
ssr: true,
|
|
136
|
+
serverBundleBuildConfig
|
|
137
|
+
};
|
|
138
|
+
return serverBuild;
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
return {
|
|
142
|
+
serverBuilds,
|
|
143
|
+
buildManifest
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
async function cleanBuildDirectory(viteConfig, ctx) {
|
|
147
|
+
let buildDirectory = ctx.reactRouterConfig.buildDirectory;
|
|
148
|
+
let isWithinRoot = () => {
|
|
149
|
+
let relativePath = path.relative(ctx.rootDirectory, buildDirectory);
|
|
150
|
+
return !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
|
|
151
|
+
};
|
|
152
|
+
if (viteConfig.build.emptyOutDir ?? isWithinRoot()) {
|
|
153
|
+
await fse.remove(buildDirectory);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function getViteManifestPaths(ctx, serverBuilds) {
|
|
157
|
+
let buildRelative = (pathname) => path.resolve(ctx.reactRouterConfig.buildDirectory, pathname);
|
|
158
|
+
let viteManifestPaths = [
|
|
159
|
+
"client/.vite/manifest.json",
|
|
160
|
+
...serverBuilds.map(({ serverBundleBuildConfig }) => {
|
|
161
|
+
let serverBundleId = serverBundleBuildConfig?.serverBundleId;
|
|
162
|
+
let serverBundlePath = serverBundleId ? serverBundleId + "/" : "";
|
|
163
|
+
return `server/${serverBundlePath}.vite/manifest.json`;
|
|
164
|
+
})
|
|
165
|
+
].map((srcPath) => buildRelative(srcPath));
|
|
166
|
+
return viteManifestPaths;
|
|
167
|
+
}
|
|
168
|
+
async function build(root, {
|
|
169
|
+
assetsInlineLimit,
|
|
170
|
+
clearScreen,
|
|
171
|
+
config: configFile,
|
|
172
|
+
emptyOutDir,
|
|
173
|
+
force,
|
|
174
|
+
logLevel,
|
|
175
|
+
minify,
|
|
176
|
+
mode,
|
|
177
|
+
sourcemapClient,
|
|
178
|
+
sourcemapServer
|
|
179
|
+
}) {
|
|
180
|
+
await preloadVite();
|
|
181
|
+
let viteConfig = await resolveViteConfig({ configFile, mode, root });
|
|
182
|
+
const ctx = await extractPluginContext(viteConfig);
|
|
183
|
+
if (!ctx) {
|
|
184
|
+
console.error(
|
|
185
|
+
colors.red("React Router Vite plugin not found in Vite config")
|
|
186
|
+
);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
let { reactRouterConfig } = ctx;
|
|
190
|
+
let vite = getVite();
|
|
191
|
+
async function viteBuild({
|
|
192
|
+
ssr,
|
|
193
|
+
serverBundleBuildConfig
|
|
194
|
+
}) {
|
|
195
|
+
await vite.build({
|
|
196
|
+
root,
|
|
197
|
+
mode,
|
|
198
|
+
configFile,
|
|
199
|
+
build: {
|
|
200
|
+
assetsInlineLimit,
|
|
201
|
+
emptyOutDir,
|
|
202
|
+
minify,
|
|
203
|
+
ssr,
|
|
204
|
+
sourcemap: ssr ? sourcemapServer : sourcemapClient
|
|
205
|
+
},
|
|
206
|
+
optimizeDeps: { force },
|
|
207
|
+
clearScreen,
|
|
208
|
+
logLevel,
|
|
209
|
+
...serverBundleBuildConfig ? { __reactRouterServerBundleBuildConfig: serverBundleBuildConfig } : {}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
await cleanBuildDirectory(viteConfig, ctx);
|
|
213
|
+
await viteBuild({ ssr: false });
|
|
214
|
+
let { serverBuilds, buildManifest } = await getServerBuilds(ctx);
|
|
215
|
+
await Promise.all(serverBuilds.map(viteBuild));
|
|
216
|
+
let viteManifestPaths = getViteManifestPaths(ctx, serverBuilds);
|
|
217
|
+
await Promise.all(
|
|
218
|
+
viteManifestPaths.map(async (viteManifestPath) => {
|
|
219
|
+
let manifestExists = await fse.pathExists(viteManifestPath);
|
|
220
|
+
if (!manifestExists) return;
|
|
221
|
+
if (!ctx.viteManifestEnabled) {
|
|
222
|
+
await fse.remove(viteManifestPath);
|
|
223
|
+
}
|
|
224
|
+
let viteDir = path.dirname(viteManifestPath);
|
|
225
|
+
let viteDirFiles = await fse.readdir(viteDir);
|
|
226
|
+
if (viteDirFiles.length === 0) {
|
|
227
|
+
await fse.remove(viteDir);
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
);
|
|
231
|
+
await reactRouterConfig.buildEnd?.({
|
|
232
|
+
buildManifest,
|
|
233
|
+
reactRouterConfig,
|
|
234
|
+
viteConfig
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
export {
|
|
238
|
+
build
|
|
239
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @react-router/dev v0.0.0-experimental-8fdb14ec6
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
12
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
13
|
+
}) : x)(function(x) {
|
|
14
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
15
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// invariant.ts
|
|
19
|
+
function invariant(value, message) {
|
|
20
|
+
if (value === false || value === null || typeof value === "undefined") {
|
|
21
|
+
console.error(
|
|
22
|
+
"The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose"
|
|
23
|
+
);
|
|
24
|
+
throw new Error(message);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
__require,
|
|
30
|
+
invariant
|
|
31
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @react-router/dev v0.0.0-experimental-8fdb14ec6
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
import {
|
|
12
|
+
invariant
|
|
13
|
+
} from "./chunk-6CEKSKVN.js";
|
|
14
|
+
|
|
15
|
+
// vite/vite.ts
|
|
16
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
17
|
+
import path2 from "pathe";
|
|
18
|
+
|
|
19
|
+
// config/is-react-router-repo.ts
|
|
20
|
+
import path from "pathe";
|
|
21
|
+
import { createRequire } from "node:module";
|
|
22
|
+
var require2 = createRequire(import.meta.url);
|
|
23
|
+
function isReactRouterRepo() {
|
|
24
|
+
let serverRuntimePath = path.dirname(
|
|
25
|
+
require2.resolve("@react-router/node/package.json")
|
|
26
|
+
);
|
|
27
|
+
let serverRuntimeParentDir = path.basename(
|
|
28
|
+
path.resolve(serverRuntimePath, "..")
|
|
29
|
+
);
|
|
30
|
+
return serverRuntimeParentDir === "packages";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// vite/vite.ts
|
|
34
|
+
var require3 = createRequire2(import.meta.url);
|
|
35
|
+
var vite;
|
|
36
|
+
var viteImportSpecifier = isReactRouterRepo() ? (
|
|
37
|
+
// Support testing against different versions of Vite by ensuring that Vite
|
|
38
|
+
// is resolved from the current working directory when running within this
|
|
39
|
+
// repo. If we don't do this, Vite will always be imported relative to this
|
|
40
|
+
// file, which means that it will always resolve to Vite 6.
|
|
41
|
+
`file:///${path2.normalize(
|
|
42
|
+
require3.resolve("vite/package.json", { paths: [process.cwd()] })
|
|
43
|
+
).replace("package.json", "dist/node/index.js")}`
|
|
44
|
+
) : "vite";
|
|
45
|
+
async function preloadVite() {
|
|
46
|
+
vite = await import(viteImportSpecifier);
|
|
47
|
+
}
|
|
48
|
+
function getVite() {
|
|
49
|
+
invariant(vite, "getVite() called before preloadVite()");
|
|
50
|
+
return vite;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export {
|
|
54
|
+
isReactRouterRepo,
|
|
55
|
+
preloadVite,
|
|
56
|
+
getVite
|
|
57
|
+
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @react-router/dev v0.0.0-experimental-8fdb14ec6
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
import {
|
|
12
|
+
invariant
|
|
13
|
+
} from "./chunk-6CEKSKVN.js";
|
|
14
|
+
|
|
15
|
+
// config/routes.ts
|
|
16
|
+
import * as Path from "pathe";
|
|
17
|
+
import * as v from "valibot";
|
|
18
|
+
import pick from "lodash/pick.js";
|
|
19
|
+
function setAppDirectory(directory) {
|
|
20
|
+
globalThis.__reactRouterAppDirectory = directory;
|
|
21
|
+
}
|
|
22
|
+
function getAppDirectory() {
|
|
23
|
+
invariant(globalThis.__reactRouterAppDirectory);
|
|
24
|
+
return globalThis.__reactRouterAppDirectory;
|
|
25
|
+
}
|
|
26
|
+
var routeConfigEntrySchema = v.pipe(
|
|
27
|
+
v.custom((value) => {
|
|
28
|
+
return !(typeof value === "object" && value !== null && "then" in value && "catch" in value);
|
|
29
|
+
}, "Invalid type: Expected object but received a promise. Did you forget to await?"),
|
|
30
|
+
v.object({
|
|
31
|
+
id: v.optional(v.string()),
|
|
32
|
+
path: v.optional(v.string()),
|
|
33
|
+
index: v.optional(v.boolean()),
|
|
34
|
+
caseSensitive: v.optional(v.boolean()),
|
|
35
|
+
file: v.string(),
|
|
36
|
+
children: v.optional(v.array(v.lazy(() => routeConfigEntrySchema)))
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
var resolvedRouteConfigSchema = v.array(routeConfigEntrySchema);
|
|
40
|
+
function validateRouteConfig({
|
|
41
|
+
routeConfigFile,
|
|
42
|
+
routeConfig
|
|
43
|
+
}) {
|
|
44
|
+
if (!routeConfig) {
|
|
45
|
+
return {
|
|
46
|
+
valid: false,
|
|
47
|
+
message: `Route config must be the default export in "${routeConfigFile}".`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (!Array.isArray(routeConfig)) {
|
|
51
|
+
return {
|
|
52
|
+
valid: false,
|
|
53
|
+
message: `Route config in "${routeConfigFile}" must be an array.`
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
let { issues } = v.safeParse(resolvedRouteConfigSchema, routeConfig);
|
|
57
|
+
if (issues?.length) {
|
|
58
|
+
let { root, nested } = v.flatten(issues);
|
|
59
|
+
return {
|
|
60
|
+
valid: false,
|
|
61
|
+
message: [
|
|
62
|
+
`Route config in "${routeConfigFile}" is invalid.`,
|
|
63
|
+
root ? `${root}` : [],
|
|
64
|
+
nested ? Object.entries(nested).map(
|
|
65
|
+
([path, message]) => `Path: routes.${path}
|
|
66
|
+
${message}`
|
|
67
|
+
) : []
|
|
68
|
+
].flat().join("\n\n")
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return { valid: true };
|
|
72
|
+
}
|
|
73
|
+
var createConfigRouteOptionKeys = [
|
|
74
|
+
"id",
|
|
75
|
+
"index",
|
|
76
|
+
"caseSensitive"
|
|
77
|
+
];
|
|
78
|
+
function route(path, file, optionsOrChildren, children) {
|
|
79
|
+
let options = {};
|
|
80
|
+
if (Array.isArray(optionsOrChildren) || !optionsOrChildren) {
|
|
81
|
+
children = optionsOrChildren;
|
|
82
|
+
} else {
|
|
83
|
+
options = optionsOrChildren;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
file,
|
|
87
|
+
children,
|
|
88
|
+
path: path ?? void 0,
|
|
89
|
+
...pick(options, createConfigRouteOptionKeys)
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
var createIndexOptionKeys = ["id"];
|
|
93
|
+
function index(file, options) {
|
|
94
|
+
return {
|
|
95
|
+
file,
|
|
96
|
+
index: true,
|
|
97
|
+
...pick(options, createIndexOptionKeys)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
var createLayoutOptionKeys = ["id"];
|
|
101
|
+
function layout(file, optionsOrChildren, children) {
|
|
102
|
+
let options = {};
|
|
103
|
+
if (Array.isArray(optionsOrChildren) || !optionsOrChildren) {
|
|
104
|
+
children = optionsOrChildren;
|
|
105
|
+
} else {
|
|
106
|
+
options = optionsOrChildren;
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
file,
|
|
110
|
+
children,
|
|
111
|
+
...pick(options, createLayoutOptionKeys)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function prefix(prefixPath, routes) {
|
|
115
|
+
return routes.map((route2) => {
|
|
116
|
+
if (route2.index || typeof route2.path === "string") {
|
|
117
|
+
return {
|
|
118
|
+
...route2,
|
|
119
|
+
path: route2.path ? joinRoutePaths(prefixPath, route2.path) : prefixPath,
|
|
120
|
+
children: route2.children
|
|
121
|
+
};
|
|
122
|
+
} else if (route2.children) {
|
|
123
|
+
return {
|
|
124
|
+
...route2,
|
|
125
|
+
children: prefix(prefixPath, route2.children)
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return route2;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function relative2(directory) {
|
|
132
|
+
return {
|
|
133
|
+
/**
|
|
134
|
+
* Helper function for creating a route config entry, for use within
|
|
135
|
+
* `routes.ts`. Note that this helper has been scoped, meaning that file
|
|
136
|
+
* path will be resolved relative to the directory provided to the
|
|
137
|
+
* `relative` call that created this helper.
|
|
138
|
+
*/
|
|
139
|
+
route: (path, file, ...rest) => {
|
|
140
|
+
return route(path, Path.resolve(directory, file), ...rest);
|
|
141
|
+
},
|
|
142
|
+
/**
|
|
143
|
+
* Helper function for creating a route config entry for an index route, for
|
|
144
|
+
* use within `routes.ts`. Note that this helper has been scoped, meaning
|
|
145
|
+
* that file path will be resolved relative to the directory provided to the
|
|
146
|
+
* `relative` call that created this helper.
|
|
147
|
+
*/
|
|
148
|
+
index: (file, ...rest) => {
|
|
149
|
+
return index(Path.resolve(directory, file), ...rest);
|
|
150
|
+
},
|
|
151
|
+
/**
|
|
152
|
+
* Helper function for creating a route config entry for a layout route, for
|
|
153
|
+
* use within `routes.ts`. Note that this helper has been scoped, meaning
|
|
154
|
+
* that file path will be resolved relative to the directory provided to the
|
|
155
|
+
* `relative` call that created this helper.
|
|
156
|
+
*/
|
|
157
|
+
layout: (file, ...rest) => {
|
|
158
|
+
return layout(Path.resolve(directory, file), ...rest);
|
|
159
|
+
},
|
|
160
|
+
// Passthrough of helper functions that don't need relative scoping so that
|
|
161
|
+
// a complete API is still provided.
|
|
162
|
+
prefix
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function configRoutesToRouteManifest(appDirectory, routes, rootId = "root") {
|
|
166
|
+
let routeManifest = {};
|
|
167
|
+
function walk(route2, parentId) {
|
|
168
|
+
let id = route2.id || createRouteId(route2.file);
|
|
169
|
+
let manifestItem = {
|
|
170
|
+
id,
|
|
171
|
+
parentId,
|
|
172
|
+
file: Path.isAbsolute(route2.file) ? Path.relative(appDirectory, route2.file) : route2.file,
|
|
173
|
+
path: route2.path,
|
|
174
|
+
index: route2.index,
|
|
175
|
+
caseSensitive: route2.caseSensitive
|
|
176
|
+
};
|
|
177
|
+
if (routeManifest.hasOwnProperty(id)) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Unable to define routes with duplicate route id: "${id}"`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
routeManifest[id] = manifestItem;
|
|
183
|
+
if (route2.children) {
|
|
184
|
+
for (let child of route2.children) {
|
|
185
|
+
walk(child, id);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
for (let route2 of routes) {
|
|
190
|
+
walk(route2, rootId);
|
|
191
|
+
}
|
|
192
|
+
return routeManifest;
|
|
193
|
+
}
|
|
194
|
+
function createRouteId(file) {
|
|
195
|
+
return Path.normalize(stripFileExtension(file));
|
|
196
|
+
}
|
|
197
|
+
function stripFileExtension(file) {
|
|
198
|
+
return file.replace(/\.[a-z0-9]+$/i, "");
|
|
199
|
+
}
|
|
200
|
+
function joinRoutePaths(path1, path2) {
|
|
201
|
+
return [
|
|
202
|
+
path1.replace(/\/+$/, ""),
|
|
203
|
+
// Remove trailing slashes
|
|
204
|
+
path2.replace(/^\/+/, "")
|
|
205
|
+
// Remove leading slashes
|
|
206
|
+
].join("/");
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export {
|
|
210
|
+
setAppDirectory,
|
|
211
|
+
getAppDirectory,
|
|
212
|
+
validateRouteConfig,
|
|
213
|
+
route,
|
|
214
|
+
index,
|
|
215
|
+
layout,
|
|
216
|
+
prefix,
|
|
217
|
+
relative2 as relative,
|
|
218
|
+
configRoutesToRouteManifest
|
|
219
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @react-router/dev v0.0.0-experimental-8fdb14ec6
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
import {
|
|
12
|
+
invariant
|
|
13
|
+
} from "./chunk-6CEKSKVN.js";
|
|
14
|
+
|
|
15
|
+
// vite/node-adapter.ts
|
|
16
|
+
import { once } from "node:events";
|
|
17
|
+
import { Readable } from "node:stream";
|
|
18
|
+
import { splitCookiesString } from "set-cookie-parser";
|
|
19
|
+
import { createReadableStreamFromReadable } from "@react-router/node";
|
|
20
|
+
function fromNodeHeaders(nodeHeaders) {
|
|
21
|
+
let headers = new Headers();
|
|
22
|
+
for (let [key, values] of Object.entries(nodeHeaders)) {
|
|
23
|
+
if (values) {
|
|
24
|
+
if (Array.isArray(values)) {
|
|
25
|
+
for (let value of values) {
|
|
26
|
+
headers.append(key, value);
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
headers.set(key, values);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return headers;
|
|
34
|
+
}
|
|
35
|
+
function fromNodeRequest(nodeReq, nodeRes) {
|
|
36
|
+
let origin = nodeReq.headers.origin && "null" !== nodeReq.headers.origin ? nodeReq.headers.origin : `http://${nodeReq.headers.host}`;
|
|
37
|
+
invariant(
|
|
38
|
+
nodeReq.originalUrl,
|
|
39
|
+
"Expected `nodeReq.originalUrl` to be defined"
|
|
40
|
+
);
|
|
41
|
+
let url = new URL(nodeReq.originalUrl, origin);
|
|
42
|
+
let controller = new AbortController();
|
|
43
|
+
let init = {
|
|
44
|
+
method: nodeReq.method,
|
|
45
|
+
headers: fromNodeHeaders(nodeReq.headers),
|
|
46
|
+
signal: controller.signal
|
|
47
|
+
};
|
|
48
|
+
nodeRes.on("finish", () => controller = null);
|
|
49
|
+
nodeRes.on("close", () => controller?.abort());
|
|
50
|
+
if (nodeReq.method !== "GET" && nodeReq.method !== "HEAD") {
|
|
51
|
+
init.body = createReadableStreamFromReadable(nodeReq);
|
|
52
|
+
init.duplex = "half";
|
|
53
|
+
}
|
|
54
|
+
return new Request(url.href, init);
|
|
55
|
+
}
|
|
56
|
+
async function toNodeRequest(res, nodeRes) {
|
|
57
|
+
nodeRes.statusCode = res.status;
|
|
58
|
+
nodeRes.statusMessage = res.statusText;
|
|
59
|
+
let cookiesStrings = [];
|
|
60
|
+
for (let [name, value] of res.headers) {
|
|
61
|
+
if (name === "set-cookie") {
|
|
62
|
+
cookiesStrings.push(...splitCookiesString(value));
|
|
63
|
+
} else nodeRes.setHeader(name, value);
|
|
64
|
+
}
|
|
65
|
+
if (cookiesStrings.length) {
|
|
66
|
+
nodeRes.setHeader("set-cookie", cookiesStrings);
|
|
67
|
+
}
|
|
68
|
+
if (res.body) {
|
|
69
|
+
let responseBody = res.body;
|
|
70
|
+
let readable = Readable.from(responseBody);
|
|
71
|
+
readable.pipe(nodeRes);
|
|
72
|
+
await once(readable, "end");
|
|
73
|
+
} else {
|
|
74
|
+
nodeRes.end();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export {
|
|
79
|
+
fromNodeRequest,
|
|
80
|
+
toNodeRequest
|
|
81
|
+
};
|