@c0va23/react-router-dev 7.8.3-alpha.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 +2512 -0
- package/LICENSE.md +23 -0
- package/README.md +5 -0
- package/bin.js +15 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +2521 -0
- package/dist/config/default-rsc-entries/entry.client.tsx +46 -0
- package/dist/config/default-rsc-entries/entry.rsc.tsx +42 -0
- package/dist/config/default-rsc-entries/entry.ssr.tsx +35 -0
- package/dist/config/defaults/entry.client.tsx +12 -0
- package/dist/config/defaults/entry.server.node.tsx +80 -0
- package/dist/config.d.ts +211 -0
- package/dist/config.js +28 -0
- package/dist/internal.d.ts +9 -0
- package/dist/internal.js +2216 -0
- package/dist/routes-CZR-bKRt.d.ts +123 -0
- package/dist/routes.d.ts +2 -0
- package/dist/routes.js +199 -0
- package/dist/static/refresh-utils.mjs +170 -0
- package/dist/static/rsc-refresh-utils.mjs +126 -0
- package/dist/vite/cloudflare.d.ts +24 -0
- package/dist/vite/cloudflare.js +900 -0
- package/dist/vite.d.ts +11 -0
- package/dist/vite.js +4914 -0
- package/module-sync-enabled/false.cjs +1 -0
- package/module-sync-enabled/index.d.mts +2 -0
- package/module-sync-enabled/index.mjs +4 -0
- package/module-sync-enabled/true.mjs +2 -0
- package/package.json +157 -0
package/dist/vite.js
ADDED
|
@@ -0,0 +1,4914 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @c0va23/react-router-dev v7.8.3-alpha.1
|
|
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
|
+
"use strict";
|
|
12
|
+
var __create = Object.create;
|
|
13
|
+
var __defProp = Object.defineProperty;
|
|
14
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
15
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
16
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
17
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
18
|
+
var __export = (target, all) => {
|
|
19
|
+
for (var name in all)
|
|
20
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
21
|
+
};
|
|
22
|
+
var __copyProps = (to, from, except, desc) => {
|
|
23
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
24
|
+
for (let key of __getOwnPropNames(from))
|
|
25
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
26
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
27
|
+
}
|
|
28
|
+
return to;
|
|
29
|
+
};
|
|
30
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
31
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
32
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
33
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
34
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
35
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
36
|
+
mod
|
|
37
|
+
));
|
|
38
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
39
|
+
|
|
40
|
+
// vite.ts
|
|
41
|
+
var vite_exports = {};
|
|
42
|
+
__export(vite_exports, {
|
|
43
|
+
reactRouter: () => reactRouterVitePlugin
|
|
44
|
+
});
|
|
45
|
+
module.exports = __toCommonJS(vite_exports);
|
|
46
|
+
|
|
47
|
+
// vite/plugin.ts
|
|
48
|
+
var import_node_crypto = require("crypto");
|
|
49
|
+
var import_node_fs2 = require("fs");
|
|
50
|
+
var import_promises2 = require("fs/promises");
|
|
51
|
+
var path6 = __toESM(require("path"));
|
|
52
|
+
var url = __toESM(require("url"));
|
|
53
|
+
var babel = __toESM(require("@babel/core"));
|
|
54
|
+
var import_react_router2 = require("react-router");
|
|
55
|
+
var import_es_module_lexer = require("es-module-lexer");
|
|
56
|
+
var import_pick3 = __toESM(require("lodash/pick"));
|
|
57
|
+
var import_jsesc = __toESM(require("jsesc"));
|
|
58
|
+
var import_picocolors3 = __toESM(require("picocolors"));
|
|
59
|
+
var import_kebabCase = __toESM(require("lodash/kebabCase"));
|
|
60
|
+
|
|
61
|
+
// typegen/index.ts
|
|
62
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
63
|
+
var Path4 = __toESM(require("pathe"));
|
|
64
|
+
var import_picocolors2 = require("picocolors");
|
|
65
|
+
|
|
66
|
+
// config/config.ts
|
|
67
|
+
var import_node_fs = __toESM(require("fs"));
|
|
68
|
+
var import_node_child_process = require("child_process");
|
|
69
|
+
var import_package_json = __toESM(require("@npmcli/package-json"));
|
|
70
|
+
|
|
71
|
+
// vite/vite.ts
|
|
72
|
+
var import_pathe2 = __toESM(require("pathe"));
|
|
73
|
+
|
|
74
|
+
// invariant.ts
|
|
75
|
+
function invariant(value, message) {
|
|
76
|
+
if (value === false || value === null || typeof value === "undefined") {
|
|
77
|
+
console.error(
|
|
78
|
+
"The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose"
|
|
79
|
+
);
|
|
80
|
+
throw new Error(message);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// config/is-react-router-repo.ts
|
|
85
|
+
var import_pathe = __toESM(require("pathe"));
|
|
86
|
+
function isReactRouterRepo() {
|
|
87
|
+
let serverRuntimePath = import_pathe.default.dirname(
|
|
88
|
+
require.resolve("@react-router/node/package.json")
|
|
89
|
+
);
|
|
90
|
+
let serverRuntimeParentDir = import_pathe.default.basename(
|
|
91
|
+
import_pathe.default.resolve(serverRuntimePath, "..")
|
|
92
|
+
);
|
|
93
|
+
return serverRuntimeParentDir === "packages";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// vite/vite.ts
|
|
97
|
+
var vite;
|
|
98
|
+
var viteImportSpecifier = isReactRouterRepo() ? (
|
|
99
|
+
// Support testing against different versions of Vite by ensuring that Vite
|
|
100
|
+
// is resolved from the current working directory when running within this
|
|
101
|
+
// repo. If we don't do this, Vite will always be imported relative to this
|
|
102
|
+
// file, which means that it will always resolve to Vite 6.
|
|
103
|
+
`file:///${import_pathe2.default.normalize(
|
|
104
|
+
require.resolve("vite/package.json", { paths: [process.cwd()] })
|
|
105
|
+
).replace("package.json", "dist/node/index.js")}`
|
|
106
|
+
) : "vite";
|
|
107
|
+
async function preloadVite() {
|
|
108
|
+
vite = await import(viteImportSpecifier);
|
|
109
|
+
}
|
|
110
|
+
function getVite() {
|
|
111
|
+
invariant(vite, "getVite() called before preloadVite()");
|
|
112
|
+
return vite;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// vite/ssr-externals.ts
|
|
116
|
+
var ssrExternals = isReactRouterRepo() ? [
|
|
117
|
+
// This is only needed within this repo because these packages
|
|
118
|
+
// are linked to a directory outside of node_modules so Vite
|
|
119
|
+
// treats them as internal code by default.
|
|
120
|
+
"react-router",
|
|
121
|
+
"react-router-dom",
|
|
122
|
+
"@react-router/architect",
|
|
123
|
+
"@react-router/cloudflare",
|
|
124
|
+
"@react-router/dev",
|
|
125
|
+
"@react-router/express",
|
|
126
|
+
"@react-router/node",
|
|
127
|
+
"@react-router/serve"
|
|
128
|
+
] : void 0;
|
|
129
|
+
|
|
130
|
+
// vite/vite-node.ts
|
|
131
|
+
async function createContext({
|
|
132
|
+
root,
|
|
133
|
+
mode,
|
|
134
|
+
customLogger
|
|
135
|
+
}) {
|
|
136
|
+
await preloadVite();
|
|
137
|
+
const vite2 = getVite();
|
|
138
|
+
const [{ ViteNodeServer }, { ViteNodeRunner }, { installSourcemapsSupport }] = await Promise.all([
|
|
139
|
+
import("vite-node/server"),
|
|
140
|
+
import("vite-node/client"),
|
|
141
|
+
import("vite-node/source-map")
|
|
142
|
+
]);
|
|
143
|
+
const devServer = await vite2.createServer({
|
|
144
|
+
root,
|
|
145
|
+
mode,
|
|
146
|
+
customLogger,
|
|
147
|
+
server: {
|
|
148
|
+
preTransformRequests: false,
|
|
149
|
+
hmr: false,
|
|
150
|
+
watch: null
|
|
151
|
+
},
|
|
152
|
+
ssr: {
|
|
153
|
+
external: ssrExternals
|
|
154
|
+
},
|
|
155
|
+
optimizeDeps: {
|
|
156
|
+
noDiscovery: true
|
|
157
|
+
},
|
|
158
|
+
css: {
|
|
159
|
+
// This empty PostCSS config object prevents the PostCSS config file from
|
|
160
|
+
// being loaded. We don't need it in a React Router config context, and
|
|
161
|
+
// there's also an issue in Vite 5 when using a .ts PostCSS config file in
|
|
162
|
+
// an ESM project: https://github.com/vitejs/vite/issues/15869. Consumers
|
|
163
|
+
// can work around this in their own Vite config file, but they can't
|
|
164
|
+
// configure this internal usage of vite-node.
|
|
165
|
+
postcss: {}
|
|
166
|
+
},
|
|
167
|
+
configFile: false,
|
|
168
|
+
envFile: false,
|
|
169
|
+
plugins: []
|
|
170
|
+
});
|
|
171
|
+
await devServer.pluginContainer.buildStart({});
|
|
172
|
+
const server = new ViteNodeServer(devServer);
|
|
173
|
+
installSourcemapsSupport({
|
|
174
|
+
getSourceMap: (source) => server.getSourceMap(source)
|
|
175
|
+
});
|
|
176
|
+
const runner = new ViteNodeRunner({
|
|
177
|
+
root: devServer.config.root,
|
|
178
|
+
base: devServer.config.base,
|
|
179
|
+
fetchModule(id) {
|
|
180
|
+
return server.fetchModule(id);
|
|
181
|
+
},
|
|
182
|
+
resolveId(id, importer) {
|
|
183
|
+
return server.resolveId(id, importer);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
return { devServer, server, runner };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// config/config.ts
|
|
190
|
+
var import_pathe3 = __toESM(require("pathe"));
|
|
191
|
+
var import_chokidar = __toESM(require("chokidar"));
|
|
192
|
+
var import_picocolors = __toESM(require("picocolors"));
|
|
193
|
+
var import_pick2 = __toESM(require("lodash/pick"));
|
|
194
|
+
var import_omit = __toESM(require("lodash/omit"));
|
|
195
|
+
var import_cloneDeep = __toESM(require("lodash/cloneDeep"));
|
|
196
|
+
var import_isEqual = __toESM(require("lodash/isEqual"));
|
|
197
|
+
|
|
198
|
+
// config/routes.ts
|
|
199
|
+
var Path = __toESM(require("pathe"));
|
|
200
|
+
var v = __toESM(require("valibot"));
|
|
201
|
+
var import_pick = __toESM(require("lodash/pick"));
|
|
202
|
+
function setAppDirectory(directory) {
|
|
203
|
+
globalThis.__reactRouterAppDirectory = directory;
|
|
204
|
+
}
|
|
205
|
+
var routeConfigEntrySchema = v.pipe(
|
|
206
|
+
v.custom((value) => {
|
|
207
|
+
return !(typeof value === "object" && value !== null && "then" in value && "catch" in value);
|
|
208
|
+
}, "Invalid type: Expected object but received a promise. Did you forget to await?"),
|
|
209
|
+
v.object({
|
|
210
|
+
id: v.optional(
|
|
211
|
+
v.pipe(
|
|
212
|
+
v.string(),
|
|
213
|
+
v.notValue("root", "A route cannot use the reserved id 'root'.")
|
|
214
|
+
)
|
|
215
|
+
),
|
|
216
|
+
path: v.optional(v.string()),
|
|
217
|
+
index: v.optional(v.boolean()),
|
|
218
|
+
caseSensitive: v.optional(v.boolean()),
|
|
219
|
+
file: v.string(),
|
|
220
|
+
children: v.optional(v.array(v.lazy(() => routeConfigEntrySchema)))
|
|
221
|
+
})
|
|
222
|
+
);
|
|
223
|
+
var resolvedRouteConfigSchema = v.array(routeConfigEntrySchema);
|
|
224
|
+
function validateRouteConfig({
|
|
225
|
+
routeConfigFile,
|
|
226
|
+
routeConfig
|
|
227
|
+
}) {
|
|
228
|
+
if (!routeConfig) {
|
|
229
|
+
return {
|
|
230
|
+
valid: false,
|
|
231
|
+
message: `Route config must be the default export in "${routeConfigFile}".`
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
if (!Array.isArray(routeConfig)) {
|
|
235
|
+
return {
|
|
236
|
+
valid: false,
|
|
237
|
+
message: `Route config in "${routeConfigFile}" must be an array.`
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
let { issues } = v.safeParse(resolvedRouteConfigSchema, routeConfig);
|
|
241
|
+
if (issues?.length) {
|
|
242
|
+
let { root, nested } = v.flatten(issues);
|
|
243
|
+
return {
|
|
244
|
+
valid: false,
|
|
245
|
+
message: [
|
|
246
|
+
`Route config in "${routeConfigFile}" is invalid.`,
|
|
247
|
+
root ? `${root}` : [],
|
|
248
|
+
nested ? Object.entries(nested).map(
|
|
249
|
+
([path7, message]) => `Path: routes.${path7}
|
|
250
|
+
${message}`
|
|
251
|
+
) : []
|
|
252
|
+
].flat().join("\n\n")
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
valid: true,
|
|
257
|
+
routeConfig
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function configRoutesToRouteManifest(appDirectory, routes) {
|
|
261
|
+
let routeManifest = {};
|
|
262
|
+
function walk(route, parentId) {
|
|
263
|
+
let id = route.id || createRouteId(route.file);
|
|
264
|
+
let manifestItem = {
|
|
265
|
+
id,
|
|
266
|
+
parentId,
|
|
267
|
+
file: Path.isAbsolute(route.file) ? Path.relative(appDirectory, route.file) : route.file,
|
|
268
|
+
path: route.path,
|
|
269
|
+
index: route.index,
|
|
270
|
+
caseSensitive: route.caseSensitive
|
|
271
|
+
};
|
|
272
|
+
if (routeManifest.hasOwnProperty(id)) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
`Unable to define routes with duplicate route id: "${id}"`
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
routeManifest[id] = manifestItem;
|
|
278
|
+
if (route.children) {
|
|
279
|
+
for (let child of route.children) {
|
|
280
|
+
walk(child, id);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
for (let route of routes) {
|
|
285
|
+
walk(route);
|
|
286
|
+
}
|
|
287
|
+
return routeManifest;
|
|
288
|
+
}
|
|
289
|
+
function createRouteId(file) {
|
|
290
|
+
return Path.normalize(stripFileExtension(file));
|
|
291
|
+
}
|
|
292
|
+
function stripFileExtension(file) {
|
|
293
|
+
return file.replace(/\.[a-z0-9]+$/i, "");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// cli/detectPackageManager.ts
|
|
297
|
+
var detectPackageManager = () => {
|
|
298
|
+
let { npm_config_user_agent } = process.env;
|
|
299
|
+
if (!npm_config_user_agent) return void 0;
|
|
300
|
+
try {
|
|
301
|
+
let pkgManager = npm_config_user_agent.split("/")[0];
|
|
302
|
+
if (pkgManager === "npm") return "npm";
|
|
303
|
+
if (pkgManager === "pnpm") return "pnpm";
|
|
304
|
+
if (pkgManager === "yarn") return "yarn";
|
|
305
|
+
if (pkgManager === "bun") return "bun";
|
|
306
|
+
return void 0;
|
|
307
|
+
} catch {
|
|
308
|
+
return void 0;
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// config/config.ts
|
|
313
|
+
var excludedConfigPresetKeys = ["presets"];
|
|
314
|
+
var branchRouteProperties = [
|
|
315
|
+
"id",
|
|
316
|
+
"path",
|
|
317
|
+
"file",
|
|
318
|
+
"index"
|
|
319
|
+
];
|
|
320
|
+
var configRouteToBranchRoute = (configRoute) => (0, import_pick2.default)(configRoute, branchRouteProperties);
|
|
321
|
+
var mergeReactRouterConfig = (...configs) => {
|
|
322
|
+
let reducer = (configA, configB) => {
|
|
323
|
+
let mergeRequired = (key) => configA[key] !== void 0 && configB[key] !== void 0;
|
|
324
|
+
return {
|
|
325
|
+
...configA,
|
|
326
|
+
...configB,
|
|
327
|
+
...mergeRequired("buildEnd") ? {
|
|
328
|
+
buildEnd: async (...args) => {
|
|
329
|
+
await Promise.all([
|
|
330
|
+
configA.buildEnd?.(...args),
|
|
331
|
+
configB.buildEnd?.(...args)
|
|
332
|
+
]);
|
|
333
|
+
}
|
|
334
|
+
} : {},
|
|
335
|
+
...mergeRequired("future") ? {
|
|
336
|
+
future: {
|
|
337
|
+
...configA.future,
|
|
338
|
+
...configB.future
|
|
339
|
+
}
|
|
340
|
+
} : {},
|
|
341
|
+
...mergeRequired("presets") ? {
|
|
342
|
+
presets: [...configA.presets ?? [], ...configB.presets ?? []]
|
|
343
|
+
} : {}
|
|
344
|
+
};
|
|
345
|
+
};
|
|
346
|
+
return configs.reduce(reducer, {});
|
|
347
|
+
};
|
|
348
|
+
var deepFreeze = (o) => {
|
|
349
|
+
Object.freeze(o);
|
|
350
|
+
let oIsFunction = typeof o === "function";
|
|
351
|
+
let hasOwnProp = Object.prototype.hasOwnProperty;
|
|
352
|
+
Object.getOwnPropertyNames(o).forEach(function(prop) {
|
|
353
|
+
if (hasOwnProp.call(o, prop) && (oIsFunction ? prop !== "caller" && prop !== "callee" && prop !== "arguments" : true) && o[prop] !== null && (typeof o[prop] === "object" || typeof o[prop] === "function") && !Object.isFrozen(o[prop])) {
|
|
354
|
+
deepFreeze(o[prop]);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
return o;
|
|
358
|
+
};
|
|
359
|
+
function ok(value) {
|
|
360
|
+
return { ok: true, value };
|
|
361
|
+
}
|
|
362
|
+
function err(error) {
|
|
363
|
+
return { ok: false, error };
|
|
364
|
+
}
|
|
365
|
+
async function resolveConfig({
|
|
366
|
+
root,
|
|
367
|
+
viteNodeContext,
|
|
368
|
+
reactRouterConfigFile,
|
|
369
|
+
skipRoutes,
|
|
370
|
+
validateConfig
|
|
371
|
+
}) {
|
|
372
|
+
let reactRouterUserConfig = {};
|
|
373
|
+
if (reactRouterConfigFile) {
|
|
374
|
+
try {
|
|
375
|
+
if (!import_node_fs.default.existsSync(reactRouterConfigFile)) {
|
|
376
|
+
return err(`${reactRouterConfigFile} no longer exists`);
|
|
377
|
+
}
|
|
378
|
+
let configModule = await viteNodeContext.runner.executeFile(
|
|
379
|
+
reactRouterConfigFile
|
|
380
|
+
);
|
|
381
|
+
if (configModule.default === void 0) {
|
|
382
|
+
return err(`${reactRouterConfigFile} must provide a default export`);
|
|
383
|
+
}
|
|
384
|
+
if (typeof configModule.default !== "object") {
|
|
385
|
+
return err(`${reactRouterConfigFile} must export a config`);
|
|
386
|
+
}
|
|
387
|
+
reactRouterUserConfig = configModule.default;
|
|
388
|
+
if (validateConfig) {
|
|
389
|
+
const error = validateConfig(reactRouterUserConfig);
|
|
390
|
+
if (error) {
|
|
391
|
+
return err(error);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
} catch (error) {
|
|
395
|
+
return err(`Error loading ${reactRouterConfigFile}: ${error}`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
reactRouterUserConfig = deepFreeze((0, import_cloneDeep.default)(reactRouterUserConfig));
|
|
399
|
+
let presets = (await Promise.all(
|
|
400
|
+
(reactRouterUserConfig.presets ?? []).map(async (preset) => {
|
|
401
|
+
if (!preset.name) {
|
|
402
|
+
throw new Error(
|
|
403
|
+
"React Router presets must have a `name` property defined."
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
if (!preset.reactRouterConfig) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
let configPreset = (0, import_omit.default)(
|
|
410
|
+
await preset.reactRouterConfig({ reactRouterUserConfig }),
|
|
411
|
+
excludedConfigPresetKeys
|
|
412
|
+
);
|
|
413
|
+
return configPreset;
|
|
414
|
+
})
|
|
415
|
+
)).filter(function isNotNull(value) {
|
|
416
|
+
return value !== null;
|
|
417
|
+
});
|
|
418
|
+
let defaults = {
|
|
419
|
+
basename: "/",
|
|
420
|
+
buildDirectory: "build",
|
|
421
|
+
serverBuildFile: "index.js",
|
|
422
|
+
serverModuleFormat: "esm",
|
|
423
|
+
ssr: true
|
|
424
|
+
};
|
|
425
|
+
let userAndPresetConfigs = mergeReactRouterConfig(
|
|
426
|
+
...presets,
|
|
427
|
+
reactRouterUserConfig
|
|
428
|
+
);
|
|
429
|
+
let {
|
|
430
|
+
appDirectory: userAppDirectory,
|
|
431
|
+
basename: basename3,
|
|
432
|
+
buildDirectory: userBuildDirectory,
|
|
433
|
+
buildEnd,
|
|
434
|
+
prerender,
|
|
435
|
+
routeDiscovery: userRouteDiscovery,
|
|
436
|
+
serverBuildFile,
|
|
437
|
+
serverBundles,
|
|
438
|
+
serverModuleFormat,
|
|
439
|
+
ssr
|
|
440
|
+
} = {
|
|
441
|
+
...defaults,
|
|
442
|
+
// Default values should be completely overridden by user/preset config, not merged
|
|
443
|
+
...userAndPresetConfigs
|
|
444
|
+
};
|
|
445
|
+
if (!ssr && serverBundles) {
|
|
446
|
+
serverBundles = void 0;
|
|
447
|
+
}
|
|
448
|
+
let isValidPrerenderConfig = prerender == null || typeof prerender === "boolean" || Array.isArray(prerender) || typeof prerender === "function";
|
|
449
|
+
if (!isValidPrerenderConfig) {
|
|
450
|
+
return err(
|
|
451
|
+
"The `prerender` config must be a boolean, an array of string paths, or a function returning a boolean or array of string paths"
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
let routeDiscovery;
|
|
455
|
+
if (userRouteDiscovery == null) {
|
|
456
|
+
if (ssr) {
|
|
457
|
+
routeDiscovery = {
|
|
458
|
+
mode: "lazy",
|
|
459
|
+
manifestPath: "/__manifest"
|
|
460
|
+
};
|
|
461
|
+
} else {
|
|
462
|
+
routeDiscovery = { mode: "initial" };
|
|
463
|
+
}
|
|
464
|
+
} else if (userRouteDiscovery.mode === "initial") {
|
|
465
|
+
routeDiscovery = userRouteDiscovery;
|
|
466
|
+
} else if (userRouteDiscovery.mode === "lazy") {
|
|
467
|
+
if (!ssr) {
|
|
468
|
+
return err(
|
|
469
|
+
'The `routeDiscovery.mode` config cannot be set to "lazy" when setting `ssr:false`'
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
let { manifestPath } = userRouteDiscovery;
|
|
473
|
+
if (manifestPath != null && !manifestPath.startsWith("/")) {
|
|
474
|
+
return err(
|
|
475
|
+
'The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., "/__manifest")'
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
routeDiscovery = userRouteDiscovery;
|
|
479
|
+
}
|
|
480
|
+
let appDirectory = import_pathe3.default.resolve(root, userAppDirectory || "app");
|
|
481
|
+
let buildDirectory = import_pathe3.default.resolve(root, userBuildDirectory);
|
|
482
|
+
let rootRouteFile = findEntry(appDirectory, "root");
|
|
483
|
+
if (!rootRouteFile) {
|
|
484
|
+
let rootRouteDisplayPath = import_pathe3.default.relative(
|
|
485
|
+
root,
|
|
486
|
+
import_pathe3.default.join(appDirectory, "root.tsx")
|
|
487
|
+
);
|
|
488
|
+
return err(
|
|
489
|
+
`Could not find a root route module in the app directory as "${rootRouteDisplayPath}"`
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
let routes;
|
|
493
|
+
let routeConfig = [];
|
|
494
|
+
if (skipRoutes) {
|
|
495
|
+
routes = {};
|
|
496
|
+
} else {
|
|
497
|
+
let routeConfigFile = findEntry(appDirectory, "routes");
|
|
498
|
+
try {
|
|
499
|
+
if (!routeConfigFile) {
|
|
500
|
+
let routeConfigDisplayPath = import_pathe3.default.relative(
|
|
501
|
+
root,
|
|
502
|
+
import_pathe3.default.join(appDirectory, "routes.ts")
|
|
503
|
+
);
|
|
504
|
+
return err(
|
|
505
|
+
`Route config file not found at "${routeConfigDisplayPath}".`
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
setAppDirectory(appDirectory);
|
|
509
|
+
let routeConfigExport = (await viteNodeContext.runner.executeFile(
|
|
510
|
+
import_pathe3.default.join(appDirectory, routeConfigFile)
|
|
511
|
+
)).default;
|
|
512
|
+
let result = validateRouteConfig({
|
|
513
|
+
routeConfigFile,
|
|
514
|
+
routeConfig: await routeConfigExport
|
|
515
|
+
});
|
|
516
|
+
if (!result.valid) {
|
|
517
|
+
return err(result.message);
|
|
518
|
+
}
|
|
519
|
+
routeConfig = [
|
|
520
|
+
{
|
|
521
|
+
id: "root",
|
|
522
|
+
path: "",
|
|
523
|
+
file: rootRouteFile,
|
|
524
|
+
children: result.routeConfig
|
|
525
|
+
}
|
|
526
|
+
];
|
|
527
|
+
routes = configRoutesToRouteManifest(appDirectory, routeConfig);
|
|
528
|
+
} catch (error) {
|
|
529
|
+
return err(
|
|
530
|
+
[
|
|
531
|
+
import_picocolors.default.red(`Route config in "${routeConfigFile}" is invalid.`),
|
|
532
|
+
"",
|
|
533
|
+
error.loc?.file && error.loc?.column && error.frame ? [
|
|
534
|
+
import_pathe3.default.relative(appDirectory, error.loc.file) + ":" + error.loc.line + ":" + error.loc.column,
|
|
535
|
+
error.frame.trim?.()
|
|
536
|
+
] : error.stack
|
|
537
|
+
].flat().join("\n")
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
let future = {
|
|
542
|
+
v8_middleware: reactRouterUserConfig.future?.v8_middleware ?? false,
|
|
543
|
+
unstable_optimizeDeps: reactRouterUserConfig.future?.unstable_optimizeDeps ?? false,
|
|
544
|
+
unstable_splitRouteModules: reactRouterUserConfig.future?.unstable_splitRouteModules ?? false,
|
|
545
|
+
unstable_subResourceIntegrity: reactRouterUserConfig.future?.unstable_subResourceIntegrity ?? false,
|
|
546
|
+
unstable_viteEnvironmentApi: reactRouterUserConfig.future?.unstable_viteEnvironmentApi ?? false
|
|
547
|
+
};
|
|
548
|
+
let reactRouterConfig = deepFreeze({
|
|
549
|
+
appDirectory,
|
|
550
|
+
basename: basename3,
|
|
551
|
+
buildDirectory,
|
|
552
|
+
buildEnd,
|
|
553
|
+
future,
|
|
554
|
+
prerender,
|
|
555
|
+
routes,
|
|
556
|
+
routeDiscovery,
|
|
557
|
+
serverBuildFile,
|
|
558
|
+
serverBundles,
|
|
559
|
+
serverModuleFormat,
|
|
560
|
+
ssr,
|
|
561
|
+
unstable_routeConfig: routeConfig
|
|
562
|
+
});
|
|
563
|
+
for (let preset of reactRouterUserConfig.presets ?? []) {
|
|
564
|
+
await preset.reactRouterConfigResolved?.({ reactRouterConfig });
|
|
565
|
+
}
|
|
566
|
+
return ok(reactRouterConfig);
|
|
567
|
+
}
|
|
568
|
+
async function createConfigLoader({
|
|
569
|
+
rootDirectory: root,
|
|
570
|
+
watch: watch2,
|
|
571
|
+
mode,
|
|
572
|
+
skipRoutes,
|
|
573
|
+
validateConfig
|
|
574
|
+
}) {
|
|
575
|
+
root = import_pathe3.default.normalize(root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd());
|
|
576
|
+
let vite2 = await import("vite");
|
|
577
|
+
let viteNodeContext = await createContext({
|
|
578
|
+
root,
|
|
579
|
+
mode,
|
|
580
|
+
// Filter out any info level logs from vite-node
|
|
581
|
+
customLogger: vite2.createLogger("warn", {
|
|
582
|
+
prefix: "[react-router]"
|
|
583
|
+
})
|
|
584
|
+
});
|
|
585
|
+
let reactRouterConfigFile;
|
|
586
|
+
let updateReactRouterConfigFile = () => {
|
|
587
|
+
reactRouterConfigFile = findEntry(root, "react-router.config", {
|
|
588
|
+
absolute: true
|
|
589
|
+
});
|
|
590
|
+
};
|
|
591
|
+
updateReactRouterConfigFile();
|
|
592
|
+
let getConfig = () => resolveConfig({
|
|
593
|
+
root,
|
|
594
|
+
viteNodeContext,
|
|
595
|
+
reactRouterConfigFile,
|
|
596
|
+
skipRoutes,
|
|
597
|
+
validateConfig
|
|
598
|
+
});
|
|
599
|
+
let appDirectory;
|
|
600
|
+
let initialConfigResult = await getConfig();
|
|
601
|
+
if (!initialConfigResult.ok) {
|
|
602
|
+
throw new Error(initialConfigResult.error);
|
|
603
|
+
}
|
|
604
|
+
appDirectory = import_pathe3.default.normalize(initialConfigResult.value.appDirectory);
|
|
605
|
+
let currentConfig = initialConfigResult.value;
|
|
606
|
+
let fsWatcher;
|
|
607
|
+
let changeHandlers = [];
|
|
608
|
+
return {
|
|
609
|
+
getConfig,
|
|
610
|
+
onChange: (handler) => {
|
|
611
|
+
if (!watch2) {
|
|
612
|
+
throw new Error(
|
|
613
|
+
"onChange is not supported when watch mode is disabled"
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
changeHandlers.push(handler);
|
|
617
|
+
if (!fsWatcher) {
|
|
618
|
+
fsWatcher = import_chokidar.default.watch([root, appDirectory], {
|
|
619
|
+
ignoreInitial: true,
|
|
620
|
+
ignored: (path7) => {
|
|
621
|
+
let dirname4 = import_pathe3.default.dirname(path7);
|
|
622
|
+
return !dirname4.startsWith(appDirectory) && // Ensure we're only watching files outside of the app directory
|
|
623
|
+
// that are at the root level, not nested in subdirectories
|
|
624
|
+
path7 !== root && // Watch the root directory itself
|
|
625
|
+
dirname4 !== root;
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
fsWatcher.on("all", async (...args) => {
|
|
629
|
+
let [event, rawFilepath] = args;
|
|
630
|
+
let filepath = import_pathe3.default.normalize(rawFilepath);
|
|
631
|
+
let fileAddedOrRemoved = event === "add" || event === "unlink";
|
|
632
|
+
let appFileAddedOrRemoved = fileAddedOrRemoved && filepath.startsWith(import_pathe3.default.normalize(appDirectory));
|
|
633
|
+
let rootRelativeFilepath = import_pathe3.default.relative(root, filepath);
|
|
634
|
+
let configFileAddedOrRemoved = fileAddedOrRemoved && isEntryFile("react-router.config", rootRelativeFilepath);
|
|
635
|
+
if (configFileAddedOrRemoved) {
|
|
636
|
+
updateReactRouterConfigFile();
|
|
637
|
+
}
|
|
638
|
+
let moduleGraphChanged = configFileAddedOrRemoved || Boolean(
|
|
639
|
+
viteNodeContext.devServer?.moduleGraph.getModuleById(filepath)
|
|
640
|
+
);
|
|
641
|
+
if (!moduleGraphChanged && !appFileAddedOrRemoved) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
viteNodeContext.devServer?.moduleGraph.invalidateAll();
|
|
645
|
+
viteNodeContext.runner?.moduleCache.clear();
|
|
646
|
+
let result = await getConfig();
|
|
647
|
+
let prevAppDirectory = appDirectory;
|
|
648
|
+
appDirectory = import_pathe3.default.normalize(
|
|
649
|
+
(result.value ?? currentConfig).appDirectory
|
|
650
|
+
);
|
|
651
|
+
if (appDirectory !== prevAppDirectory) {
|
|
652
|
+
fsWatcher.unwatch(prevAppDirectory);
|
|
653
|
+
fsWatcher.add(appDirectory);
|
|
654
|
+
}
|
|
655
|
+
let configCodeChanged = configFileAddedOrRemoved || reactRouterConfigFile !== void 0 && isEntryFileDependency(
|
|
656
|
+
viteNodeContext.devServer.moduleGraph,
|
|
657
|
+
reactRouterConfigFile,
|
|
658
|
+
filepath
|
|
659
|
+
);
|
|
660
|
+
let routeConfigFile = !skipRoutes ? findEntry(appDirectory, "routes", {
|
|
661
|
+
absolute: true
|
|
662
|
+
}) : void 0;
|
|
663
|
+
let routeConfigCodeChanged = routeConfigFile !== void 0 && isEntryFileDependency(
|
|
664
|
+
viteNodeContext.devServer.moduleGraph,
|
|
665
|
+
routeConfigFile,
|
|
666
|
+
filepath
|
|
667
|
+
);
|
|
668
|
+
let configChanged = result.ok && !(0, import_isEqual.default)(omitRoutes(currentConfig), omitRoutes(result.value));
|
|
669
|
+
let routeConfigChanged = result.ok && !(0, import_isEqual.default)(currentConfig?.routes, result.value.routes);
|
|
670
|
+
for (let handler2 of changeHandlers) {
|
|
671
|
+
handler2({
|
|
672
|
+
result,
|
|
673
|
+
configCodeChanged,
|
|
674
|
+
routeConfigCodeChanged,
|
|
675
|
+
configChanged,
|
|
676
|
+
routeConfigChanged,
|
|
677
|
+
path: filepath,
|
|
678
|
+
event
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
if (result.ok) {
|
|
682
|
+
currentConfig = result.value;
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
return () => {
|
|
687
|
+
changeHandlers = changeHandlers.filter(
|
|
688
|
+
(changeHandler) => changeHandler !== handler
|
|
689
|
+
);
|
|
690
|
+
};
|
|
691
|
+
},
|
|
692
|
+
close: async () => {
|
|
693
|
+
changeHandlers = [];
|
|
694
|
+
await viteNodeContext.devServer.close();
|
|
695
|
+
await fsWatcher?.close();
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
async function resolveEntryFiles({
|
|
700
|
+
rootDirectory,
|
|
701
|
+
reactRouterConfig
|
|
702
|
+
}) {
|
|
703
|
+
let { appDirectory } = reactRouterConfig;
|
|
704
|
+
let defaultsDirectory = import_pathe3.default.resolve(
|
|
705
|
+
import_pathe3.default.dirname(require.resolve("@react-router/dev/package.json")),
|
|
706
|
+
"dist",
|
|
707
|
+
"config",
|
|
708
|
+
"defaults"
|
|
709
|
+
);
|
|
710
|
+
let userEntryClientFile = findEntry(appDirectory, "entry.client");
|
|
711
|
+
let userEntryServerFile = findEntry(appDirectory, "entry.server");
|
|
712
|
+
let entryServerFile;
|
|
713
|
+
let entryClientFile = userEntryClientFile || "entry.client.tsx";
|
|
714
|
+
if (userEntryServerFile) {
|
|
715
|
+
entryServerFile = userEntryServerFile;
|
|
716
|
+
} else {
|
|
717
|
+
let packageJsonPath = findEntry(rootDirectory, "package", {
|
|
718
|
+
extensions: [".json"],
|
|
719
|
+
absolute: true,
|
|
720
|
+
walkParents: true
|
|
721
|
+
});
|
|
722
|
+
if (!packageJsonPath) {
|
|
723
|
+
throw new Error(
|
|
724
|
+
`Could not find package.json in ${rootDirectory} or any of its parent directories. Please add a package.json, or provide a custom entry.server.tsx/jsx file in your app directory.`
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
let packageJsonDirectory = import_pathe3.default.dirname(packageJsonPath);
|
|
728
|
+
let pkgJson = await import_package_json.default.load(packageJsonDirectory);
|
|
729
|
+
let deps = pkgJson.content.dependencies ?? {};
|
|
730
|
+
if (!deps["@react-router/node"]) {
|
|
731
|
+
throw new Error(
|
|
732
|
+
`Could not determine server runtime. Please install @react-router/node, or provide a custom entry.server.tsx/jsx file in your app directory.`
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
if (!deps["isbot"]) {
|
|
736
|
+
console.log(
|
|
737
|
+
"adding `isbot@5` to your package.json, you should commit this change"
|
|
738
|
+
);
|
|
739
|
+
pkgJson.update({
|
|
740
|
+
dependencies: {
|
|
741
|
+
...pkgJson.content.dependencies,
|
|
742
|
+
isbot: "^5"
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
await pkgJson.save();
|
|
746
|
+
let packageManager = detectPackageManager() ?? "npm";
|
|
747
|
+
(0, import_node_child_process.execSync)(`${packageManager} install`, {
|
|
748
|
+
cwd: packageJsonDirectory,
|
|
749
|
+
stdio: "inherit"
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
entryServerFile = `entry.server.node.tsx`;
|
|
753
|
+
}
|
|
754
|
+
let entryClientFilePath = userEntryClientFile ? import_pathe3.default.resolve(reactRouterConfig.appDirectory, userEntryClientFile) : import_pathe3.default.resolve(defaultsDirectory, entryClientFile);
|
|
755
|
+
let entryServerFilePath = userEntryServerFile ? import_pathe3.default.resolve(reactRouterConfig.appDirectory, userEntryServerFile) : import_pathe3.default.resolve(defaultsDirectory, entryServerFile);
|
|
756
|
+
return { entryClientFilePath, entryServerFilePath };
|
|
757
|
+
}
|
|
758
|
+
function omitRoutes(config) {
|
|
759
|
+
return {
|
|
760
|
+
...config,
|
|
761
|
+
routes: {}
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
var entryExts = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".mts"];
|
|
765
|
+
function isEntryFile(entryBasename, filename2) {
|
|
766
|
+
return entryExts.some((ext) => filename2 === `${entryBasename}${ext}`);
|
|
767
|
+
}
|
|
768
|
+
function findEntry(dir, basename3, options) {
|
|
769
|
+
let currentDir = import_pathe3.default.resolve(dir);
|
|
770
|
+
let { root } = import_pathe3.default.parse(currentDir);
|
|
771
|
+
while (true) {
|
|
772
|
+
for (let ext of options?.extensions ?? entryExts) {
|
|
773
|
+
let file = import_pathe3.default.resolve(currentDir, basename3 + ext);
|
|
774
|
+
if (import_node_fs.default.existsSync(file)) {
|
|
775
|
+
return options?.absolute ?? false ? file : import_pathe3.default.relative(dir, file);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
if (!options?.walkParents) {
|
|
779
|
+
return void 0;
|
|
780
|
+
}
|
|
781
|
+
let parentDir = import_pathe3.default.dirname(currentDir);
|
|
782
|
+
if (currentDir === root || parentDir === currentDir) {
|
|
783
|
+
return void 0;
|
|
784
|
+
}
|
|
785
|
+
currentDir = parentDir;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
function isEntryFileDependency(moduleGraph, entryFilepath, filepath, visited = /* @__PURE__ */ new Set()) {
|
|
789
|
+
entryFilepath = import_pathe3.default.normalize(entryFilepath);
|
|
790
|
+
filepath = import_pathe3.default.normalize(filepath);
|
|
791
|
+
if (visited.has(filepath)) {
|
|
792
|
+
return false;
|
|
793
|
+
}
|
|
794
|
+
visited.add(filepath);
|
|
795
|
+
if (filepath === entryFilepath) {
|
|
796
|
+
return true;
|
|
797
|
+
}
|
|
798
|
+
let mod = moduleGraph.getModuleById(filepath);
|
|
799
|
+
if (!mod) {
|
|
800
|
+
return false;
|
|
801
|
+
}
|
|
802
|
+
for (let importer of mod.importers) {
|
|
803
|
+
if (!importer.id) {
|
|
804
|
+
continue;
|
|
805
|
+
}
|
|
806
|
+
if (importer.id === entryFilepath || isEntryFileDependency(moduleGraph, entryFilepath, importer.id, visited)) {
|
|
807
|
+
return true;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
return false;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// typegen/context.ts
|
|
814
|
+
async function createContext2({
|
|
815
|
+
rootDirectory,
|
|
816
|
+
watch: watch2,
|
|
817
|
+
mode
|
|
818
|
+
}) {
|
|
819
|
+
const configLoader = await createConfigLoader({ rootDirectory, mode, watch: watch2 });
|
|
820
|
+
const configResult = await configLoader.getConfig();
|
|
821
|
+
if (!configResult.ok) {
|
|
822
|
+
throw new Error(configResult.error);
|
|
823
|
+
}
|
|
824
|
+
const config = configResult.value;
|
|
825
|
+
return {
|
|
826
|
+
configLoader,
|
|
827
|
+
rootDirectory,
|
|
828
|
+
config
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// typegen/generate.ts
|
|
833
|
+
var import_dedent = __toESM(require("dedent"));
|
|
834
|
+
var Path3 = __toESM(require("pathe"));
|
|
835
|
+
var Pathe = __toESM(require("pathe/utils"));
|
|
836
|
+
|
|
837
|
+
// vite/babel.ts
|
|
838
|
+
var babel_exports = {};
|
|
839
|
+
__export(babel_exports, {
|
|
840
|
+
generate: () => generate,
|
|
841
|
+
parse: () => import_parser.parse,
|
|
842
|
+
t: () => t,
|
|
843
|
+
traverse: () => traverse
|
|
844
|
+
});
|
|
845
|
+
var import_parser = require("@babel/parser");
|
|
846
|
+
var t = __toESM(require("@babel/types"));
|
|
847
|
+
var traverse = require("@babel/traverse").default;
|
|
848
|
+
var generate = require("@babel/generator").default;
|
|
849
|
+
|
|
850
|
+
// typegen/params.ts
|
|
851
|
+
function parse2(fullpath2) {
|
|
852
|
+
const result = {};
|
|
853
|
+
let segments = fullpath2.split("/");
|
|
854
|
+
segments.forEach((segment) => {
|
|
855
|
+
const match = segment.match(/^:([\w-]+)(\?)?/);
|
|
856
|
+
if (!match) return;
|
|
857
|
+
const param = match[1];
|
|
858
|
+
const isRequired = match[2] === void 0;
|
|
859
|
+
result[param] ||= isRequired;
|
|
860
|
+
return;
|
|
861
|
+
});
|
|
862
|
+
const hasSplat = segments.at(-1) === "*";
|
|
863
|
+
if (hasSplat) result["*"] = true;
|
|
864
|
+
return result;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// typegen/route.ts
|
|
868
|
+
function lineage(routes, route) {
|
|
869
|
+
const result = [];
|
|
870
|
+
while (route) {
|
|
871
|
+
result.push(route);
|
|
872
|
+
if (!route.parentId) break;
|
|
873
|
+
route = routes[route.parentId];
|
|
874
|
+
}
|
|
875
|
+
result.reverse();
|
|
876
|
+
return result;
|
|
877
|
+
}
|
|
878
|
+
function fullpath(lineage2) {
|
|
879
|
+
const route = lineage2.at(-1);
|
|
880
|
+
if (lineage2.length === 1 && route?.id === "root") return "/";
|
|
881
|
+
const isLayout = route && route.index !== true && route.path === void 0;
|
|
882
|
+
if (isLayout) return void 0;
|
|
883
|
+
return "/" + lineage2.map((route2) => route2.path?.replace(/^\//, "")?.replace(/\/$/, "")).filter((path7) => path7 !== void 0 && path7 !== "").join("/");
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// typegen/generate.ts
|
|
887
|
+
function typesDirectory(ctx) {
|
|
888
|
+
return Path3.join(ctx.rootDirectory, ".react-router/types");
|
|
889
|
+
}
|
|
890
|
+
function generateFuture(ctx) {
|
|
891
|
+
const filename2 = Path3.join(typesDirectory(ctx), "+future.ts");
|
|
892
|
+
const content = import_dedent.default`
|
|
893
|
+
// Generated by React Router
|
|
894
|
+
|
|
895
|
+
import "react-router";
|
|
896
|
+
|
|
897
|
+
declare module "react-router" {
|
|
898
|
+
interface Future {
|
|
899
|
+
middleware: ${ctx.config.future.v8_middleware}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
`;
|
|
903
|
+
return { filename: filename2, content };
|
|
904
|
+
}
|
|
905
|
+
function generateServerBuild(ctx) {
|
|
906
|
+
const filename2 = Path3.join(typesDirectory(ctx), "+server-build.d.ts");
|
|
907
|
+
const content = import_dedent.default`
|
|
908
|
+
// Generated by React Router
|
|
909
|
+
|
|
910
|
+
declare module "virtual:react-router/server-build" {
|
|
911
|
+
import { ServerBuild } from "react-router";
|
|
912
|
+
export const assets: ServerBuild["assets"];
|
|
913
|
+
export const assetsBuildDirectory: ServerBuild["assetsBuildDirectory"];
|
|
914
|
+
export const basename: ServerBuild["basename"];
|
|
915
|
+
export const entry: ServerBuild["entry"];
|
|
916
|
+
export const future: ServerBuild["future"];
|
|
917
|
+
export const isSpaMode: ServerBuild["isSpaMode"];
|
|
918
|
+
export const prerender: ServerBuild["prerender"];
|
|
919
|
+
export const publicPath: ServerBuild["publicPath"];
|
|
920
|
+
export const routeDiscovery: ServerBuild["routeDiscovery"];
|
|
921
|
+
export const routes: ServerBuild["routes"];
|
|
922
|
+
export const ssr: ServerBuild["ssr"];
|
|
923
|
+
export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"];
|
|
924
|
+
}
|
|
925
|
+
`;
|
|
926
|
+
return { filename: filename2, content };
|
|
927
|
+
}
|
|
928
|
+
var { t: t2 } = babel_exports;
|
|
929
|
+
function generateRoutes(ctx) {
|
|
930
|
+
const fileToRoutes = /* @__PURE__ */ new Map();
|
|
931
|
+
const lineages = /* @__PURE__ */ new Map();
|
|
932
|
+
const allPages = /* @__PURE__ */ new Set();
|
|
933
|
+
const routeToPages = /* @__PURE__ */ new Map();
|
|
934
|
+
for (const route of Object.values(ctx.config.routes)) {
|
|
935
|
+
let routeIds = fileToRoutes.get(route.file);
|
|
936
|
+
if (!routeIds) {
|
|
937
|
+
routeIds = /* @__PURE__ */ new Set();
|
|
938
|
+
fileToRoutes.set(route.file, routeIds);
|
|
939
|
+
}
|
|
940
|
+
routeIds.add(route.id);
|
|
941
|
+
const lineage2 = lineage(ctx.config.routes, route);
|
|
942
|
+
lineages.set(route.id, lineage2);
|
|
943
|
+
const fullpath2 = fullpath(lineage2);
|
|
944
|
+
if (!fullpath2) continue;
|
|
945
|
+
const pages = expand(fullpath2);
|
|
946
|
+
pages.forEach((page) => allPages.add(page));
|
|
947
|
+
lineage2.forEach(({ id }) => {
|
|
948
|
+
let routePages = routeToPages.get(id);
|
|
949
|
+
if (!routePages) {
|
|
950
|
+
routePages = /* @__PURE__ */ new Set();
|
|
951
|
+
routeToPages.set(id, routePages);
|
|
952
|
+
}
|
|
953
|
+
pages.forEach((page) => routePages.add(page));
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
const routesTs = {
|
|
957
|
+
filename: Path3.join(typesDirectory(ctx), "+routes.ts"),
|
|
958
|
+
content: import_dedent.default`
|
|
959
|
+
// Generated by React Router
|
|
960
|
+
|
|
961
|
+
import "react-router"
|
|
962
|
+
|
|
963
|
+
declare module "react-router" {
|
|
964
|
+
interface Register {
|
|
965
|
+
pages: Pages
|
|
966
|
+
routeFiles: RouteFiles
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
` + "\n\n" + generate(pagesType(allPages)).code + "\n\n" + generate(routeFilesType({ fileToRoutes, routeToPages })).code
|
|
970
|
+
};
|
|
971
|
+
const allAnnotations = Array.from(fileToRoutes.entries()).filter(([file]) => isInAppDirectory(ctx, file)).map(
|
|
972
|
+
([file, routeIds]) => getRouteAnnotations({ ctx, file, routeIds, lineages })
|
|
973
|
+
);
|
|
974
|
+
return [routesTs, ...allAnnotations];
|
|
975
|
+
}
|
|
976
|
+
function pagesType(pages) {
|
|
977
|
+
return t2.tsTypeAliasDeclaration(
|
|
978
|
+
t2.identifier("Pages"),
|
|
979
|
+
null,
|
|
980
|
+
t2.tsTypeLiteral(
|
|
981
|
+
Array.from(pages).map((page) => {
|
|
982
|
+
return t2.tsPropertySignature(
|
|
983
|
+
t2.stringLiteral(page),
|
|
984
|
+
t2.tsTypeAnnotation(
|
|
985
|
+
t2.tsTypeLiteral([
|
|
986
|
+
t2.tsPropertySignature(
|
|
987
|
+
t2.identifier("params"),
|
|
988
|
+
t2.tsTypeAnnotation(paramsType(page))
|
|
989
|
+
)
|
|
990
|
+
])
|
|
991
|
+
)
|
|
992
|
+
);
|
|
993
|
+
})
|
|
994
|
+
)
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
function routeFilesType({
|
|
998
|
+
fileToRoutes,
|
|
999
|
+
routeToPages
|
|
1000
|
+
}) {
|
|
1001
|
+
return t2.tsTypeAliasDeclaration(
|
|
1002
|
+
t2.identifier("RouteFiles"),
|
|
1003
|
+
null,
|
|
1004
|
+
t2.tsTypeLiteral(
|
|
1005
|
+
Array.from(fileToRoutes).map(
|
|
1006
|
+
([file, routeIds]) => t2.tsPropertySignature(
|
|
1007
|
+
t2.stringLiteral(file),
|
|
1008
|
+
t2.tsTypeAnnotation(
|
|
1009
|
+
t2.tsUnionType(
|
|
1010
|
+
Array.from(routeIds).map((routeId) => {
|
|
1011
|
+
const pages = routeToPages.get(routeId) ?? /* @__PURE__ */ new Set();
|
|
1012
|
+
return t2.tsTypeLiteral([
|
|
1013
|
+
t2.tsPropertySignature(
|
|
1014
|
+
t2.identifier("id"),
|
|
1015
|
+
t2.tsTypeAnnotation(
|
|
1016
|
+
t2.tsLiteralType(t2.stringLiteral(routeId))
|
|
1017
|
+
)
|
|
1018
|
+
),
|
|
1019
|
+
t2.tsPropertySignature(
|
|
1020
|
+
t2.identifier("page"),
|
|
1021
|
+
t2.tsTypeAnnotation(
|
|
1022
|
+
pages ? t2.tsUnionType(
|
|
1023
|
+
Array.from(pages).map(
|
|
1024
|
+
(page) => t2.tsLiteralType(t2.stringLiteral(page))
|
|
1025
|
+
)
|
|
1026
|
+
) : t2.tsNeverKeyword()
|
|
1027
|
+
)
|
|
1028
|
+
)
|
|
1029
|
+
]);
|
|
1030
|
+
})
|
|
1031
|
+
)
|
|
1032
|
+
)
|
|
1033
|
+
)
|
|
1034
|
+
)
|
|
1035
|
+
)
|
|
1036
|
+
);
|
|
1037
|
+
}
|
|
1038
|
+
function isInAppDirectory(ctx, routeFile) {
|
|
1039
|
+
const path7 = Path3.resolve(ctx.config.appDirectory, routeFile);
|
|
1040
|
+
return path7.startsWith(ctx.config.appDirectory);
|
|
1041
|
+
}
|
|
1042
|
+
function getRouteAnnotations({
|
|
1043
|
+
ctx,
|
|
1044
|
+
file,
|
|
1045
|
+
routeIds,
|
|
1046
|
+
lineages
|
|
1047
|
+
}) {
|
|
1048
|
+
const filename2 = Path3.join(
|
|
1049
|
+
typesDirectory(ctx),
|
|
1050
|
+
Path3.relative(ctx.rootDirectory, ctx.config.appDirectory),
|
|
1051
|
+
Path3.dirname(file),
|
|
1052
|
+
"+types",
|
|
1053
|
+
Pathe.filename(file) + ".ts"
|
|
1054
|
+
);
|
|
1055
|
+
const matchesType = t2.tsTypeAliasDeclaration(
|
|
1056
|
+
t2.identifier("Matches"),
|
|
1057
|
+
null,
|
|
1058
|
+
t2.tsUnionType(
|
|
1059
|
+
Array.from(routeIds).map((routeId) => {
|
|
1060
|
+
const lineage2 = lineages.get(routeId);
|
|
1061
|
+
return t2.tsTupleType(
|
|
1062
|
+
lineage2.map(
|
|
1063
|
+
(route) => t2.tsTypeLiteral([
|
|
1064
|
+
t2.tsPropertySignature(
|
|
1065
|
+
t2.identifier("id"),
|
|
1066
|
+
t2.tsTypeAnnotation(t2.tsLiteralType(t2.stringLiteral(route.id)))
|
|
1067
|
+
),
|
|
1068
|
+
t2.tsPropertySignature(
|
|
1069
|
+
t2.identifier("module"),
|
|
1070
|
+
t2.tsTypeAnnotation(
|
|
1071
|
+
t2.tsTypeQuery(
|
|
1072
|
+
t2.tsImportType(
|
|
1073
|
+
t2.stringLiteral(
|
|
1074
|
+
relativeImportSource(
|
|
1075
|
+
rootDirsPath(ctx, filename2),
|
|
1076
|
+
Path3.resolve(ctx.config.appDirectory, route.file)
|
|
1077
|
+
)
|
|
1078
|
+
)
|
|
1079
|
+
)
|
|
1080
|
+
)
|
|
1081
|
+
)
|
|
1082
|
+
)
|
|
1083
|
+
])
|
|
1084
|
+
)
|
|
1085
|
+
);
|
|
1086
|
+
})
|
|
1087
|
+
)
|
|
1088
|
+
);
|
|
1089
|
+
const routeImportSource = relativeImportSource(
|
|
1090
|
+
rootDirsPath(ctx, filename2),
|
|
1091
|
+
Path3.resolve(ctx.config.appDirectory, file)
|
|
1092
|
+
);
|
|
1093
|
+
const content = import_dedent.default`
|
|
1094
|
+
// Generated by React Router
|
|
1095
|
+
|
|
1096
|
+
import type { GetInfo, GetAnnotations } from "react-router/internal";
|
|
1097
|
+
|
|
1098
|
+
type Module = typeof import("${routeImportSource}")
|
|
1099
|
+
|
|
1100
|
+
type Info = GetInfo<{
|
|
1101
|
+
file: "${file}",
|
|
1102
|
+
module: Module
|
|
1103
|
+
}>
|
|
1104
|
+
` + "\n\n" + generate(matchesType).code + "\n\n" + import_dedent.default`
|
|
1105
|
+
type Annotations = GetAnnotations<Info & { module: Module, matches: Matches }>;
|
|
1106
|
+
|
|
1107
|
+
export namespace Route {
|
|
1108
|
+
// links
|
|
1109
|
+
export type LinkDescriptors = Annotations["LinkDescriptors"];
|
|
1110
|
+
export type LinksFunction = Annotations["LinksFunction"];
|
|
1111
|
+
|
|
1112
|
+
// meta
|
|
1113
|
+
export type MetaArgs = Annotations["MetaArgs"];
|
|
1114
|
+
export type MetaDescriptors = Annotations["MetaDescriptors"];
|
|
1115
|
+
export type MetaFunction = Annotations["MetaFunction"];
|
|
1116
|
+
|
|
1117
|
+
// headers
|
|
1118
|
+
export type HeadersArgs = Annotations["HeadersArgs"];
|
|
1119
|
+
export type HeadersFunction = Annotations["HeadersFunction"];
|
|
1120
|
+
|
|
1121
|
+
// middleware
|
|
1122
|
+
export type MiddlewareFunction = Annotations["MiddlewareFunction"];
|
|
1123
|
+
|
|
1124
|
+
// clientMiddleware
|
|
1125
|
+
export type ClientMiddlewareFunction = Annotations["ClientMiddlewareFunction"];
|
|
1126
|
+
|
|
1127
|
+
// loader
|
|
1128
|
+
export type LoaderArgs = Annotations["LoaderArgs"];
|
|
1129
|
+
|
|
1130
|
+
// clientLoader
|
|
1131
|
+
export type ClientLoaderArgs = Annotations["ClientLoaderArgs"];
|
|
1132
|
+
|
|
1133
|
+
// action
|
|
1134
|
+
export type ActionArgs = Annotations["ActionArgs"];
|
|
1135
|
+
|
|
1136
|
+
// clientAction
|
|
1137
|
+
export type ClientActionArgs = Annotations["ClientActionArgs"];
|
|
1138
|
+
|
|
1139
|
+
// HydrateFallback
|
|
1140
|
+
export type HydrateFallbackProps = Annotations["HydrateFallbackProps"];
|
|
1141
|
+
|
|
1142
|
+
// Component
|
|
1143
|
+
export type ComponentProps = Annotations["ComponentProps"];
|
|
1144
|
+
|
|
1145
|
+
// ErrorBoundary
|
|
1146
|
+
export type ErrorBoundaryProps = Annotations["ErrorBoundaryProps"];
|
|
1147
|
+
}
|
|
1148
|
+
`;
|
|
1149
|
+
return { filename: filename2, content };
|
|
1150
|
+
}
|
|
1151
|
+
function relativeImportSource(from, to) {
|
|
1152
|
+
let path7 = Path3.relative(Path3.dirname(from), to);
|
|
1153
|
+
let extension = Path3.extname(path7);
|
|
1154
|
+
path7 = Path3.join(Path3.dirname(path7), Pathe.filename(path7));
|
|
1155
|
+
if (!path7.startsWith("../")) path7 = "./" + path7;
|
|
1156
|
+
if (!extension || /\.(js|ts)x?$/.test(extension)) {
|
|
1157
|
+
extension = ".js";
|
|
1158
|
+
}
|
|
1159
|
+
return path7 + extension;
|
|
1160
|
+
}
|
|
1161
|
+
function rootDirsPath(ctx, typesPath) {
|
|
1162
|
+
const rel = Path3.relative(typesDirectory(ctx), typesPath);
|
|
1163
|
+
return Path3.join(ctx.rootDirectory, rel);
|
|
1164
|
+
}
|
|
1165
|
+
function paramsType(path7) {
|
|
1166
|
+
const params = parse2(path7);
|
|
1167
|
+
return t2.tsTypeLiteral(
|
|
1168
|
+
Object.entries(params).map(([param, isRequired]) => {
|
|
1169
|
+
const property = t2.tsPropertySignature(
|
|
1170
|
+
t2.stringLiteral(param),
|
|
1171
|
+
t2.tsTypeAnnotation(t2.tsStringKeyword())
|
|
1172
|
+
);
|
|
1173
|
+
property.optional = !isRequired;
|
|
1174
|
+
return property;
|
|
1175
|
+
})
|
|
1176
|
+
);
|
|
1177
|
+
}
|
|
1178
|
+
function expand(fullpath2) {
|
|
1179
|
+
function recurse(segments2, index) {
|
|
1180
|
+
if (index === segments2.length) return [""];
|
|
1181
|
+
const segment = segments2[index];
|
|
1182
|
+
const isOptional = segment.endsWith("?");
|
|
1183
|
+
const isDynamic = segment.startsWith(":");
|
|
1184
|
+
const required = segment.replace(/\?$/, "");
|
|
1185
|
+
const keep = !isOptional || isDynamic;
|
|
1186
|
+
const kept = isDynamic ? segment : required;
|
|
1187
|
+
const withoutSegment = recurse(segments2, index + 1);
|
|
1188
|
+
const withSegment = withoutSegment.map((rest) => [kept, rest].join("/"));
|
|
1189
|
+
if (keep) return withSegment;
|
|
1190
|
+
return [...withoutSegment, ...withSegment];
|
|
1191
|
+
}
|
|
1192
|
+
const segments = fullpath2.split("/");
|
|
1193
|
+
const expanded = /* @__PURE__ */ new Set();
|
|
1194
|
+
for (let result of recurse(segments, 0)) {
|
|
1195
|
+
if (result !== "/") result = result.replace(/\/$/, "");
|
|
1196
|
+
expanded.add(result);
|
|
1197
|
+
}
|
|
1198
|
+
return expanded;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// typegen/index.ts
|
|
1202
|
+
async function clearRouteModuleAnnotations(ctx) {
|
|
1203
|
+
await import_promises.default.rm(
|
|
1204
|
+
Path4.join(typesDirectory(ctx), Path4.basename(ctx.config.appDirectory)),
|
|
1205
|
+
{ recursive: true, force: true }
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1208
|
+
async function write(...files) {
|
|
1209
|
+
return Promise.all(
|
|
1210
|
+
files.map(async ({ filename: filename2, content }) => {
|
|
1211
|
+
await import_promises.default.mkdir(Path4.dirname(filename2), { recursive: true });
|
|
1212
|
+
await import_promises.default.writeFile(filename2, content);
|
|
1213
|
+
})
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1216
|
+
async function watch(rootDirectory, { mode, logger }) {
|
|
1217
|
+
const ctx = await createContext2({ rootDirectory, mode, watch: true });
|
|
1218
|
+
await import_promises.default.rm(typesDirectory(ctx), { recursive: true, force: true });
|
|
1219
|
+
await write(
|
|
1220
|
+
generateFuture(ctx),
|
|
1221
|
+
generateServerBuild(ctx),
|
|
1222
|
+
...generateRoutes(ctx)
|
|
1223
|
+
);
|
|
1224
|
+
logger?.info((0, import_picocolors2.green)("generated types"), { timestamp: true, clear: true });
|
|
1225
|
+
ctx.configLoader.onChange(
|
|
1226
|
+
async ({ result, configChanged, routeConfigChanged }) => {
|
|
1227
|
+
if (!result.ok) {
|
|
1228
|
+
logger?.error((0, import_picocolors2.red)(result.error), { timestamp: true, clear: true });
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
ctx.config = result.value;
|
|
1232
|
+
if (configChanged) {
|
|
1233
|
+
await write(generateFuture(ctx));
|
|
1234
|
+
logger?.info((0, import_picocolors2.green)("regenerated types"), {
|
|
1235
|
+
timestamp: true,
|
|
1236
|
+
clear: true
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
if (routeConfigChanged) {
|
|
1240
|
+
await clearRouteModuleAnnotations(ctx);
|
|
1241
|
+
await write(...generateRoutes(ctx));
|
|
1242
|
+
logger?.info((0, import_picocolors2.green)("regenerated types"), {
|
|
1243
|
+
timestamp: true,
|
|
1244
|
+
clear: true
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
);
|
|
1249
|
+
return {
|
|
1250
|
+
close: async () => await ctx.configLoader.close()
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// vite/node-adapter.ts
|
|
1255
|
+
var import_node_events = require("events");
|
|
1256
|
+
var import_node_tls = require("tls");
|
|
1257
|
+
var import_node_stream = require("stream");
|
|
1258
|
+
var import_set_cookie_parser = require("set-cookie-parser");
|
|
1259
|
+
var import_node = require("@react-router/node");
|
|
1260
|
+
function fromNodeHeaders(nodeReq) {
|
|
1261
|
+
let nodeHeaders = nodeReq.headers;
|
|
1262
|
+
if (nodeReq.httpVersionMajor >= 2) {
|
|
1263
|
+
nodeHeaders = { ...nodeHeaders };
|
|
1264
|
+
if (nodeHeaders[":authority"]) {
|
|
1265
|
+
nodeHeaders.host = nodeHeaders[":authority"];
|
|
1266
|
+
}
|
|
1267
|
+
delete nodeHeaders[":authority"];
|
|
1268
|
+
delete nodeHeaders[":method"];
|
|
1269
|
+
delete nodeHeaders[":path"];
|
|
1270
|
+
delete nodeHeaders[":scheme"];
|
|
1271
|
+
}
|
|
1272
|
+
let headers = new Headers();
|
|
1273
|
+
for (let [key, values] of Object.entries(nodeHeaders)) {
|
|
1274
|
+
if (values) {
|
|
1275
|
+
if (Array.isArray(values)) {
|
|
1276
|
+
for (let value of values) {
|
|
1277
|
+
headers.append(key, value);
|
|
1278
|
+
}
|
|
1279
|
+
} else {
|
|
1280
|
+
headers.set(key, values);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
return headers;
|
|
1285
|
+
}
|
|
1286
|
+
function fromNodeRequest(nodeReq, nodeRes) {
|
|
1287
|
+
let protocol = nodeReq.socket instanceof import_node_tls.TLSSocket && nodeReq.socket.encrypted ? "https" : "http";
|
|
1288
|
+
let origin = nodeReq.headers.origin && "null" !== nodeReq.headers.origin ? nodeReq.headers.origin : `${protocol}://${nodeReq.headers.host}`;
|
|
1289
|
+
invariant(
|
|
1290
|
+
nodeReq.originalUrl,
|
|
1291
|
+
"Expected `nodeReq.originalUrl` to be defined"
|
|
1292
|
+
);
|
|
1293
|
+
let url2 = new URL(nodeReq.originalUrl, origin);
|
|
1294
|
+
let controller = new AbortController();
|
|
1295
|
+
let init = {
|
|
1296
|
+
method: nodeReq.method,
|
|
1297
|
+
headers: fromNodeHeaders(nodeReq),
|
|
1298
|
+
signal: controller.signal
|
|
1299
|
+
};
|
|
1300
|
+
nodeRes.on("finish", () => controller = null);
|
|
1301
|
+
nodeRes.on("close", () => controller?.abort());
|
|
1302
|
+
if (nodeReq.method !== "GET" && nodeReq.method !== "HEAD") {
|
|
1303
|
+
init.body = (0, import_node.createReadableStreamFromReadable)(nodeReq);
|
|
1304
|
+
init.duplex = "half";
|
|
1305
|
+
}
|
|
1306
|
+
return new Request(url2.href, init);
|
|
1307
|
+
}
|
|
1308
|
+
async function toNodeRequest(res, nodeRes) {
|
|
1309
|
+
nodeRes.statusCode = res.status;
|
|
1310
|
+
if (!nodeRes.req || nodeRes.req.httpVersionMajor < 2) {
|
|
1311
|
+
nodeRes.statusMessage = res.statusText;
|
|
1312
|
+
}
|
|
1313
|
+
let cookiesStrings = [];
|
|
1314
|
+
for (let [name, value] of res.headers) {
|
|
1315
|
+
if (name === "set-cookie") {
|
|
1316
|
+
cookiesStrings.push(...(0, import_set_cookie_parser.splitCookiesString)(value));
|
|
1317
|
+
} else nodeRes.setHeader(name, value);
|
|
1318
|
+
}
|
|
1319
|
+
if (cookiesStrings.length) {
|
|
1320
|
+
nodeRes.setHeader("set-cookie", cookiesStrings);
|
|
1321
|
+
}
|
|
1322
|
+
if (res.body) {
|
|
1323
|
+
let responseBody = res.body;
|
|
1324
|
+
let readable = import_node_stream.Readable.from(responseBody);
|
|
1325
|
+
readable.pipe(nodeRes);
|
|
1326
|
+
await (0, import_node_events.once)(readable, "end");
|
|
1327
|
+
} else {
|
|
1328
|
+
nodeRes.end();
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
// vite/styles.ts
|
|
1333
|
+
var path4 = __toESM(require("path"));
|
|
1334
|
+
var import_react_router = require("react-router");
|
|
1335
|
+
|
|
1336
|
+
// vite/resolve-file-url.ts
|
|
1337
|
+
var path3 = __toESM(require("path"));
|
|
1338
|
+
var resolveFileUrl = ({ rootDirectory }, filePath) => {
|
|
1339
|
+
let vite2 = getVite();
|
|
1340
|
+
let relativePath = path3.relative(rootDirectory, filePath);
|
|
1341
|
+
let isWithinRoot = !relativePath.startsWith("..") && !path3.isAbsolute(relativePath);
|
|
1342
|
+
if (!isWithinRoot) {
|
|
1343
|
+
return path3.posix.join("/@fs", vite2.normalizePath(filePath));
|
|
1344
|
+
}
|
|
1345
|
+
return "/" + vite2.normalizePath(relativePath);
|
|
1346
|
+
};
|
|
1347
|
+
|
|
1348
|
+
// vite/styles.ts
|
|
1349
|
+
var cssFileRegExp = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/;
|
|
1350
|
+
var cssModulesRegExp = new RegExp(`\\.module${cssFileRegExp.source}`);
|
|
1351
|
+
var isCssFile = (file) => cssFileRegExp.test(file);
|
|
1352
|
+
var isCssModulesFile = (file) => cssModulesRegExp.test(file);
|
|
1353
|
+
var cssUrlParamsWithoutSideEffects = ["url", "inline", "raw", "inline-css"];
|
|
1354
|
+
var isCssUrlWithoutSideEffects = (url2) => {
|
|
1355
|
+
let queryString = url2.split("?")[1];
|
|
1356
|
+
if (!queryString) {
|
|
1357
|
+
return false;
|
|
1358
|
+
}
|
|
1359
|
+
let params = new URLSearchParams(queryString);
|
|
1360
|
+
for (let paramWithoutSideEffects of cssUrlParamsWithoutSideEffects) {
|
|
1361
|
+
if (
|
|
1362
|
+
// Parameter is blank and not explicitly set, i.e. "?url", not "?url="
|
|
1363
|
+
params.get(paramWithoutSideEffects) === "" && !url2.includes(`?${paramWithoutSideEffects}=`) && !url2.includes(`&${paramWithoutSideEffects}=`)
|
|
1364
|
+
) {
|
|
1365
|
+
return true;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
return false;
|
|
1369
|
+
};
|
|
1370
|
+
var getStylesForFiles = async ({
|
|
1371
|
+
viteDevServer,
|
|
1372
|
+
rootDirectory,
|
|
1373
|
+
loadCssContents,
|
|
1374
|
+
files
|
|
1375
|
+
}) => {
|
|
1376
|
+
let styles = {};
|
|
1377
|
+
let deps = /* @__PURE__ */ new Set();
|
|
1378
|
+
try {
|
|
1379
|
+
for (let file of files) {
|
|
1380
|
+
let normalizedPath = path4.resolve(rootDirectory, file).replace(/\\/g, "/");
|
|
1381
|
+
let node = await viteDevServer.moduleGraph.getModuleById(normalizedPath);
|
|
1382
|
+
if (!node) {
|
|
1383
|
+
try {
|
|
1384
|
+
await viteDevServer.transformRequest(
|
|
1385
|
+
resolveFileUrl({ rootDirectory }, normalizedPath)
|
|
1386
|
+
);
|
|
1387
|
+
} catch (err2) {
|
|
1388
|
+
console.error(err2);
|
|
1389
|
+
}
|
|
1390
|
+
node = await viteDevServer.moduleGraph.getModuleById(normalizedPath);
|
|
1391
|
+
}
|
|
1392
|
+
if (!node) {
|
|
1393
|
+
console.log(`Could not resolve module for file: ${file}`);
|
|
1394
|
+
continue;
|
|
1395
|
+
}
|
|
1396
|
+
await findDeps(viteDevServer, node, deps);
|
|
1397
|
+
}
|
|
1398
|
+
} catch (err2) {
|
|
1399
|
+
console.error(err2);
|
|
1400
|
+
}
|
|
1401
|
+
for (let dep of deps) {
|
|
1402
|
+
if (dep.file && isCssFile(dep.file) && !isCssUrlWithoutSideEffects(dep.url)) {
|
|
1403
|
+
try {
|
|
1404
|
+
styles[dep.url] = await loadCssContents(viteDevServer, dep);
|
|
1405
|
+
} catch {
|
|
1406
|
+
console.warn(`Failed to load CSS for ${dep.file}`);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
return Object.entries(styles).map(([fileName, css], i) => [
|
|
1411
|
+
`
|
|
1412
|
+
/* ${fileName.replace(/\/\*/g, "/\\*").replace(/\*\//g, "*\\/")} */`,
|
|
1413
|
+
css
|
|
1414
|
+
]).flat().join("\n") || void 0;
|
|
1415
|
+
};
|
|
1416
|
+
var findDeps = async (vite2, node, deps) => {
|
|
1417
|
+
let branches = [];
|
|
1418
|
+
async function addFromNode(node2) {
|
|
1419
|
+
if (!deps.has(node2)) {
|
|
1420
|
+
deps.add(node2);
|
|
1421
|
+
await findDeps(vite2, node2, deps);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
async function addFromUrl(url2) {
|
|
1425
|
+
let node2 = await vite2.moduleGraph.getModuleByUrl(url2);
|
|
1426
|
+
if (node2) {
|
|
1427
|
+
await addFromNode(node2);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
if (node.ssrTransformResult) {
|
|
1431
|
+
if (node.ssrTransformResult.deps) {
|
|
1432
|
+
node.ssrTransformResult.deps.forEach(
|
|
1433
|
+
(url2) => branches.push(addFromUrl(url2))
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
} else {
|
|
1437
|
+
node.importedModules.forEach((node2) => branches.push(addFromNode(node2)));
|
|
1438
|
+
}
|
|
1439
|
+
await Promise.all(branches);
|
|
1440
|
+
};
|
|
1441
|
+
var groupRoutesByParentId = (manifest) => {
|
|
1442
|
+
let routes = {};
|
|
1443
|
+
Object.values(manifest).forEach((route) => {
|
|
1444
|
+
if (route) {
|
|
1445
|
+
let parentId = route.parentId || "";
|
|
1446
|
+
if (!routes[parentId]) {
|
|
1447
|
+
routes[parentId] = [];
|
|
1448
|
+
}
|
|
1449
|
+
routes[parentId].push(route);
|
|
1450
|
+
}
|
|
1451
|
+
});
|
|
1452
|
+
return routes;
|
|
1453
|
+
};
|
|
1454
|
+
var createRoutesWithChildren = (manifest, parentId = "", routesByParentId = groupRoutesByParentId(manifest)) => {
|
|
1455
|
+
return (routesByParentId[parentId] || []).map((route) => ({
|
|
1456
|
+
...route,
|
|
1457
|
+
...route.index ? {
|
|
1458
|
+
index: true
|
|
1459
|
+
} : {
|
|
1460
|
+
index: false,
|
|
1461
|
+
children: createRoutesWithChildren(
|
|
1462
|
+
manifest,
|
|
1463
|
+
route.id,
|
|
1464
|
+
routesByParentId
|
|
1465
|
+
)
|
|
1466
|
+
}
|
|
1467
|
+
}));
|
|
1468
|
+
};
|
|
1469
|
+
var getStylesForPathname = async ({
|
|
1470
|
+
viteDevServer,
|
|
1471
|
+
rootDirectory,
|
|
1472
|
+
reactRouterConfig,
|
|
1473
|
+
entryClientFilePath,
|
|
1474
|
+
loadCssContents,
|
|
1475
|
+
pathname
|
|
1476
|
+
}) => {
|
|
1477
|
+
if (pathname === void 0 || pathname.includes("?_data=")) {
|
|
1478
|
+
return void 0;
|
|
1479
|
+
}
|
|
1480
|
+
let routesWithChildren = createRoutesWithChildren(reactRouterConfig.routes);
|
|
1481
|
+
let appPath = path4.relative(process.cwd(), reactRouterConfig.appDirectory);
|
|
1482
|
+
let documentRouteFiles = (0, import_react_router.matchRoutes)(routesWithChildren, pathname, reactRouterConfig.basename)?.map(
|
|
1483
|
+
(match) => path4.resolve(appPath, reactRouterConfig.routes[match.route.id].file)
|
|
1484
|
+
) ?? [];
|
|
1485
|
+
let styles = await getStylesForFiles({
|
|
1486
|
+
viteDevServer,
|
|
1487
|
+
rootDirectory,
|
|
1488
|
+
loadCssContents,
|
|
1489
|
+
files: [
|
|
1490
|
+
// Always include the client entry file when crawling the module graph for CSS
|
|
1491
|
+
path4.relative(rootDirectory, entryClientFilePath),
|
|
1492
|
+
// Then include any styles from the matched routes
|
|
1493
|
+
...documentRouteFiles
|
|
1494
|
+
]
|
|
1495
|
+
});
|
|
1496
|
+
return styles;
|
|
1497
|
+
};
|
|
1498
|
+
var getCssStringFromViteDevModuleCode = (code) => {
|
|
1499
|
+
let cssContent = void 0;
|
|
1500
|
+
const ast = import_parser.parse(code, { sourceType: "module" });
|
|
1501
|
+
traverse(ast, {
|
|
1502
|
+
VariableDeclaration(path7) {
|
|
1503
|
+
const declaration = path7.node.declarations[0];
|
|
1504
|
+
if (declaration?.id?.type === "Identifier" && declaration.id.name === "__vite__css" && declaration.init?.type === "StringLiteral") {
|
|
1505
|
+
cssContent = declaration.init.value;
|
|
1506
|
+
path7.stop();
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
return cssContent;
|
|
1511
|
+
};
|
|
1512
|
+
|
|
1513
|
+
// vite/virtual-module.ts
|
|
1514
|
+
function create(name) {
|
|
1515
|
+
let id = `virtual:react-router/${name}`;
|
|
1516
|
+
return {
|
|
1517
|
+
id,
|
|
1518
|
+
resolvedId: `\0${id}`,
|
|
1519
|
+
url: `/@id/__x00__${id}`
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
// vite/resolve-relative-route-file-path.ts
|
|
1524
|
+
var import_pathe4 = __toESM(require("pathe"));
|
|
1525
|
+
function resolveRelativeRouteFilePath(route, reactRouterConfig) {
|
|
1526
|
+
let vite2 = getVite();
|
|
1527
|
+
let file = route.file;
|
|
1528
|
+
let fullPath = import_pathe4.default.resolve(reactRouterConfig.appDirectory, file);
|
|
1529
|
+
return vite2.normalizePath(fullPath);
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
// vite/combine-urls.ts
|
|
1533
|
+
function combineURLs(baseURL, relativeURL) {
|
|
1534
|
+
return relativeURL ? baseURL.replace(/\/+$/, "") + "/" + relativeURL.replace(/^\/+/, "") : baseURL;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
// vite/remove-exports.ts
|
|
1538
|
+
var import_babel_dead_code_elimination = require("babel-dead-code-elimination");
|
|
1539
|
+
var removeExports = (ast, exportsToRemove) => {
|
|
1540
|
+
let previouslyReferencedIdentifiers = (0, import_babel_dead_code_elimination.findReferencedIdentifiers)(ast);
|
|
1541
|
+
let exportsFiltered = false;
|
|
1542
|
+
let markedForRemoval = /* @__PURE__ */ new Set();
|
|
1543
|
+
let removedExportLocalNames = /* @__PURE__ */ new Set();
|
|
1544
|
+
traverse(ast, {
|
|
1545
|
+
ExportDeclaration(path7) {
|
|
1546
|
+
if (path7.node.type === "ExportNamedDeclaration") {
|
|
1547
|
+
if (path7.node.specifiers.length) {
|
|
1548
|
+
path7.node.specifiers = path7.node.specifiers.filter((specifier) => {
|
|
1549
|
+
if (specifier.type === "ExportSpecifier" && specifier.exported.type === "Identifier") {
|
|
1550
|
+
if (exportsToRemove.includes(specifier.exported.name)) {
|
|
1551
|
+
exportsFiltered = true;
|
|
1552
|
+
if (specifier.local && specifier.local.name !== specifier.exported.name) {
|
|
1553
|
+
removedExportLocalNames.add(specifier.local.name);
|
|
1554
|
+
}
|
|
1555
|
+
return false;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
return true;
|
|
1559
|
+
});
|
|
1560
|
+
if (path7.node.specifiers.length === 0) {
|
|
1561
|
+
markedForRemoval.add(path7);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
if (path7.node.declaration?.type === "VariableDeclaration") {
|
|
1565
|
+
let declaration = path7.node.declaration;
|
|
1566
|
+
declaration.declarations = declaration.declarations.filter(
|
|
1567
|
+
(declaration2) => {
|
|
1568
|
+
if (declaration2.id.type === "Identifier" && exportsToRemove.includes(declaration2.id.name)) {
|
|
1569
|
+
exportsFiltered = true;
|
|
1570
|
+
return false;
|
|
1571
|
+
}
|
|
1572
|
+
if (declaration2.id.type === "ArrayPattern" || declaration2.id.type === "ObjectPattern") {
|
|
1573
|
+
validateDestructuredExports(declaration2.id, exportsToRemove);
|
|
1574
|
+
}
|
|
1575
|
+
return true;
|
|
1576
|
+
}
|
|
1577
|
+
);
|
|
1578
|
+
if (declaration.declarations.length === 0) {
|
|
1579
|
+
markedForRemoval.add(path7);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
if (path7.node.declaration?.type === "FunctionDeclaration") {
|
|
1583
|
+
let id = path7.node.declaration.id;
|
|
1584
|
+
if (id && exportsToRemove.includes(id.name)) {
|
|
1585
|
+
markedForRemoval.add(path7);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
if (path7.node.declaration?.type === "ClassDeclaration") {
|
|
1589
|
+
let id = path7.node.declaration.id;
|
|
1590
|
+
if (id && exportsToRemove.includes(id.name)) {
|
|
1591
|
+
markedForRemoval.add(path7);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
if (path7.node.type === "ExportDefaultDeclaration") {
|
|
1596
|
+
if (exportsToRemove.includes("default")) {
|
|
1597
|
+
markedForRemoval.add(path7);
|
|
1598
|
+
if (path7.node.declaration) {
|
|
1599
|
+
if (path7.node.declaration.type === "Identifier") {
|
|
1600
|
+
removedExportLocalNames.add(path7.node.declaration.name);
|
|
1601
|
+
} else if ((path7.node.declaration.type === "FunctionDeclaration" || path7.node.declaration.type === "ClassDeclaration") && path7.node.declaration.id) {
|
|
1602
|
+
removedExportLocalNames.add(path7.node.declaration.id.name);
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
});
|
|
1609
|
+
traverse(ast, {
|
|
1610
|
+
ExpressionStatement(path7) {
|
|
1611
|
+
if (!path7.parentPath.isProgram()) {
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
if (path7.node.expression.type === "AssignmentExpression") {
|
|
1615
|
+
const left = path7.node.expression.left;
|
|
1616
|
+
if (left.type === "MemberExpression" && left.object.type === "Identifier" && (exportsToRemove.includes(left.object.name) || removedExportLocalNames.has(left.object.name))) {
|
|
1617
|
+
markedForRemoval.add(path7);
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
});
|
|
1622
|
+
if (markedForRemoval.size > 0 || exportsFiltered) {
|
|
1623
|
+
for (let path7 of markedForRemoval) {
|
|
1624
|
+
path7.remove();
|
|
1625
|
+
}
|
|
1626
|
+
(0, import_babel_dead_code_elimination.deadCodeElimination)(ast, previouslyReferencedIdentifiers);
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
function validateDestructuredExports(id, exportsToRemove) {
|
|
1630
|
+
if (id.type === "ArrayPattern") {
|
|
1631
|
+
for (let element of id.elements) {
|
|
1632
|
+
if (!element) {
|
|
1633
|
+
continue;
|
|
1634
|
+
}
|
|
1635
|
+
if (element.type === "Identifier" && exportsToRemove.includes(element.name)) {
|
|
1636
|
+
throw invalidDestructureError(element.name);
|
|
1637
|
+
}
|
|
1638
|
+
if (element.type === "RestElement" && element.argument.type === "Identifier" && exportsToRemove.includes(element.argument.name)) {
|
|
1639
|
+
throw invalidDestructureError(element.argument.name);
|
|
1640
|
+
}
|
|
1641
|
+
if (element.type === "ArrayPattern" || element.type === "ObjectPattern") {
|
|
1642
|
+
validateDestructuredExports(element, exportsToRemove);
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
if (id.type === "ObjectPattern") {
|
|
1647
|
+
for (let property of id.properties) {
|
|
1648
|
+
if (!property) {
|
|
1649
|
+
continue;
|
|
1650
|
+
}
|
|
1651
|
+
if (property.type === "ObjectProperty" && property.key.type === "Identifier") {
|
|
1652
|
+
if (property.value.type === "Identifier" && exportsToRemove.includes(property.value.name)) {
|
|
1653
|
+
throw invalidDestructureError(property.value.name);
|
|
1654
|
+
}
|
|
1655
|
+
if (property.value.type === "ArrayPattern" || property.value.type === "ObjectPattern") {
|
|
1656
|
+
validateDestructuredExports(property.value, exportsToRemove);
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
if (property.type === "RestElement" && property.argument.type === "Identifier" && exportsToRemove.includes(property.argument.name)) {
|
|
1660
|
+
throw invalidDestructureError(property.argument.name);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
function invalidDestructureError(name) {
|
|
1666
|
+
return new Error(`Cannot remove destructured export "${name}"`);
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
// vite/has-dependency.ts
|
|
1670
|
+
function hasDependency({
|
|
1671
|
+
name,
|
|
1672
|
+
rootDirectory
|
|
1673
|
+
}) {
|
|
1674
|
+
try {
|
|
1675
|
+
return Boolean(require.resolve(name, { paths: [rootDirectory] }));
|
|
1676
|
+
} catch (err2) {
|
|
1677
|
+
return false;
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
// vite/cache.ts
|
|
1682
|
+
function getOrSetFromCache(cache, key, version, getValue) {
|
|
1683
|
+
if (!cache) {
|
|
1684
|
+
return getValue();
|
|
1685
|
+
}
|
|
1686
|
+
let entry = cache.get(key);
|
|
1687
|
+
if (entry?.version === version) {
|
|
1688
|
+
return entry.value;
|
|
1689
|
+
}
|
|
1690
|
+
let value = getValue();
|
|
1691
|
+
let newEntry = { value, version };
|
|
1692
|
+
cache.set(key, newEntry);
|
|
1693
|
+
return value;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
// vite/route-chunks.ts
|
|
1697
|
+
function codeToAst(code, cache, cacheKey) {
|
|
1698
|
+
return structuredClone(
|
|
1699
|
+
getOrSetFromCache(
|
|
1700
|
+
cache,
|
|
1701
|
+
`${cacheKey}::codeToAst`,
|
|
1702
|
+
code,
|
|
1703
|
+
() => (0, import_parser.parse)(code, { sourceType: "module" })
|
|
1704
|
+
)
|
|
1705
|
+
);
|
|
1706
|
+
}
|
|
1707
|
+
function assertNodePath(path7) {
|
|
1708
|
+
invariant(
|
|
1709
|
+
path7 && !Array.isArray(path7),
|
|
1710
|
+
`Expected a Path, but got ${Array.isArray(path7) ? "an array" : path7}`
|
|
1711
|
+
);
|
|
1712
|
+
}
|
|
1713
|
+
function assertNodePathIsStatement(path7) {
|
|
1714
|
+
invariant(
|
|
1715
|
+
path7 && !Array.isArray(path7) && t.isStatement(path7.node),
|
|
1716
|
+
`Expected a Statement path, but got ${Array.isArray(path7) ? "an array" : path7?.node?.type}`
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
function assertNodePathIsVariableDeclarator(path7) {
|
|
1720
|
+
invariant(
|
|
1721
|
+
path7 && !Array.isArray(path7) && t.isVariableDeclarator(path7.node),
|
|
1722
|
+
`Expected an Identifier path, but got ${Array.isArray(path7) ? "an array" : path7?.node?.type}`
|
|
1723
|
+
);
|
|
1724
|
+
}
|
|
1725
|
+
function assertNodePathIsPattern(path7) {
|
|
1726
|
+
invariant(
|
|
1727
|
+
path7 && !Array.isArray(path7) && t.isPattern(path7.node),
|
|
1728
|
+
`Expected a Pattern path, but got ${Array.isArray(path7) ? "an array" : path7?.node?.type}`
|
|
1729
|
+
);
|
|
1730
|
+
}
|
|
1731
|
+
function getExportDependencies(code, cache, cacheKey) {
|
|
1732
|
+
return getOrSetFromCache(
|
|
1733
|
+
cache,
|
|
1734
|
+
`${cacheKey}::getExportDependencies`,
|
|
1735
|
+
code,
|
|
1736
|
+
() => {
|
|
1737
|
+
let exportDependencies = /* @__PURE__ */ new Map();
|
|
1738
|
+
let ast = codeToAst(code, cache, cacheKey);
|
|
1739
|
+
function handleExport(exportName, exportPath, identifiersPath = exportPath) {
|
|
1740
|
+
let identifiers = getDependentIdentifiersForPath(identifiersPath);
|
|
1741
|
+
let topLevelStatements = /* @__PURE__ */ new Set([
|
|
1742
|
+
exportPath.node,
|
|
1743
|
+
...getTopLevelStatementsForPaths(identifiers)
|
|
1744
|
+
]);
|
|
1745
|
+
let topLevelNonModuleStatements = new Set(
|
|
1746
|
+
Array.from(topLevelStatements).filter(
|
|
1747
|
+
(statement) => !t.isImportDeclaration(statement) && !t.isExportDeclaration(statement)
|
|
1748
|
+
)
|
|
1749
|
+
);
|
|
1750
|
+
let importedIdentifierNames = /* @__PURE__ */ new Set();
|
|
1751
|
+
for (let identifier of identifiers) {
|
|
1752
|
+
if (identifier.parentPath.parentPath?.isImportDeclaration()) {
|
|
1753
|
+
importedIdentifierNames.add(identifier.node.name);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
let exportedVariableDeclarators = /* @__PURE__ */ new Set();
|
|
1757
|
+
for (let identifier of identifiers) {
|
|
1758
|
+
if (identifier.parentPath.isVariableDeclarator() && identifier.parentPath.parentPath.parentPath?.isExportNamedDeclaration()) {
|
|
1759
|
+
exportedVariableDeclarators.add(identifier.parentPath.node);
|
|
1760
|
+
continue;
|
|
1761
|
+
}
|
|
1762
|
+
let isWithinExportDestructuring = Boolean(
|
|
1763
|
+
identifier.findParent(
|
|
1764
|
+
(path7) => Boolean(
|
|
1765
|
+
path7.isPattern() && path7.parentPath?.isVariableDeclarator() && path7.parentPath.parentPath?.parentPath?.isExportNamedDeclaration()
|
|
1766
|
+
)
|
|
1767
|
+
)
|
|
1768
|
+
);
|
|
1769
|
+
if (isWithinExportDestructuring) {
|
|
1770
|
+
let currentPath = identifier;
|
|
1771
|
+
while (currentPath) {
|
|
1772
|
+
if (
|
|
1773
|
+
// Check the identifier is within a variable declaration, and if
|
|
1774
|
+
// so, ensure we're on the left-hand side of the expression
|
|
1775
|
+
// since these identifiers are what make up the export names,
|
|
1776
|
+
// e.g. export const { foo } = { foo: bar }; should pick up
|
|
1777
|
+
// `foo` but not `bar`.
|
|
1778
|
+
currentPath.parentPath?.isVariableDeclarator() && currentPath.parentKey === "id"
|
|
1779
|
+
) {
|
|
1780
|
+
exportedVariableDeclarators.add(currentPath.parentPath.node);
|
|
1781
|
+
break;
|
|
1782
|
+
}
|
|
1783
|
+
currentPath = currentPath.parentPath;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
let dependencies = {
|
|
1788
|
+
topLevelStatements,
|
|
1789
|
+
topLevelNonModuleStatements,
|
|
1790
|
+
importedIdentifierNames,
|
|
1791
|
+
exportedVariableDeclarators
|
|
1792
|
+
};
|
|
1793
|
+
exportDependencies.set(exportName, dependencies);
|
|
1794
|
+
}
|
|
1795
|
+
traverse(ast, {
|
|
1796
|
+
ExportDeclaration(exportPath) {
|
|
1797
|
+
let { node } = exportPath;
|
|
1798
|
+
if (t.isExportAllDeclaration(node)) {
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
if (t.isExportDefaultDeclaration(node)) {
|
|
1802
|
+
handleExport("default", exportPath);
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
let { declaration } = node;
|
|
1806
|
+
if (t.isVariableDeclaration(declaration)) {
|
|
1807
|
+
let { declarations } = declaration;
|
|
1808
|
+
for (let i = 0; i < declarations.length; i++) {
|
|
1809
|
+
let declarator = declarations[i];
|
|
1810
|
+
if (t.isIdentifier(declarator.id)) {
|
|
1811
|
+
let declaratorPath = exportPath.get(
|
|
1812
|
+
`declaration.declarations.${i}`
|
|
1813
|
+
);
|
|
1814
|
+
assertNodePathIsVariableDeclarator(declaratorPath);
|
|
1815
|
+
handleExport(declarator.id.name, exportPath, declaratorPath);
|
|
1816
|
+
continue;
|
|
1817
|
+
}
|
|
1818
|
+
if (t.isPattern(declarator.id)) {
|
|
1819
|
+
let exportedPatternPath = exportPath.get(
|
|
1820
|
+
`declaration.declarations.${i}.id`
|
|
1821
|
+
);
|
|
1822
|
+
assertNodePathIsPattern(exportedPatternPath);
|
|
1823
|
+
let identifiers = getIdentifiersForPatternPath(exportedPatternPath);
|
|
1824
|
+
for (let identifier of identifiers) {
|
|
1825
|
+
handleExport(identifier.node.name, exportPath, identifier);
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
if (t.isFunctionDeclaration(declaration) || t.isClassDeclaration(declaration)) {
|
|
1832
|
+
invariant(
|
|
1833
|
+
declaration.id,
|
|
1834
|
+
"Expected exported function or class declaration to have a name when not the default export"
|
|
1835
|
+
);
|
|
1836
|
+
handleExport(declaration.id.name, exportPath);
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
if (t.isExportNamedDeclaration(node)) {
|
|
1840
|
+
for (let specifier of node.specifiers) {
|
|
1841
|
+
if (t.isIdentifier(specifier.exported)) {
|
|
1842
|
+
let name = specifier.exported.name;
|
|
1843
|
+
let specifierPath = exportPath.get("specifiers").find((path7) => path7.node === specifier);
|
|
1844
|
+
invariant(
|
|
1845
|
+
specifierPath,
|
|
1846
|
+
`Expected to find specifier path for ${name}`
|
|
1847
|
+
);
|
|
1848
|
+
handleExport(name, exportPath, specifierPath);
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
throw new Error(`Unknown export node type: ${node.type}`);
|
|
1854
|
+
}
|
|
1855
|
+
});
|
|
1856
|
+
return exportDependencies;
|
|
1857
|
+
}
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
function getDependentIdentifiersForPath(path7, state) {
|
|
1861
|
+
let { visited, identifiers } = state ?? {
|
|
1862
|
+
visited: /* @__PURE__ */ new Set(),
|
|
1863
|
+
identifiers: /* @__PURE__ */ new Set()
|
|
1864
|
+
};
|
|
1865
|
+
if (visited.has(path7)) {
|
|
1866
|
+
return identifiers;
|
|
1867
|
+
}
|
|
1868
|
+
visited.add(path7);
|
|
1869
|
+
path7.traverse({
|
|
1870
|
+
Identifier(path8) {
|
|
1871
|
+
if (identifiers.has(path8)) {
|
|
1872
|
+
return;
|
|
1873
|
+
}
|
|
1874
|
+
identifiers.add(path8);
|
|
1875
|
+
let binding = path8.scope.getBinding(path8.node.name);
|
|
1876
|
+
if (!binding) {
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
getDependentIdentifiersForPath(binding.path, { visited, identifiers });
|
|
1880
|
+
for (let reference of binding.referencePaths) {
|
|
1881
|
+
if (reference.isExportNamedDeclaration()) {
|
|
1882
|
+
continue;
|
|
1883
|
+
}
|
|
1884
|
+
getDependentIdentifiersForPath(reference, {
|
|
1885
|
+
visited,
|
|
1886
|
+
identifiers
|
|
1887
|
+
});
|
|
1888
|
+
}
|
|
1889
|
+
for (let constantViolation of binding.constantViolations) {
|
|
1890
|
+
getDependentIdentifiersForPath(constantViolation, {
|
|
1891
|
+
visited,
|
|
1892
|
+
identifiers
|
|
1893
|
+
});
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
});
|
|
1897
|
+
let topLevelStatement = getTopLevelStatementPathForPath(path7);
|
|
1898
|
+
let withinImportStatement = topLevelStatement.isImportDeclaration();
|
|
1899
|
+
let withinExportStatement = topLevelStatement.isExportDeclaration();
|
|
1900
|
+
if (!withinImportStatement && !withinExportStatement) {
|
|
1901
|
+
getDependentIdentifiersForPath(topLevelStatement, {
|
|
1902
|
+
visited,
|
|
1903
|
+
identifiers
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
if (withinExportStatement && path7.isIdentifier() && (t.isPattern(path7.parentPath.node) || // [foo]
|
|
1907
|
+
t.isPattern(path7.parentPath.parentPath?.node))) {
|
|
1908
|
+
let variableDeclarator = path7.findParent((p) => p.isVariableDeclarator());
|
|
1909
|
+
assertNodePath(variableDeclarator);
|
|
1910
|
+
getDependentIdentifiersForPath(variableDeclarator, {
|
|
1911
|
+
visited,
|
|
1912
|
+
identifiers
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
return identifiers;
|
|
1916
|
+
}
|
|
1917
|
+
function getTopLevelStatementPathForPath(path7) {
|
|
1918
|
+
let ancestry = path7.getAncestry();
|
|
1919
|
+
let topLevelStatement = ancestry[ancestry.length - 2];
|
|
1920
|
+
assertNodePathIsStatement(topLevelStatement);
|
|
1921
|
+
return topLevelStatement;
|
|
1922
|
+
}
|
|
1923
|
+
function getTopLevelStatementsForPaths(paths) {
|
|
1924
|
+
let topLevelStatements = /* @__PURE__ */ new Set();
|
|
1925
|
+
for (let path7 of paths) {
|
|
1926
|
+
let topLevelStatement = getTopLevelStatementPathForPath(path7);
|
|
1927
|
+
topLevelStatements.add(topLevelStatement.node);
|
|
1928
|
+
}
|
|
1929
|
+
return topLevelStatements;
|
|
1930
|
+
}
|
|
1931
|
+
function getIdentifiersForPatternPath(patternPath, identifiers = /* @__PURE__ */ new Set()) {
|
|
1932
|
+
function walk(currentPath) {
|
|
1933
|
+
if (currentPath.isIdentifier()) {
|
|
1934
|
+
identifiers.add(currentPath);
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
if (currentPath.isObjectPattern()) {
|
|
1938
|
+
let { properties } = currentPath.node;
|
|
1939
|
+
for (let i = 0; i < properties.length; i++) {
|
|
1940
|
+
const property = properties[i];
|
|
1941
|
+
if (t.isObjectProperty(property)) {
|
|
1942
|
+
let valuePath = currentPath.get(`properties.${i}.value`);
|
|
1943
|
+
assertNodePath(valuePath);
|
|
1944
|
+
walk(valuePath);
|
|
1945
|
+
} else if (t.isRestElement(property)) {
|
|
1946
|
+
let argumentPath = currentPath.get(`properties.${i}.argument`);
|
|
1947
|
+
assertNodePath(argumentPath);
|
|
1948
|
+
walk(argumentPath);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
} else if (currentPath.isArrayPattern()) {
|
|
1952
|
+
let { elements } = currentPath.node;
|
|
1953
|
+
for (let i = 0; i < elements.length; i++) {
|
|
1954
|
+
const element = elements[i];
|
|
1955
|
+
if (element) {
|
|
1956
|
+
let elementPath = currentPath.get(`elements.${i}`);
|
|
1957
|
+
assertNodePath(elementPath);
|
|
1958
|
+
walk(elementPath);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
} else if (currentPath.isRestElement()) {
|
|
1962
|
+
let argumentPath = currentPath.get("argument");
|
|
1963
|
+
assertNodePath(argumentPath);
|
|
1964
|
+
walk(argumentPath);
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
walk(patternPath);
|
|
1968
|
+
return identifiers;
|
|
1969
|
+
}
|
|
1970
|
+
var getExportedName = (exported) => {
|
|
1971
|
+
return t.isIdentifier(exported) ? exported.name : exported.value;
|
|
1972
|
+
};
|
|
1973
|
+
function setsIntersect(set1, set2) {
|
|
1974
|
+
let smallerSet = set1;
|
|
1975
|
+
let largerSet = set2;
|
|
1976
|
+
if (set1.size > set2.size) {
|
|
1977
|
+
smallerSet = set2;
|
|
1978
|
+
largerSet = set1;
|
|
1979
|
+
}
|
|
1980
|
+
for (let element of smallerSet) {
|
|
1981
|
+
if (largerSet.has(element)) {
|
|
1982
|
+
return true;
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
return false;
|
|
1986
|
+
}
|
|
1987
|
+
function hasChunkableExport(code, exportName, cache, cacheKey) {
|
|
1988
|
+
return getOrSetFromCache(
|
|
1989
|
+
cache,
|
|
1990
|
+
`${cacheKey}::hasChunkableExport::${exportName}`,
|
|
1991
|
+
code,
|
|
1992
|
+
() => {
|
|
1993
|
+
let exportDependencies = getExportDependencies(code, cache, cacheKey);
|
|
1994
|
+
let dependencies = exportDependencies.get(exportName);
|
|
1995
|
+
if (!dependencies) {
|
|
1996
|
+
return false;
|
|
1997
|
+
}
|
|
1998
|
+
for (let [currentExportName, currentDependencies] of exportDependencies) {
|
|
1999
|
+
if (currentExportName === exportName) {
|
|
2000
|
+
continue;
|
|
2001
|
+
}
|
|
2002
|
+
if (setsIntersect(
|
|
2003
|
+
currentDependencies.topLevelNonModuleStatements,
|
|
2004
|
+
dependencies.topLevelNonModuleStatements
|
|
2005
|
+
)) {
|
|
2006
|
+
return false;
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
if (dependencies.exportedVariableDeclarators.size > 1) {
|
|
2010
|
+
return false;
|
|
2011
|
+
}
|
|
2012
|
+
if (dependencies.exportedVariableDeclarators.size > 0) {
|
|
2013
|
+
for (let [
|
|
2014
|
+
currentExportName,
|
|
2015
|
+
currentDependencies
|
|
2016
|
+
] of exportDependencies) {
|
|
2017
|
+
if (currentExportName === exportName) {
|
|
2018
|
+
continue;
|
|
2019
|
+
}
|
|
2020
|
+
if (setsIntersect(
|
|
2021
|
+
currentDependencies.exportedVariableDeclarators,
|
|
2022
|
+
dependencies.exportedVariableDeclarators
|
|
2023
|
+
)) {
|
|
2024
|
+
return false;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
return true;
|
|
2029
|
+
}
|
|
2030
|
+
);
|
|
2031
|
+
}
|
|
2032
|
+
function getChunkedExport(code, exportName, generateOptions = {}, cache, cacheKey) {
|
|
2033
|
+
return getOrSetFromCache(
|
|
2034
|
+
cache,
|
|
2035
|
+
`${cacheKey}::getChunkedExport::${exportName}::${JSON.stringify(
|
|
2036
|
+
generateOptions
|
|
2037
|
+
)}`,
|
|
2038
|
+
code,
|
|
2039
|
+
() => {
|
|
2040
|
+
if (!hasChunkableExport(code, exportName, cache, cacheKey)) {
|
|
2041
|
+
return void 0;
|
|
2042
|
+
}
|
|
2043
|
+
let exportDependencies = getExportDependencies(code, cache, cacheKey);
|
|
2044
|
+
let dependencies = exportDependencies.get(exportName);
|
|
2045
|
+
invariant(dependencies, "Expected export to have dependencies");
|
|
2046
|
+
let topLevelStatementsArray = Array.from(dependencies.topLevelStatements);
|
|
2047
|
+
let exportedVariableDeclaratorsArray = Array.from(
|
|
2048
|
+
dependencies.exportedVariableDeclarators
|
|
2049
|
+
);
|
|
2050
|
+
let ast = codeToAst(code, cache, cacheKey);
|
|
2051
|
+
ast.program.body = ast.program.body.filter(
|
|
2052
|
+
(node) => topLevelStatementsArray.some(
|
|
2053
|
+
(statement) => t.isNodesEquivalent(node, statement)
|
|
2054
|
+
)
|
|
2055
|
+
).map((node) => {
|
|
2056
|
+
if (!t.isImportDeclaration(node)) {
|
|
2057
|
+
return node;
|
|
2058
|
+
}
|
|
2059
|
+
if (dependencies.importedIdentifierNames.size === 0) {
|
|
2060
|
+
return null;
|
|
2061
|
+
}
|
|
2062
|
+
node.specifiers = node.specifiers.filter(
|
|
2063
|
+
(specifier) => dependencies.importedIdentifierNames.has(specifier.local.name)
|
|
2064
|
+
);
|
|
2065
|
+
invariant(
|
|
2066
|
+
node.specifiers.length > 0,
|
|
2067
|
+
"Expected import statement to have used specifiers"
|
|
2068
|
+
);
|
|
2069
|
+
return node;
|
|
2070
|
+
}).map((node) => {
|
|
2071
|
+
if (!t.isExportDeclaration(node)) {
|
|
2072
|
+
return node;
|
|
2073
|
+
}
|
|
2074
|
+
if (t.isExportAllDeclaration(node)) {
|
|
2075
|
+
return null;
|
|
2076
|
+
}
|
|
2077
|
+
if (t.isExportDefaultDeclaration(node)) {
|
|
2078
|
+
return exportName === "default" ? node : null;
|
|
2079
|
+
}
|
|
2080
|
+
let { declaration } = node;
|
|
2081
|
+
if (t.isVariableDeclaration(declaration)) {
|
|
2082
|
+
declaration.declarations = declaration.declarations.filter(
|
|
2083
|
+
(node2) => exportedVariableDeclaratorsArray.some(
|
|
2084
|
+
(declarator) => t.isNodesEquivalent(node2, declarator)
|
|
2085
|
+
)
|
|
2086
|
+
);
|
|
2087
|
+
if (declaration.declarations.length === 0) {
|
|
2088
|
+
return null;
|
|
2089
|
+
}
|
|
2090
|
+
return node;
|
|
2091
|
+
}
|
|
2092
|
+
if (t.isFunctionDeclaration(node.declaration) || t.isClassDeclaration(node.declaration)) {
|
|
2093
|
+
return node.declaration.id?.name === exportName ? node : null;
|
|
2094
|
+
}
|
|
2095
|
+
if (t.isExportNamedDeclaration(node)) {
|
|
2096
|
+
if (node.specifiers.length === 0) {
|
|
2097
|
+
return null;
|
|
2098
|
+
}
|
|
2099
|
+
node.specifiers = node.specifiers.filter(
|
|
2100
|
+
(specifier) => getExportedName(specifier.exported) === exportName
|
|
2101
|
+
);
|
|
2102
|
+
if (node.specifiers.length === 0) {
|
|
2103
|
+
return null;
|
|
2104
|
+
}
|
|
2105
|
+
return node;
|
|
2106
|
+
}
|
|
2107
|
+
throw new Error(`Unknown export node type: ${node.type}`);
|
|
2108
|
+
}).filter((node) => node !== null);
|
|
2109
|
+
return generate(ast, generateOptions);
|
|
2110
|
+
}
|
|
2111
|
+
);
|
|
2112
|
+
}
|
|
2113
|
+
function omitChunkedExports(code, exportNames, generateOptions = {}, cache, cacheKey) {
|
|
2114
|
+
return getOrSetFromCache(
|
|
2115
|
+
cache,
|
|
2116
|
+
`${cacheKey}::omitChunkedExports::${exportNames.join(
|
|
2117
|
+
","
|
|
2118
|
+
)}::${JSON.stringify(generateOptions)}`,
|
|
2119
|
+
code,
|
|
2120
|
+
() => {
|
|
2121
|
+
const isChunkable = (exportName) => hasChunkableExport(code, exportName, cache, cacheKey);
|
|
2122
|
+
const isOmitted = (exportName) => exportNames.includes(exportName) && isChunkable(exportName);
|
|
2123
|
+
const isRetained = (exportName) => !isOmitted(exportName);
|
|
2124
|
+
let exportDependencies = getExportDependencies(code, cache, cacheKey);
|
|
2125
|
+
let allExportNames = Array.from(exportDependencies.keys());
|
|
2126
|
+
let omittedExportNames = allExportNames.filter(isOmitted);
|
|
2127
|
+
let retainedExportNames = allExportNames.filter(isRetained);
|
|
2128
|
+
let omittedStatements = /* @__PURE__ */ new Set();
|
|
2129
|
+
let omittedExportedVariableDeclarators = /* @__PURE__ */ new Set();
|
|
2130
|
+
for (let omittedExportName of omittedExportNames) {
|
|
2131
|
+
let dependencies = exportDependencies.get(omittedExportName);
|
|
2132
|
+
invariant(
|
|
2133
|
+
dependencies,
|
|
2134
|
+
`Expected dependencies for ${omittedExportName}`
|
|
2135
|
+
);
|
|
2136
|
+
for (let statement of dependencies.topLevelNonModuleStatements) {
|
|
2137
|
+
omittedStatements.add(statement);
|
|
2138
|
+
}
|
|
2139
|
+
for (let declarator of dependencies.exportedVariableDeclarators) {
|
|
2140
|
+
omittedExportedVariableDeclarators.add(declarator);
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
let ast = codeToAst(code, cache, cacheKey);
|
|
2144
|
+
let omittedStatementsArray = Array.from(omittedStatements);
|
|
2145
|
+
let omittedExportedVariableDeclaratorsArray = Array.from(
|
|
2146
|
+
omittedExportedVariableDeclarators
|
|
2147
|
+
);
|
|
2148
|
+
ast.program.body = ast.program.body.filter(
|
|
2149
|
+
(node) => omittedStatementsArray.every(
|
|
2150
|
+
(statement) => !t.isNodesEquivalent(node, statement)
|
|
2151
|
+
)
|
|
2152
|
+
).map((node) => {
|
|
2153
|
+
if (!t.isImportDeclaration(node)) {
|
|
2154
|
+
return node;
|
|
2155
|
+
}
|
|
2156
|
+
if (node.specifiers.length === 0) {
|
|
2157
|
+
return node;
|
|
2158
|
+
}
|
|
2159
|
+
node.specifiers = node.specifiers.filter((specifier) => {
|
|
2160
|
+
let importedName = specifier.local.name;
|
|
2161
|
+
for (let retainedExportName of retainedExportNames) {
|
|
2162
|
+
let dependencies = exportDependencies.get(retainedExportName);
|
|
2163
|
+
if (dependencies?.importedIdentifierNames?.has(importedName)) {
|
|
2164
|
+
return true;
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
for (let omittedExportName of omittedExportNames) {
|
|
2168
|
+
let dependencies = exportDependencies.get(omittedExportName);
|
|
2169
|
+
if (dependencies?.importedIdentifierNames?.has(importedName)) {
|
|
2170
|
+
return false;
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
return true;
|
|
2174
|
+
});
|
|
2175
|
+
if (node.specifiers.length === 0) {
|
|
2176
|
+
return null;
|
|
2177
|
+
}
|
|
2178
|
+
return node;
|
|
2179
|
+
}).map((node) => {
|
|
2180
|
+
if (!t.isExportDeclaration(node)) {
|
|
2181
|
+
return node;
|
|
2182
|
+
}
|
|
2183
|
+
if (t.isExportAllDeclaration(node)) {
|
|
2184
|
+
return node;
|
|
2185
|
+
}
|
|
2186
|
+
if (t.isExportDefaultDeclaration(node)) {
|
|
2187
|
+
return isOmitted("default") ? null : node;
|
|
2188
|
+
}
|
|
2189
|
+
if (t.isVariableDeclaration(node.declaration)) {
|
|
2190
|
+
node.declaration.declarations = node.declaration.declarations.filter(
|
|
2191
|
+
(node2) => omittedExportedVariableDeclaratorsArray.every(
|
|
2192
|
+
(declarator) => !t.isNodesEquivalent(node2, declarator)
|
|
2193
|
+
)
|
|
2194
|
+
);
|
|
2195
|
+
if (node.declaration.declarations.length === 0) {
|
|
2196
|
+
return null;
|
|
2197
|
+
}
|
|
2198
|
+
return node;
|
|
2199
|
+
}
|
|
2200
|
+
if (t.isFunctionDeclaration(node.declaration) || t.isClassDeclaration(node.declaration)) {
|
|
2201
|
+
invariant(
|
|
2202
|
+
node.declaration.id,
|
|
2203
|
+
"Expected exported function or class declaration to have a name when not the default export"
|
|
2204
|
+
);
|
|
2205
|
+
return isOmitted(node.declaration.id.name) ? null : node;
|
|
2206
|
+
}
|
|
2207
|
+
if (t.isExportNamedDeclaration(node)) {
|
|
2208
|
+
if (node.specifiers.length === 0) {
|
|
2209
|
+
return node;
|
|
2210
|
+
}
|
|
2211
|
+
node.specifiers = node.specifiers.filter((specifier) => {
|
|
2212
|
+
const exportedName = getExportedName(specifier.exported);
|
|
2213
|
+
return !isOmitted(exportedName);
|
|
2214
|
+
});
|
|
2215
|
+
if (node.specifiers.length === 0) {
|
|
2216
|
+
return null;
|
|
2217
|
+
}
|
|
2218
|
+
return node;
|
|
2219
|
+
}
|
|
2220
|
+
throw new Error(`Unknown node type: ${node.type}`);
|
|
2221
|
+
}).filter((node) => node !== null);
|
|
2222
|
+
if (ast.program.body.length === 0) {
|
|
2223
|
+
return void 0;
|
|
2224
|
+
}
|
|
2225
|
+
return generate(ast, generateOptions);
|
|
2226
|
+
}
|
|
2227
|
+
);
|
|
2228
|
+
}
|
|
2229
|
+
function detectRouteChunks(code, cache, cacheKey) {
|
|
2230
|
+
const hasRouteChunkByExportName = Object.fromEntries(
|
|
2231
|
+
routeChunkExportNames.map((exportName) => [
|
|
2232
|
+
exportName,
|
|
2233
|
+
hasChunkableExport(code, exportName, cache, cacheKey)
|
|
2234
|
+
])
|
|
2235
|
+
);
|
|
2236
|
+
const chunkedExports = Object.entries(hasRouteChunkByExportName).filter(([, isChunked]) => isChunked).map(([exportName]) => exportName);
|
|
2237
|
+
const hasRouteChunks = chunkedExports.length > 0;
|
|
2238
|
+
return {
|
|
2239
|
+
hasRouteChunks,
|
|
2240
|
+
hasRouteChunkByExportName,
|
|
2241
|
+
chunkedExports
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
var routeChunkExportNames = [
|
|
2245
|
+
"clientAction",
|
|
2246
|
+
"clientLoader",
|
|
2247
|
+
"clientMiddleware",
|
|
2248
|
+
"HydrateFallback"
|
|
2249
|
+
];
|
|
2250
|
+
var mainChunkName = "main";
|
|
2251
|
+
var routeChunkNames = ["main", ...routeChunkExportNames];
|
|
2252
|
+
function getRouteChunkCode(code, chunkName, cache, cacheKey) {
|
|
2253
|
+
if (chunkName === mainChunkName) {
|
|
2254
|
+
return omitChunkedExports(code, routeChunkExportNames, {}, cache, cacheKey);
|
|
2255
|
+
}
|
|
2256
|
+
return getChunkedExport(code, chunkName, {}, cache, cacheKey);
|
|
2257
|
+
}
|
|
2258
|
+
var routeChunkQueryStringPrefix = "?route-chunk=";
|
|
2259
|
+
var routeChunkQueryStrings = {
|
|
2260
|
+
main: `${routeChunkQueryStringPrefix}main`,
|
|
2261
|
+
clientAction: `${routeChunkQueryStringPrefix}clientAction`,
|
|
2262
|
+
clientLoader: `${routeChunkQueryStringPrefix}clientLoader`,
|
|
2263
|
+
clientMiddleware: `${routeChunkQueryStringPrefix}clientMiddleware`,
|
|
2264
|
+
HydrateFallback: `${routeChunkQueryStringPrefix}HydrateFallback`
|
|
2265
|
+
};
|
|
2266
|
+
function getRouteChunkModuleId(filePath, chunkName) {
|
|
2267
|
+
return `${filePath}${routeChunkQueryStrings[chunkName]}`;
|
|
2268
|
+
}
|
|
2269
|
+
function isRouteChunkModuleId(id) {
|
|
2270
|
+
return Object.values(routeChunkQueryStrings).some(
|
|
2271
|
+
(queryString) => id.endsWith(queryString)
|
|
2272
|
+
);
|
|
2273
|
+
}
|
|
2274
|
+
function isRouteChunkName(name) {
|
|
2275
|
+
return name === mainChunkName || routeChunkExportNames.includes(name);
|
|
2276
|
+
}
|
|
2277
|
+
function getRouteChunkNameFromModuleId(id) {
|
|
2278
|
+
if (!isRouteChunkModuleId(id)) {
|
|
2279
|
+
return null;
|
|
2280
|
+
}
|
|
2281
|
+
let chunkName = id.split(routeChunkQueryStringPrefix)[1].split("&")[0];
|
|
2282
|
+
if (!isRouteChunkName(chunkName)) {
|
|
2283
|
+
return null;
|
|
2284
|
+
}
|
|
2285
|
+
return chunkName;
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
// vite/optimize-deps-entries.ts
|
|
2289
|
+
var import_tinyglobby = require("tinyglobby");
|
|
2290
|
+
function getOptimizeDepsEntries({
|
|
2291
|
+
entryClientFilePath,
|
|
2292
|
+
reactRouterConfig
|
|
2293
|
+
}) {
|
|
2294
|
+
if (!reactRouterConfig.future.unstable_optimizeDeps) {
|
|
2295
|
+
return [];
|
|
2296
|
+
}
|
|
2297
|
+
const vite2 = getVite();
|
|
2298
|
+
const viteMajorVersion = parseInt(vite2.version.split(".")[0], 10);
|
|
2299
|
+
return [
|
|
2300
|
+
vite2.normalizePath(entryClientFilePath),
|
|
2301
|
+
...Object.values(reactRouterConfig.routes).map(
|
|
2302
|
+
(route) => resolveRelativeRouteFilePath(route, reactRouterConfig)
|
|
2303
|
+
)
|
|
2304
|
+
].map(
|
|
2305
|
+
(entry) => (
|
|
2306
|
+
// In Vite 7, the `optimizeDeps.entries` option only accepts glob patterns.
|
|
2307
|
+
// In prior versions, absolute file paths were treated differently.
|
|
2308
|
+
viteMajorVersion >= 7 ? (0, import_tinyglobby.escapePath)(entry) : entry
|
|
2309
|
+
)
|
|
2310
|
+
);
|
|
2311
|
+
}
|
|
2312
|
+
|
|
2313
|
+
// vite/with-props.ts
|
|
2314
|
+
var namedComponentExports = ["HydrateFallback", "ErrorBoundary"];
|
|
2315
|
+
function isNamedComponentExport(name) {
|
|
2316
|
+
return namedComponentExports.includes(name);
|
|
2317
|
+
}
|
|
2318
|
+
var decorateComponentExportsWithProps = (ast) => {
|
|
2319
|
+
const hocs = [];
|
|
2320
|
+
function getHocUid(path7, hocName) {
|
|
2321
|
+
const uid = path7.scope.generateUidIdentifier(hocName);
|
|
2322
|
+
hocs.push([hocName, uid]);
|
|
2323
|
+
return uid;
|
|
2324
|
+
}
|
|
2325
|
+
traverse(ast, {
|
|
2326
|
+
ExportDeclaration(path7) {
|
|
2327
|
+
if (path7.isExportDefaultDeclaration()) {
|
|
2328
|
+
const declaration = path7.get("declaration");
|
|
2329
|
+
const expr = declaration.isExpression() ? declaration.node : declaration.isFunctionDeclaration() ? toFunctionExpression(declaration.node) : void 0;
|
|
2330
|
+
if (expr) {
|
|
2331
|
+
const uid = getHocUid(path7, "UNSAFE_withComponentProps");
|
|
2332
|
+
declaration.replaceWith(t.callExpression(uid, [expr]));
|
|
2333
|
+
}
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
if (path7.isExportNamedDeclaration()) {
|
|
2337
|
+
const decl = path7.get("declaration");
|
|
2338
|
+
if (decl.isVariableDeclaration()) {
|
|
2339
|
+
decl.get("declarations").forEach((varDeclarator) => {
|
|
2340
|
+
const id = varDeclarator.get("id");
|
|
2341
|
+
const init = varDeclarator.get("init");
|
|
2342
|
+
const expr = init.node;
|
|
2343
|
+
if (!expr) return;
|
|
2344
|
+
if (!id.isIdentifier()) return;
|
|
2345
|
+
const { name } = id.node;
|
|
2346
|
+
if (!isNamedComponentExport(name)) return;
|
|
2347
|
+
const uid = getHocUid(path7, `UNSAFE_with${name}Props`);
|
|
2348
|
+
init.replaceWith(t.callExpression(uid, [expr]));
|
|
2349
|
+
});
|
|
2350
|
+
return;
|
|
2351
|
+
}
|
|
2352
|
+
if (decl.isFunctionDeclaration()) {
|
|
2353
|
+
const { id } = decl.node;
|
|
2354
|
+
if (!id) return;
|
|
2355
|
+
const { name } = id;
|
|
2356
|
+
if (!isNamedComponentExport(name)) return;
|
|
2357
|
+
const uid = getHocUid(path7, `UNSAFE_with${name}Props`);
|
|
2358
|
+
decl.replaceWith(
|
|
2359
|
+
t.variableDeclaration("const", [
|
|
2360
|
+
t.variableDeclarator(
|
|
2361
|
+
t.identifier(name),
|
|
2362
|
+
t.callExpression(uid, [toFunctionExpression(decl.node)])
|
|
2363
|
+
)
|
|
2364
|
+
])
|
|
2365
|
+
);
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
});
|
|
2370
|
+
if (hocs.length > 0) {
|
|
2371
|
+
ast.program.body.unshift(
|
|
2372
|
+
t.importDeclaration(
|
|
2373
|
+
hocs.map(
|
|
2374
|
+
([name, identifier]) => t.importSpecifier(identifier, t.identifier(name))
|
|
2375
|
+
),
|
|
2376
|
+
t.stringLiteral("react-router")
|
|
2377
|
+
)
|
|
2378
|
+
);
|
|
2379
|
+
}
|
|
2380
|
+
};
|
|
2381
|
+
function toFunctionExpression(decl) {
|
|
2382
|
+
return t.functionExpression(
|
|
2383
|
+
decl.id,
|
|
2384
|
+
decl.params,
|
|
2385
|
+
decl.body,
|
|
2386
|
+
decl.generator,
|
|
2387
|
+
decl.async
|
|
2388
|
+
);
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
// vite/plugins/validate-plugin-order.ts
|
|
2392
|
+
function validatePluginOrder() {
|
|
2393
|
+
return {
|
|
2394
|
+
name: "react-router:validate-plugin-order",
|
|
2395
|
+
configResolved(viteConfig) {
|
|
2396
|
+
let pluginIndex = (pluginName) => {
|
|
2397
|
+
pluginName = Array.isArray(pluginName) ? pluginName : [pluginName];
|
|
2398
|
+
return viteConfig.plugins.findIndex(
|
|
2399
|
+
(plugin) => pluginName.includes(plugin.name)
|
|
2400
|
+
);
|
|
2401
|
+
};
|
|
2402
|
+
let reactRouterRscPluginIndex = pluginIndex("react-router/rsc");
|
|
2403
|
+
let viteRscPluginIndex = pluginIndex("rsc");
|
|
2404
|
+
if (reactRouterRscPluginIndex >= 0 && viteRscPluginIndex >= 0 && reactRouterRscPluginIndex > viteRscPluginIndex) {
|
|
2405
|
+
throw new Error(
|
|
2406
|
+
`The "@vitejs/plugin-rsc" plugin should be placed after the React Router RSC plugin in your Vite config`
|
|
2407
|
+
);
|
|
2408
|
+
}
|
|
2409
|
+
let reactRouterPluginIndex = pluginIndex([
|
|
2410
|
+
"react-router",
|
|
2411
|
+
"react-router/rsc"
|
|
2412
|
+
]);
|
|
2413
|
+
let mdxPluginIndex = pluginIndex("@mdx-js/rollup");
|
|
2414
|
+
if (mdxPluginIndex >= 0 && mdxPluginIndex > reactRouterPluginIndex) {
|
|
2415
|
+
throw new Error(
|
|
2416
|
+
`The "@mdx-js/rollup" plugin should be placed before the React Router plugin in your Vite config`
|
|
2417
|
+
);
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
// vite/plugin.ts
|
|
2424
|
+
function extractPluginContext(viteConfig) {
|
|
2425
|
+
return viteConfig["__reactRouterPluginContext"];
|
|
2426
|
+
}
|
|
2427
|
+
var SERVER_ONLY_ROUTE_EXPORTS = ["loader", "action", "middleware", "headers"];
|
|
2428
|
+
var CLIENT_NON_COMPONENT_EXPORTS = [
|
|
2429
|
+
"clientAction",
|
|
2430
|
+
"clientLoader",
|
|
2431
|
+
"clientMiddleware",
|
|
2432
|
+
"handle",
|
|
2433
|
+
"meta",
|
|
2434
|
+
"links",
|
|
2435
|
+
"shouldRevalidate"
|
|
2436
|
+
];
|
|
2437
|
+
var CLIENT_ROUTE_EXPORTS = [
|
|
2438
|
+
...CLIENT_NON_COMPONENT_EXPORTS,
|
|
2439
|
+
"default",
|
|
2440
|
+
"ErrorBoundary",
|
|
2441
|
+
"HydrateFallback",
|
|
2442
|
+
"Layout"
|
|
2443
|
+
];
|
|
2444
|
+
var BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route";
|
|
2445
|
+
var SSR_BUNDLE_PREFIX = "ssrBundle_";
|
|
2446
|
+
function isSsrBundleEnvironmentName(name) {
|
|
2447
|
+
return name.startsWith(SSR_BUNDLE_PREFIX);
|
|
2448
|
+
}
|
|
2449
|
+
function getServerEnvironmentEntries(ctx, record) {
|
|
2450
|
+
return Object.entries(record).filter(
|
|
2451
|
+
([name]) => ctx.buildManifest?.serverBundles ? isSsrBundleEnvironmentName(name) : name === "ssr"
|
|
2452
|
+
);
|
|
2453
|
+
}
|
|
2454
|
+
function getServerEnvironmentValues(ctx, record) {
|
|
2455
|
+
return getServerEnvironmentEntries(ctx, record).map(([, value]) => value);
|
|
2456
|
+
}
|
|
2457
|
+
var isRouteEntryModuleId = (id) => {
|
|
2458
|
+
return id.endsWith(BUILD_CLIENT_ROUTE_QUERY_STRING);
|
|
2459
|
+
};
|
|
2460
|
+
var isRouteVirtualModule = (id) => {
|
|
2461
|
+
return isRouteEntryModuleId(id) || isRouteChunkModuleId(id);
|
|
2462
|
+
};
|
|
2463
|
+
var isServerBuildVirtualModuleId = (id) => {
|
|
2464
|
+
return id.split("?")[0] === virtual.serverBuild.id;
|
|
2465
|
+
};
|
|
2466
|
+
var getServerBuildFile = (viteManifest) => {
|
|
2467
|
+
let serverBuildIds = Object.keys(viteManifest).filter(
|
|
2468
|
+
isServerBuildVirtualModuleId
|
|
2469
|
+
);
|
|
2470
|
+
invariant(
|
|
2471
|
+
serverBuildIds.length <= 1,
|
|
2472
|
+
"Multiple server build files found in manifest"
|
|
2473
|
+
);
|
|
2474
|
+
invariant(
|
|
2475
|
+
serverBuildIds.length === 1,
|
|
2476
|
+
"Server build file not found in manifest"
|
|
2477
|
+
);
|
|
2478
|
+
return viteManifest[serverBuildIds[0]].file;
|
|
2479
|
+
};
|
|
2480
|
+
var virtualHmrRuntime = create("hmr-runtime");
|
|
2481
|
+
var virtualInjectHmrRuntime = create("inject-hmr-runtime");
|
|
2482
|
+
var normalizeRelativeFilePath = (file, reactRouterConfig) => {
|
|
2483
|
+
let vite2 = getVite();
|
|
2484
|
+
let fullPath = path6.resolve(reactRouterConfig.appDirectory, file);
|
|
2485
|
+
let relativePath = path6.relative(reactRouterConfig.appDirectory, fullPath);
|
|
2486
|
+
return vite2.normalizePath(relativePath).split("?")[0];
|
|
2487
|
+
};
|
|
2488
|
+
var virtual = {
|
|
2489
|
+
serverBuild: create("server-build"),
|
|
2490
|
+
serverManifest: create("server-manifest"),
|
|
2491
|
+
browserManifest: create("browser-manifest")
|
|
2492
|
+
};
|
|
2493
|
+
var invalidateVirtualModules = (viteDevServer) => {
|
|
2494
|
+
Object.values(virtual).forEach((vmod) => {
|
|
2495
|
+
let mod = viteDevServer.moduleGraph.getModuleById(vmod.resolvedId);
|
|
2496
|
+
if (mod) {
|
|
2497
|
+
viteDevServer.moduleGraph.invalidateModule(mod);
|
|
2498
|
+
}
|
|
2499
|
+
});
|
|
2500
|
+
};
|
|
2501
|
+
var getHash = (source, maxLength) => {
|
|
2502
|
+
let hash = (0, import_node_crypto.createHash)("sha256").update(source).digest("hex");
|
|
2503
|
+
return typeof maxLength === "number" ? hash.slice(0, maxLength) : hash;
|
|
2504
|
+
};
|
|
2505
|
+
var resolveChunk = (ctx, viteManifest, absoluteFilePath) => {
|
|
2506
|
+
let vite2 = getVite();
|
|
2507
|
+
let rootRelativeFilePath = vite2.normalizePath(
|
|
2508
|
+
path6.relative(ctx.rootDirectory, absoluteFilePath)
|
|
2509
|
+
);
|
|
2510
|
+
let entryChunk = viteManifest[rootRelativeFilePath];
|
|
2511
|
+
if (!entryChunk) {
|
|
2512
|
+
return void 0;
|
|
2513
|
+
}
|
|
2514
|
+
return entryChunk;
|
|
2515
|
+
};
|
|
2516
|
+
var getPublicModulePathForEntry = (ctx, viteManifest, entryFilePath) => {
|
|
2517
|
+
let entryChunk = resolveChunk(ctx, viteManifest, entryFilePath);
|
|
2518
|
+
return entryChunk ? `${ctx.publicPath}${entryChunk.file}` : void 0;
|
|
2519
|
+
};
|
|
2520
|
+
var getCssCodeSplitDisabledFile = (ctx, viteConfig, viteManifest) => {
|
|
2521
|
+
if (viteConfig.build.cssCodeSplit) {
|
|
2522
|
+
return null;
|
|
2523
|
+
}
|
|
2524
|
+
let cssFile = viteManifest["style.css"]?.file;
|
|
2525
|
+
invariant(
|
|
2526
|
+
cssFile,
|
|
2527
|
+
"Expected `style.css` to be present in Vite manifest when `build.cssCodeSplit` is disabled"
|
|
2528
|
+
);
|
|
2529
|
+
return `${ctx.publicPath}${cssFile}`;
|
|
2530
|
+
};
|
|
2531
|
+
var getClientEntryChunk = (ctx, viteManifest) => {
|
|
2532
|
+
let filePath = ctx.entryClientFilePath;
|
|
2533
|
+
let chunk = resolveChunk(ctx, viteManifest, filePath);
|
|
2534
|
+
invariant(chunk, `Chunk not found: ${filePath}`);
|
|
2535
|
+
return chunk;
|
|
2536
|
+
};
|
|
2537
|
+
var getReactRouterManifestBuildAssets = (ctx, viteConfig, viteManifest, entryFilePath, route) => {
|
|
2538
|
+
let entryChunk = resolveChunk(ctx, viteManifest, entryFilePath);
|
|
2539
|
+
invariant(entryChunk, `Chunk not found: ${entryFilePath}`);
|
|
2540
|
+
let isRootRoute = Boolean(route && route.parentId === void 0);
|
|
2541
|
+
let routeModuleChunks = routeChunkNames.map(
|
|
2542
|
+
(routeChunkName) => resolveChunk(
|
|
2543
|
+
ctx,
|
|
2544
|
+
viteManifest,
|
|
2545
|
+
getRouteChunkModuleId(entryFilePath.split("?")[0], routeChunkName)
|
|
2546
|
+
)
|
|
2547
|
+
).filter(isNonNullable);
|
|
2548
|
+
let chunks = resolveDependantChunks(
|
|
2549
|
+
viteManifest,
|
|
2550
|
+
[
|
|
2551
|
+
// If this is the root route, we also need to include assets from the
|
|
2552
|
+
// client entry file as this is a common way for consumers to import
|
|
2553
|
+
// global reset styles, etc.
|
|
2554
|
+
isRootRoute ? getClientEntryChunk(ctx, viteManifest) : null,
|
|
2555
|
+
entryChunk,
|
|
2556
|
+
routeModuleChunks
|
|
2557
|
+
].flat(1).filter(isNonNullable)
|
|
2558
|
+
);
|
|
2559
|
+
return {
|
|
2560
|
+
module: `${ctx.publicPath}${entryChunk.file}`,
|
|
2561
|
+
imports: dedupe(chunks.flatMap((e) => e.imports ?? [])).map((imported) => {
|
|
2562
|
+
return `${ctx.publicPath}${viteManifest[imported].file}`;
|
|
2563
|
+
}) ?? [],
|
|
2564
|
+
css: dedupe(
|
|
2565
|
+
[
|
|
2566
|
+
// If CSS code splitting is disabled, Vite includes a singular 'style.css' asset
|
|
2567
|
+
// in the manifest that isn't tied to any route file. If we want to render these
|
|
2568
|
+
// styles correctly, we need to include them in the root route.
|
|
2569
|
+
isRootRoute ? getCssCodeSplitDisabledFile(ctx, viteConfig, viteManifest) : null,
|
|
2570
|
+
chunks.flatMap((e) => e.css ?? []).map((href) => `${ctx.publicPath}${href}`)
|
|
2571
|
+
].flat(1).filter(isNonNullable)
|
|
2572
|
+
)
|
|
2573
|
+
};
|
|
2574
|
+
};
|
|
2575
|
+
function resolveDependantChunks(viteManifest, entryChunks) {
|
|
2576
|
+
let chunks = /* @__PURE__ */ new Set();
|
|
2577
|
+
function walk(chunk) {
|
|
2578
|
+
if (chunks.has(chunk)) {
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
chunks.add(chunk);
|
|
2582
|
+
if (chunk.imports) {
|
|
2583
|
+
for (let importKey of chunk.imports) {
|
|
2584
|
+
walk(viteManifest[importKey]);
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
for (let entryChunk of entryChunks) {
|
|
2589
|
+
walk(entryChunk);
|
|
2590
|
+
}
|
|
2591
|
+
return Array.from(chunks);
|
|
2592
|
+
}
|
|
2593
|
+
function dedupe(array2) {
|
|
2594
|
+
return [...new Set(array2)];
|
|
2595
|
+
}
|
|
2596
|
+
var writeFileSafe = async (file, contents) => {
|
|
2597
|
+
await (0, import_promises2.mkdir)(path6.dirname(file), { recursive: true });
|
|
2598
|
+
await (0, import_promises2.writeFile)(file, contents);
|
|
2599
|
+
};
|
|
2600
|
+
var getExportNames = (code) => {
|
|
2601
|
+
let [, exportSpecifiers] = (0, import_es_module_lexer.parse)(code);
|
|
2602
|
+
return exportSpecifiers.map(({ n: name }) => name);
|
|
2603
|
+
};
|
|
2604
|
+
var getRouteManifestModuleExports = async (viteChildCompiler, ctx) => {
|
|
2605
|
+
let entries = await Promise.all(
|
|
2606
|
+
Object.entries(ctx.reactRouterConfig.routes).map(async ([key, route]) => {
|
|
2607
|
+
let sourceExports = await getRouteModuleExports(
|
|
2608
|
+
viteChildCompiler,
|
|
2609
|
+
ctx,
|
|
2610
|
+
route.file
|
|
2611
|
+
);
|
|
2612
|
+
return [key, sourceExports];
|
|
2613
|
+
})
|
|
2614
|
+
);
|
|
2615
|
+
return Object.fromEntries(entries);
|
|
2616
|
+
};
|
|
2617
|
+
var compileRouteFile = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
|
|
2618
|
+
if (!viteChildCompiler) {
|
|
2619
|
+
throw new Error("Vite child compiler not found");
|
|
2620
|
+
}
|
|
2621
|
+
let ssr = true;
|
|
2622
|
+
let { pluginContainer, moduleGraph } = viteChildCompiler;
|
|
2623
|
+
let routePath = path6.resolve(ctx.reactRouterConfig.appDirectory, routeFile);
|
|
2624
|
+
let url2 = resolveFileUrl(ctx, routePath);
|
|
2625
|
+
let resolveId = async () => {
|
|
2626
|
+
let result = await pluginContainer.resolveId(url2, void 0, { ssr });
|
|
2627
|
+
if (!result) throw new Error(`Could not resolve module ID for ${url2}`);
|
|
2628
|
+
return result.id;
|
|
2629
|
+
};
|
|
2630
|
+
let [id, code] = await Promise.all([
|
|
2631
|
+
resolveId(),
|
|
2632
|
+
readRouteFile?.() ?? (0, import_promises2.readFile)(routePath, "utf-8"),
|
|
2633
|
+
// pluginContainer.transform(...) fails if we don't do this first:
|
|
2634
|
+
moduleGraph.ensureEntryFromUrl(url2, ssr)
|
|
2635
|
+
]);
|
|
2636
|
+
let transformed = await pluginContainer.transform(code, id, { ssr });
|
|
2637
|
+
return transformed.code;
|
|
2638
|
+
};
|
|
2639
|
+
var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
|
|
2640
|
+
if (!viteChildCompiler) {
|
|
2641
|
+
throw new Error("Vite child compiler not found");
|
|
2642
|
+
}
|
|
2643
|
+
let code = await compileRouteFile(
|
|
2644
|
+
viteChildCompiler,
|
|
2645
|
+
ctx,
|
|
2646
|
+
routeFile,
|
|
2647
|
+
readRouteFile
|
|
2648
|
+
);
|
|
2649
|
+
return getExportNames(code);
|
|
2650
|
+
};
|
|
2651
|
+
var resolveEnvironmentBuildContext = ({
|
|
2652
|
+
viteCommand,
|
|
2653
|
+
viteUserConfig
|
|
2654
|
+
}) => {
|
|
2655
|
+
if (!("__reactRouterEnvironmentBuildContext" in viteUserConfig) || !viteUserConfig.__reactRouterEnvironmentBuildContext) {
|
|
2656
|
+
return null;
|
|
2657
|
+
}
|
|
2658
|
+
let buildContext = viteUserConfig.__reactRouterEnvironmentBuildContext;
|
|
2659
|
+
let resolvedBuildContext = {
|
|
2660
|
+
name: buildContext.name,
|
|
2661
|
+
options: buildContext.resolveOptions({ viteUserConfig })
|
|
2662
|
+
};
|
|
2663
|
+
return resolvedBuildContext;
|
|
2664
|
+
};
|
|
2665
|
+
var getServerBuildDirectory = (reactRouterConfig, { serverBundleId } = {}) => path6.join(
|
|
2666
|
+
reactRouterConfig.buildDirectory,
|
|
2667
|
+
"server",
|
|
2668
|
+
...serverBundleId ? [serverBundleId] : []
|
|
2669
|
+
);
|
|
2670
|
+
var getClientBuildDirectory = (reactRouterConfig) => path6.join(reactRouterConfig.buildDirectory, "client");
|
|
2671
|
+
var getServerBundleRouteIds = (vitePluginContext, ctx) => {
|
|
2672
|
+
if (!ctx.buildManifest) {
|
|
2673
|
+
return void 0;
|
|
2674
|
+
}
|
|
2675
|
+
let environmentName = ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? vitePluginContext.environment.name : ctx.environmentBuildContext?.name;
|
|
2676
|
+
if (!environmentName || !isSsrBundleEnvironmentName(environmentName)) {
|
|
2677
|
+
return void 0;
|
|
2678
|
+
}
|
|
2679
|
+
let serverBundleId = environmentName.replace(SSR_BUNDLE_PREFIX, "");
|
|
2680
|
+
let routesByServerBundleId = getRoutesByServerBundleId(ctx.buildManifest);
|
|
2681
|
+
let serverBundleRoutes = routesByServerBundleId[serverBundleId];
|
|
2682
|
+
invariant(
|
|
2683
|
+
serverBundleRoutes,
|
|
2684
|
+
`Routes not found for server bundle "${serverBundleId}"`
|
|
2685
|
+
);
|
|
2686
|
+
return Object.keys(serverBundleRoutes);
|
|
2687
|
+
};
|
|
2688
|
+
var defaultEntriesDir = path6.resolve(
|
|
2689
|
+
path6.dirname(require.resolve("@react-router/dev/package.json")),
|
|
2690
|
+
"dist",
|
|
2691
|
+
"config",
|
|
2692
|
+
"defaults"
|
|
2693
|
+
);
|
|
2694
|
+
var defaultEntries = (0, import_node_fs2.readdirSync)(defaultEntriesDir).map(
|
|
2695
|
+
(filename2) => path6.join(defaultEntriesDir, filename2)
|
|
2696
|
+
);
|
|
2697
|
+
invariant(defaultEntries.length > 0, "No default entries found");
|
|
2698
|
+
var reactRouterDevLoadContext = () => void 0;
|
|
2699
|
+
var reactRouterVitePlugin = () => {
|
|
2700
|
+
let rootDirectory;
|
|
2701
|
+
let viteCommand;
|
|
2702
|
+
let viteUserConfig;
|
|
2703
|
+
let viteConfigEnv;
|
|
2704
|
+
let viteConfig;
|
|
2705
|
+
let cssModulesManifest = {};
|
|
2706
|
+
let viteChildCompiler = null;
|
|
2707
|
+
let cache = /* @__PURE__ */ new Map();
|
|
2708
|
+
let reactRouterConfigLoader;
|
|
2709
|
+
let typegenWatcherPromise;
|
|
2710
|
+
let logger;
|
|
2711
|
+
let firstLoad = true;
|
|
2712
|
+
let ctx;
|
|
2713
|
+
let updatePluginContext = async () => {
|
|
2714
|
+
let reactRouterConfig;
|
|
2715
|
+
let reactRouterConfigResult = await reactRouterConfigLoader.getConfig();
|
|
2716
|
+
if (reactRouterConfigResult.ok) {
|
|
2717
|
+
reactRouterConfig = reactRouterConfigResult.value;
|
|
2718
|
+
} else {
|
|
2719
|
+
logger.error(reactRouterConfigResult.error);
|
|
2720
|
+
if (firstLoad) {
|
|
2721
|
+
process.exit(1);
|
|
2722
|
+
}
|
|
2723
|
+
return;
|
|
2724
|
+
}
|
|
2725
|
+
let injectedPluginContext = !reactRouterConfig.future.unstable_viteEnvironmentApi && viteCommand === "build" ? extractPluginContext(viteUserConfig) : void 0;
|
|
2726
|
+
let { entryClientFilePath, entryServerFilePath } = await resolveEntryFiles({
|
|
2727
|
+
rootDirectory,
|
|
2728
|
+
reactRouterConfig
|
|
2729
|
+
});
|
|
2730
|
+
let publicPath = viteUserConfig.base ?? "/";
|
|
2731
|
+
if (reactRouterConfig.basename !== "/" && viteCommand === "serve" && !viteUserConfig.server?.middlewareMode && !reactRouterConfig.basename.startsWith(publicPath)) {
|
|
2732
|
+
logger.error(
|
|
2733
|
+
import_picocolors3.default.red(
|
|
2734
|
+
"When using the React Router `basename` and the Vite `base` config, the `basename` config must begin with `base` for the default Vite dev server."
|
|
2735
|
+
)
|
|
2736
|
+
);
|
|
2737
|
+
process.exit(1);
|
|
2738
|
+
}
|
|
2739
|
+
let viteManifestEnabled = viteUserConfig.build?.manifest === true;
|
|
2740
|
+
let buildManifest = viteCommand === "build" ? injectedPluginContext?.buildManifest ?? await getBuildManifest({ reactRouterConfig, rootDirectory }) : null;
|
|
2741
|
+
let environmentBuildContext = viteCommand === "build" ? resolveEnvironmentBuildContext({ viteCommand, viteUserConfig }) : null;
|
|
2742
|
+
firstLoad = false;
|
|
2743
|
+
ctx = {
|
|
2744
|
+
environmentBuildContext,
|
|
2745
|
+
reactRouterConfig,
|
|
2746
|
+
rootDirectory,
|
|
2747
|
+
entryClientFilePath,
|
|
2748
|
+
entryServerFilePath,
|
|
2749
|
+
publicPath,
|
|
2750
|
+
viteManifestEnabled,
|
|
2751
|
+
buildManifest
|
|
2752
|
+
};
|
|
2753
|
+
};
|
|
2754
|
+
let getServerEntry = async ({ routeIds }) => {
|
|
2755
|
+
invariant(viteConfig, "viteconfig required to generate the server entry");
|
|
2756
|
+
let routes = routeIds ? (
|
|
2757
|
+
// For server bundle builds, the server build should only import the
|
|
2758
|
+
// routes for this bundle rather than importing all routes
|
|
2759
|
+
(0, import_pick3.default)(ctx.reactRouterConfig.routes, routeIds)
|
|
2760
|
+
) : (
|
|
2761
|
+
// Otherwise, all routes are imported as usual
|
|
2762
|
+
ctx.reactRouterConfig.routes
|
|
2763
|
+
);
|
|
2764
|
+
let prerenderPaths = await getPrerenderPaths(
|
|
2765
|
+
ctx.reactRouterConfig.prerender,
|
|
2766
|
+
ctx.reactRouterConfig.ssr,
|
|
2767
|
+
routes
|
|
2768
|
+
);
|
|
2769
|
+
let isSpaMode = isSpaModeEnabled(ctx.reactRouterConfig);
|
|
2770
|
+
return `
|
|
2771
|
+
import * as entryServer from ${JSON.stringify(
|
|
2772
|
+
resolveFileUrl(ctx, ctx.entryServerFilePath)
|
|
2773
|
+
)};
|
|
2774
|
+
${Object.keys(routes).map((key, index) => {
|
|
2775
|
+
let route = routes[key];
|
|
2776
|
+
if (isSpaMode && key !== "root") {
|
|
2777
|
+
return `const route${index} = { default: () => null };`;
|
|
2778
|
+
} else {
|
|
2779
|
+
return `import * as route${index} from ${JSON.stringify(
|
|
2780
|
+
resolveFileUrl(
|
|
2781
|
+
ctx,
|
|
2782
|
+
resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
|
|
2783
|
+
)
|
|
2784
|
+
)};`;
|
|
2785
|
+
}
|
|
2786
|
+
}).join("\n")}
|
|
2787
|
+
export { default as assets } from ${JSON.stringify(
|
|
2788
|
+
virtual.serverManifest.id
|
|
2789
|
+
)};
|
|
2790
|
+
export const assetsBuildDirectory = ${JSON.stringify(
|
|
2791
|
+
path6.relative(
|
|
2792
|
+
ctx.rootDirectory,
|
|
2793
|
+
getClientBuildDirectory(ctx.reactRouterConfig)
|
|
2794
|
+
)
|
|
2795
|
+
)};
|
|
2796
|
+
export const basename = ${JSON.stringify(ctx.reactRouterConfig.basename)};
|
|
2797
|
+
export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
|
|
2798
|
+
export const ssr = ${ctx.reactRouterConfig.ssr};
|
|
2799
|
+
export const isSpaMode = ${isSpaMode};
|
|
2800
|
+
export const prerender = ${JSON.stringify(prerenderPaths)};
|
|
2801
|
+
export const routeDiscovery = ${JSON.stringify(
|
|
2802
|
+
ctx.reactRouterConfig.routeDiscovery
|
|
2803
|
+
)};
|
|
2804
|
+
export const publicPath = ${JSON.stringify(ctx.publicPath)};
|
|
2805
|
+
export const entry = { module: entryServer };
|
|
2806
|
+
export const routes = {
|
|
2807
|
+
${Object.keys(routes).map((key, index) => {
|
|
2808
|
+
let route = routes[key];
|
|
2809
|
+
return `${JSON.stringify(key)}: {
|
|
2810
|
+
id: ${JSON.stringify(route.id)},
|
|
2811
|
+
parentId: ${JSON.stringify(route.parentId)},
|
|
2812
|
+
path: ${JSON.stringify(route.path)},
|
|
2813
|
+
index: ${JSON.stringify(route.index)},
|
|
2814
|
+
caseSensitive: ${JSON.stringify(route.caseSensitive)},
|
|
2815
|
+
module: route${index}
|
|
2816
|
+
}`;
|
|
2817
|
+
}).join(",\n ")}
|
|
2818
|
+
};
|
|
2819
|
+
${ctx.reactRouterConfig.future.unstable_viteEnvironmentApi && viteCommand === "serve" ? `
|
|
2820
|
+
export const unstable_getCriticalCss = ({ pathname }) => {
|
|
2821
|
+
return {
|
|
2822
|
+
rel: "stylesheet",
|
|
2823
|
+
href: "${ctx.publicPath}@react-router/critical.css?pathname=" + pathname,
|
|
2824
|
+
};
|
|
2825
|
+
}
|
|
2826
|
+
` : ""}`;
|
|
2827
|
+
};
|
|
2828
|
+
let loadViteManifest = async (directory) => {
|
|
2829
|
+
let manifestContents = await (0, import_promises2.readFile)(
|
|
2830
|
+
path6.resolve(directory, ".vite", "manifest.json"),
|
|
2831
|
+
"utf-8"
|
|
2832
|
+
);
|
|
2833
|
+
return JSON.parse(manifestContents);
|
|
2834
|
+
};
|
|
2835
|
+
let getViteManifestAssetPaths = (viteManifest) => {
|
|
2836
|
+
let cssUrlPaths = Object.values(viteManifest).filter((chunk) => chunk.file.endsWith(".css")).map((chunk) => chunk.file);
|
|
2837
|
+
let chunkAssetPaths = Object.values(viteManifest).flatMap(
|
|
2838
|
+
(chunk) => chunk.assets ?? []
|
|
2839
|
+
);
|
|
2840
|
+
return /* @__PURE__ */ new Set([...cssUrlPaths, ...chunkAssetPaths]);
|
|
2841
|
+
};
|
|
2842
|
+
let generateSriManifest = async (ctx2) => {
|
|
2843
|
+
let clientBuildDirectory = getClientBuildDirectory(ctx2.reactRouterConfig);
|
|
2844
|
+
let entries = (0, import_node_fs2.readdirSync)(clientBuildDirectory, {
|
|
2845
|
+
withFileTypes: true,
|
|
2846
|
+
recursive: true
|
|
2847
|
+
});
|
|
2848
|
+
let sriManifest = {};
|
|
2849
|
+
for (const entry of entries) {
|
|
2850
|
+
if (entry.isFile() && entry.name.endsWith(".js")) {
|
|
2851
|
+
const entryNormalizedPath = "parentPath" in entry && typeof entry.parentPath === "string" ? entry.parentPath : entry.path;
|
|
2852
|
+
let contents;
|
|
2853
|
+
try {
|
|
2854
|
+
contents = await (0, import_promises2.readFile)(
|
|
2855
|
+
path6.join(entryNormalizedPath, entry.name),
|
|
2856
|
+
"utf-8"
|
|
2857
|
+
);
|
|
2858
|
+
} catch (e) {
|
|
2859
|
+
logger.error(`Failed to read file for SRI generation: ${entry.name}`);
|
|
2860
|
+
throw e;
|
|
2861
|
+
}
|
|
2862
|
+
let hash = (0, import_node_crypto.createHash)("sha384").update(contents).digest().toString("base64");
|
|
2863
|
+
let filepath = getVite().normalizePath(
|
|
2864
|
+
path6.relative(
|
|
2865
|
+
clientBuildDirectory,
|
|
2866
|
+
path6.join(entryNormalizedPath, entry.name)
|
|
2867
|
+
)
|
|
2868
|
+
);
|
|
2869
|
+
sriManifest[`${ctx2.publicPath}${filepath}`] = `sha384-${hash}`;
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
return sriManifest;
|
|
2873
|
+
};
|
|
2874
|
+
let generateReactRouterManifestsForBuild = async ({
|
|
2875
|
+
viteConfig: viteConfig2,
|
|
2876
|
+
routeIds
|
|
2877
|
+
}) => {
|
|
2878
|
+
invariant(viteConfig2);
|
|
2879
|
+
let viteManifest = await loadViteManifest(
|
|
2880
|
+
getClientBuildDirectory(ctx.reactRouterConfig)
|
|
2881
|
+
);
|
|
2882
|
+
let entry = getReactRouterManifestBuildAssets(
|
|
2883
|
+
ctx,
|
|
2884
|
+
viteConfig2,
|
|
2885
|
+
viteManifest,
|
|
2886
|
+
ctx.entryClientFilePath,
|
|
2887
|
+
null
|
|
2888
|
+
);
|
|
2889
|
+
let browserRoutes = {};
|
|
2890
|
+
let serverRoutes = {};
|
|
2891
|
+
let routeManifestExports = await getRouteManifestModuleExports(
|
|
2892
|
+
viteChildCompiler,
|
|
2893
|
+
ctx
|
|
2894
|
+
);
|
|
2895
|
+
let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
|
|
2896
|
+
for (let route of Object.values(ctx.reactRouterConfig.routes)) {
|
|
2897
|
+
let routeFile = path6.join(ctx.reactRouterConfig.appDirectory, route.file);
|
|
2898
|
+
let sourceExports = routeManifestExports[route.id];
|
|
2899
|
+
let hasClientAction = sourceExports.includes("clientAction");
|
|
2900
|
+
let hasClientLoader = sourceExports.includes("clientLoader");
|
|
2901
|
+
let hasClientMiddleware = sourceExports.includes("clientMiddleware");
|
|
2902
|
+
let hasHydrateFallback = sourceExports.includes("HydrateFallback");
|
|
2903
|
+
let { hasRouteChunkByExportName } = await detectRouteChunksIfEnabled(
|
|
2904
|
+
cache,
|
|
2905
|
+
ctx,
|
|
2906
|
+
routeFile,
|
|
2907
|
+
{ routeFile, viteChildCompiler }
|
|
2908
|
+
);
|
|
2909
|
+
if (enforceSplitRouteModules) {
|
|
2910
|
+
validateRouteChunks({
|
|
2911
|
+
ctx,
|
|
2912
|
+
id: route.file,
|
|
2913
|
+
valid: {
|
|
2914
|
+
clientAction: !hasClientAction || hasRouteChunkByExportName.clientAction,
|
|
2915
|
+
clientLoader: !hasClientLoader || hasRouteChunkByExportName.clientLoader,
|
|
2916
|
+
clientMiddleware: !hasClientMiddleware || hasRouteChunkByExportName.clientMiddleware,
|
|
2917
|
+
HydrateFallback: !hasHydrateFallback || hasRouteChunkByExportName.HydrateFallback
|
|
2918
|
+
}
|
|
2919
|
+
});
|
|
2920
|
+
}
|
|
2921
|
+
let routeManifestEntry = {
|
|
2922
|
+
id: route.id,
|
|
2923
|
+
parentId: route.parentId,
|
|
2924
|
+
path: route.path,
|
|
2925
|
+
index: route.index,
|
|
2926
|
+
caseSensitive: route.caseSensitive,
|
|
2927
|
+
hasAction: sourceExports.includes("action"),
|
|
2928
|
+
hasLoader: sourceExports.includes("loader"),
|
|
2929
|
+
hasClientAction,
|
|
2930
|
+
hasClientLoader,
|
|
2931
|
+
hasClientMiddleware,
|
|
2932
|
+
hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
|
|
2933
|
+
...getReactRouterManifestBuildAssets(
|
|
2934
|
+
ctx,
|
|
2935
|
+
viteConfig2,
|
|
2936
|
+
viteManifest,
|
|
2937
|
+
`${routeFile}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
2938
|
+
route
|
|
2939
|
+
),
|
|
2940
|
+
clientActionModule: hasRouteChunkByExportName.clientAction ? getPublicModulePathForEntry(
|
|
2941
|
+
ctx,
|
|
2942
|
+
viteManifest,
|
|
2943
|
+
getRouteChunkModuleId(routeFile, "clientAction")
|
|
2944
|
+
) : void 0,
|
|
2945
|
+
clientLoaderModule: hasRouteChunkByExportName.clientLoader ? getPublicModulePathForEntry(
|
|
2946
|
+
ctx,
|
|
2947
|
+
viteManifest,
|
|
2948
|
+
getRouteChunkModuleId(routeFile, "clientLoader")
|
|
2949
|
+
) : void 0,
|
|
2950
|
+
clientMiddlewareModule: hasRouteChunkByExportName.clientMiddleware ? getPublicModulePathForEntry(
|
|
2951
|
+
ctx,
|
|
2952
|
+
viteManifest,
|
|
2953
|
+
getRouteChunkModuleId(routeFile, "clientMiddleware")
|
|
2954
|
+
) : void 0,
|
|
2955
|
+
hydrateFallbackModule: hasRouteChunkByExportName.HydrateFallback ? getPublicModulePathForEntry(
|
|
2956
|
+
ctx,
|
|
2957
|
+
viteManifest,
|
|
2958
|
+
getRouteChunkModuleId(routeFile, "HydrateFallback")
|
|
2959
|
+
) : void 0
|
|
2960
|
+
};
|
|
2961
|
+
browserRoutes[route.id] = routeManifestEntry;
|
|
2962
|
+
if (!routeIds || routeIds.includes(route.id)) {
|
|
2963
|
+
serverRoutes[route.id] = routeManifestEntry;
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
let fingerprintedValues = { entry, routes: browserRoutes };
|
|
2967
|
+
let version = getHash(JSON.stringify(fingerprintedValues), 8);
|
|
2968
|
+
let manifestPath = path6.posix.join(
|
|
2969
|
+
viteConfig2.build.assetsDir,
|
|
2970
|
+
`manifest-${version}.js`
|
|
2971
|
+
);
|
|
2972
|
+
let url2 = `${ctx.publicPath}${manifestPath}`;
|
|
2973
|
+
let nonFingerprintedValues = { url: url2, version };
|
|
2974
|
+
let reactRouterBrowserManifest = {
|
|
2975
|
+
...fingerprintedValues,
|
|
2976
|
+
...nonFingerprintedValues,
|
|
2977
|
+
sri: void 0
|
|
2978
|
+
};
|
|
2979
|
+
await writeFileSafe(
|
|
2980
|
+
path6.join(getClientBuildDirectory(ctx.reactRouterConfig), manifestPath),
|
|
2981
|
+
`window.__reactRouterManifest=${JSON.stringify(
|
|
2982
|
+
reactRouterBrowserManifest
|
|
2983
|
+
)};`
|
|
2984
|
+
);
|
|
2985
|
+
let sri = void 0;
|
|
2986
|
+
if (ctx.reactRouterConfig.future.unstable_subResourceIntegrity) {
|
|
2987
|
+
sri = await generateSriManifest(ctx);
|
|
2988
|
+
}
|
|
2989
|
+
let reactRouterServerManifest = {
|
|
2990
|
+
...reactRouterBrowserManifest,
|
|
2991
|
+
routes: serverRoutes,
|
|
2992
|
+
sri
|
|
2993
|
+
};
|
|
2994
|
+
return {
|
|
2995
|
+
reactRouterBrowserManifest,
|
|
2996
|
+
reactRouterServerManifest
|
|
2997
|
+
};
|
|
2998
|
+
};
|
|
2999
|
+
let currentReactRouterManifestForDev = null;
|
|
3000
|
+
let getReactRouterManifestForDev = async () => {
|
|
3001
|
+
let routes = {};
|
|
3002
|
+
let routeManifestExports = await getRouteManifestModuleExports(
|
|
3003
|
+
viteChildCompiler,
|
|
3004
|
+
ctx
|
|
3005
|
+
);
|
|
3006
|
+
let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
|
|
3007
|
+
for (let [key, route] of Object.entries(ctx.reactRouterConfig.routes)) {
|
|
3008
|
+
let routeFile = route.file;
|
|
3009
|
+
let sourceExports = routeManifestExports[key];
|
|
3010
|
+
let hasClientAction = sourceExports.includes("clientAction");
|
|
3011
|
+
let hasClientLoader = sourceExports.includes("clientLoader");
|
|
3012
|
+
let hasClientMiddleware = sourceExports.includes("clientMiddleware");
|
|
3013
|
+
let hasHydrateFallback = sourceExports.includes("HydrateFallback");
|
|
3014
|
+
let routeModulePath = combineURLs(
|
|
3015
|
+
ctx.publicPath,
|
|
3016
|
+
`${resolveFileUrl(
|
|
3017
|
+
ctx,
|
|
3018
|
+
resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
|
|
3019
|
+
)}`
|
|
3020
|
+
);
|
|
3021
|
+
if (enforceSplitRouteModules) {
|
|
3022
|
+
let { hasRouteChunkByExportName } = await detectRouteChunksIfEnabled(
|
|
3023
|
+
cache,
|
|
3024
|
+
ctx,
|
|
3025
|
+
routeFile,
|
|
3026
|
+
{ routeFile, viteChildCompiler }
|
|
3027
|
+
);
|
|
3028
|
+
validateRouteChunks({
|
|
3029
|
+
ctx,
|
|
3030
|
+
id: route.file,
|
|
3031
|
+
valid: {
|
|
3032
|
+
clientAction: !hasClientAction || hasRouteChunkByExportName.clientAction,
|
|
3033
|
+
clientLoader: !hasClientLoader || hasRouteChunkByExportName.clientLoader,
|
|
3034
|
+
clientMiddleware: !hasClientMiddleware || hasRouteChunkByExportName.clientMiddleware,
|
|
3035
|
+
HydrateFallback: !hasHydrateFallback || hasRouteChunkByExportName.HydrateFallback
|
|
3036
|
+
}
|
|
3037
|
+
});
|
|
3038
|
+
}
|
|
3039
|
+
routes[key] = {
|
|
3040
|
+
id: route.id,
|
|
3041
|
+
parentId: route.parentId,
|
|
3042
|
+
path: route.path,
|
|
3043
|
+
index: route.index,
|
|
3044
|
+
caseSensitive: route.caseSensitive,
|
|
3045
|
+
module: routeModulePath,
|
|
3046
|
+
// Split route modules are a build-time optimization
|
|
3047
|
+
clientActionModule: void 0,
|
|
3048
|
+
clientLoaderModule: void 0,
|
|
3049
|
+
clientMiddlewareModule: void 0,
|
|
3050
|
+
hydrateFallbackModule: void 0,
|
|
3051
|
+
hasAction: sourceExports.includes("action"),
|
|
3052
|
+
hasLoader: sourceExports.includes("loader"),
|
|
3053
|
+
hasClientAction,
|
|
3054
|
+
hasClientLoader,
|
|
3055
|
+
hasClientMiddleware,
|
|
3056
|
+
hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
|
|
3057
|
+
imports: []
|
|
3058
|
+
};
|
|
3059
|
+
}
|
|
3060
|
+
let sri = void 0;
|
|
3061
|
+
let reactRouterManifestForDev = {
|
|
3062
|
+
version: String(Math.random()),
|
|
3063
|
+
url: combineURLs(ctx.publicPath, virtual.browserManifest.url),
|
|
3064
|
+
hmr: {
|
|
3065
|
+
runtime: combineURLs(ctx.publicPath, virtualInjectHmrRuntime.url)
|
|
3066
|
+
},
|
|
3067
|
+
entry: {
|
|
3068
|
+
module: combineURLs(
|
|
3069
|
+
ctx.publicPath,
|
|
3070
|
+
resolveFileUrl(ctx, ctx.entryClientFilePath)
|
|
3071
|
+
),
|
|
3072
|
+
imports: []
|
|
3073
|
+
},
|
|
3074
|
+
sri,
|
|
3075
|
+
routes
|
|
3076
|
+
};
|
|
3077
|
+
currentReactRouterManifestForDev = reactRouterManifestForDev;
|
|
3078
|
+
return reactRouterManifestForDev;
|
|
3079
|
+
};
|
|
3080
|
+
const loadCssContents = async (viteDevServer, dep) => {
|
|
3081
|
+
invariant(
|
|
3082
|
+
viteCommand === "serve",
|
|
3083
|
+
"loadCssContents is only available in dev mode"
|
|
3084
|
+
);
|
|
3085
|
+
if (dep.file && isCssModulesFile(dep.file)) {
|
|
3086
|
+
return cssModulesManifest[dep.file];
|
|
3087
|
+
}
|
|
3088
|
+
let transformedCssCode = (await viteDevServer.transformRequest(dep.url))?.code;
|
|
3089
|
+
invariant(
|
|
3090
|
+
transformedCssCode,
|
|
3091
|
+
`Failed to load CSS for ${dep.file ?? dep.url}`
|
|
3092
|
+
);
|
|
3093
|
+
let cssString = getCssStringFromViteDevModuleCode(transformedCssCode);
|
|
3094
|
+
invariant(
|
|
3095
|
+
typeof cssString === "string",
|
|
3096
|
+
`Failed to extract CSS for ${dep.file ?? dep.url}`
|
|
3097
|
+
);
|
|
3098
|
+
return cssString;
|
|
3099
|
+
};
|
|
3100
|
+
return [
|
|
3101
|
+
{
|
|
3102
|
+
name: "react-router",
|
|
3103
|
+
config: async (_viteUserConfig, _viteConfigEnv) => {
|
|
3104
|
+
await preloadVite();
|
|
3105
|
+
let vite2 = getVite();
|
|
3106
|
+
viteUserConfig = _viteUserConfig;
|
|
3107
|
+
viteConfigEnv = _viteConfigEnv;
|
|
3108
|
+
viteCommand = viteConfigEnv.command;
|
|
3109
|
+
let viteClientConditions = [
|
|
3110
|
+
...vite2.defaultClientConditions ?? []
|
|
3111
|
+
];
|
|
3112
|
+
logger = vite2.createLogger(viteUserConfig.logLevel, {
|
|
3113
|
+
prefix: "[react-router]"
|
|
3114
|
+
});
|
|
3115
|
+
rootDirectory = viteUserConfig.root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd();
|
|
3116
|
+
let mode = viteConfigEnv.mode;
|
|
3117
|
+
if (viteCommand === "serve") {
|
|
3118
|
+
typegenWatcherPromise = watch(rootDirectory, {
|
|
3119
|
+
mode,
|
|
3120
|
+
// ignore `info` logs from typegen since they are redundant when Vite plugin logs are active
|
|
3121
|
+
logger: vite2.createLogger("warn", { prefix: "[react-router]" })
|
|
3122
|
+
});
|
|
3123
|
+
}
|
|
3124
|
+
reactRouterConfigLoader = await createConfigLoader({
|
|
3125
|
+
rootDirectory,
|
|
3126
|
+
mode,
|
|
3127
|
+
watch: viteCommand === "serve"
|
|
3128
|
+
});
|
|
3129
|
+
await updatePluginContext();
|
|
3130
|
+
Object.assign(
|
|
3131
|
+
process.env,
|
|
3132
|
+
vite2.loadEnv(
|
|
3133
|
+
viteConfigEnv.mode,
|
|
3134
|
+
viteUserConfig.envDir ?? ctx.rootDirectory,
|
|
3135
|
+
// We override the default prefix of "VITE_" with a blank string since
|
|
3136
|
+
// we're targeting the server, so we want to load all environment
|
|
3137
|
+
// variables, not just those explicitly marked for the client
|
|
3138
|
+
""
|
|
3139
|
+
)
|
|
3140
|
+
);
|
|
3141
|
+
let environments = await getEnvironmentsOptions(ctx, viteCommand, {
|
|
3142
|
+
viteUserConfig
|
|
3143
|
+
});
|
|
3144
|
+
let serverEnvironment = getServerEnvironmentValues(
|
|
3145
|
+
ctx,
|
|
3146
|
+
environments
|
|
3147
|
+
)[0];
|
|
3148
|
+
invariant(serverEnvironment);
|
|
3149
|
+
let clientEnvironment = environments.client;
|
|
3150
|
+
invariant(clientEnvironment);
|
|
3151
|
+
return {
|
|
3152
|
+
__reactRouterPluginContext: ctx,
|
|
3153
|
+
appType: viteCommand === "serve" && viteConfigEnv.mode === "production" && ctx.reactRouterConfig.ssr === false ? "spa" : "custom",
|
|
3154
|
+
ssr: {
|
|
3155
|
+
external: serverEnvironment.resolve?.external,
|
|
3156
|
+
resolve: serverEnvironment.resolve
|
|
3157
|
+
},
|
|
3158
|
+
optimizeDeps: {
|
|
3159
|
+
entries: getOptimizeDepsEntries({
|
|
3160
|
+
entryClientFilePath: ctx.entryClientFilePath,
|
|
3161
|
+
reactRouterConfig: ctx.reactRouterConfig
|
|
3162
|
+
}),
|
|
3163
|
+
include: [
|
|
3164
|
+
// Pre-bundle React dependencies to avoid React duplicates,
|
|
3165
|
+
// even if React dependencies are not direct dependencies.
|
|
3166
|
+
// https://react.dev/warnings/invalid-hook-call-warning#duplicate-react
|
|
3167
|
+
"react",
|
|
3168
|
+
"react/jsx-runtime",
|
|
3169
|
+
"react/jsx-dev-runtime",
|
|
3170
|
+
"react-dom",
|
|
3171
|
+
"react-dom/client",
|
|
3172
|
+
// Pre-bundle router dependencies to avoid router duplicates.
|
|
3173
|
+
// Mismatching routers cause `Error: You must render this element inside a <Remix> element`.
|
|
3174
|
+
"react-router",
|
|
3175
|
+
"react-router/dom",
|
|
3176
|
+
// Check to avoid "Failed to resolve dependency: react-router-dom, present in 'optimizeDeps.include'"
|
|
3177
|
+
...hasDependency({
|
|
3178
|
+
name: "react-router-dom",
|
|
3179
|
+
rootDirectory: ctx.rootDirectory
|
|
3180
|
+
}) ? ["react-router-dom"] : []
|
|
3181
|
+
]
|
|
3182
|
+
},
|
|
3183
|
+
esbuild: {
|
|
3184
|
+
jsx: "automatic",
|
|
3185
|
+
jsxDev: viteCommand !== "build"
|
|
3186
|
+
},
|
|
3187
|
+
resolve: {
|
|
3188
|
+
dedupe: [
|
|
3189
|
+
// https://react.dev/warnings/invalid-hook-call-warning#duplicate-react
|
|
3190
|
+
"react",
|
|
3191
|
+
"react-dom",
|
|
3192
|
+
// see description for `optimizeDeps.include`
|
|
3193
|
+
"react-router",
|
|
3194
|
+
"react-router/dom",
|
|
3195
|
+
"react-router-dom"
|
|
3196
|
+
],
|
|
3197
|
+
conditions: viteCommand === "build" ? viteClientConditions : ["development", ...viteClientConditions]
|
|
3198
|
+
},
|
|
3199
|
+
base: viteUserConfig.base,
|
|
3200
|
+
// When consumer provides an allowlist for files that can be read by
|
|
3201
|
+
// the server, ensure that the default entry files are included.
|
|
3202
|
+
// If we don't do this and a default entry file is used, the server
|
|
3203
|
+
// will throw an error that the file is not allowed to be read.
|
|
3204
|
+
// https://vitejs.dev/config/server-options#server-fs-allow
|
|
3205
|
+
server: viteUserConfig.server?.fs?.allow ? { fs: { allow: defaultEntries } } : void 0,
|
|
3206
|
+
...ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? {
|
|
3207
|
+
environments,
|
|
3208
|
+
build: {
|
|
3209
|
+
// This isn't honored by the SSR environment config (which seems
|
|
3210
|
+
// to be a Vite bug?) so we set it here too.
|
|
3211
|
+
ssrEmitAssets: true
|
|
3212
|
+
},
|
|
3213
|
+
builder: {
|
|
3214
|
+
sharedConfigBuild: true,
|
|
3215
|
+
sharedPlugins: true,
|
|
3216
|
+
async buildApp(builder) {
|
|
3217
|
+
invariant(viteConfig);
|
|
3218
|
+
viteConfig.logger.info(
|
|
3219
|
+
"Using Vite Environment API (experimental)"
|
|
3220
|
+
);
|
|
3221
|
+
let { reactRouterConfig } = ctx;
|
|
3222
|
+
await cleanBuildDirectory(viteConfig, ctx);
|
|
3223
|
+
await builder.build(builder.environments.client);
|
|
3224
|
+
let serverEnvironments = getServerEnvironmentValues(
|
|
3225
|
+
ctx,
|
|
3226
|
+
builder.environments
|
|
3227
|
+
);
|
|
3228
|
+
await Promise.all(serverEnvironments.map(builder.build));
|
|
3229
|
+
await cleanViteManifests(environments, ctx);
|
|
3230
|
+
let { buildManifest } = ctx;
|
|
3231
|
+
invariant(buildManifest, "Expected build manifest");
|
|
3232
|
+
await reactRouterConfig.buildEnd?.({
|
|
3233
|
+
buildManifest,
|
|
3234
|
+
reactRouterConfig,
|
|
3235
|
+
viteConfig
|
|
3236
|
+
});
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
} : {
|
|
3240
|
+
build: ctx.environmentBuildContext?.options.build ?? (viteConfigEnv.isSsrBuild ? serverEnvironment.build : clientEnvironment.build)
|
|
3241
|
+
}
|
|
3242
|
+
};
|
|
3243
|
+
},
|
|
3244
|
+
configEnvironment(name, options) {
|
|
3245
|
+
if (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi && (ctx.buildManifest?.serverBundles ? isSsrBundleEnvironmentName(name) : name === "ssr")) {
|
|
3246
|
+
const vite2 = getVite();
|
|
3247
|
+
return {
|
|
3248
|
+
resolve: {
|
|
3249
|
+
external: (
|
|
3250
|
+
// This check is required to honor the "noExternal: true" config
|
|
3251
|
+
// provided by vite-plugin-cloudflare within this repo. When compiling
|
|
3252
|
+
// for Cloudflare, all server dependencies are pre-bundled, but our
|
|
3253
|
+
// `ssrExternals` config inadvertently overrides this. This doesn't
|
|
3254
|
+
// impact consumers because for them `ssrExternals` is undefined and
|
|
3255
|
+
// Cloudflare's "noExternal: true" config remains intact.
|
|
3256
|
+
options.resolve?.noExternal === true ? void 0 : ssrExternals
|
|
3257
|
+
)
|
|
3258
|
+
},
|
|
3259
|
+
optimizeDeps: options.optimizeDeps?.noDiscovery === false ? {
|
|
3260
|
+
entries: [
|
|
3261
|
+
vite2.normalizePath(ctx.entryServerFilePath),
|
|
3262
|
+
...Object.values(ctx.reactRouterConfig.routes).map(
|
|
3263
|
+
(route) => resolveRelativeRouteFilePath(
|
|
3264
|
+
route,
|
|
3265
|
+
ctx.reactRouterConfig
|
|
3266
|
+
)
|
|
3267
|
+
)
|
|
3268
|
+
],
|
|
3269
|
+
include: [
|
|
3270
|
+
"react",
|
|
3271
|
+
"react/jsx-dev-runtime",
|
|
3272
|
+
"react-dom/server",
|
|
3273
|
+
"react-router"
|
|
3274
|
+
]
|
|
3275
|
+
} : void 0
|
|
3276
|
+
};
|
|
3277
|
+
}
|
|
3278
|
+
},
|
|
3279
|
+
async configResolved(resolvedViteConfig) {
|
|
3280
|
+
await import_es_module_lexer.init;
|
|
3281
|
+
viteConfig = resolvedViteConfig;
|
|
3282
|
+
invariant(viteConfig);
|
|
3283
|
+
if (!viteConfig.configFile) {
|
|
3284
|
+
throw new Error(
|
|
3285
|
+
"The React Router Vite plugin requires the use of a Vite config file"
|
|
3286
|
+
);
|
|
3287
|
+
}
|
|
3288
|
+
let vite2 = getVite();
|
|
3289
|
+
let childCompilerConfigFile = await vite2.loadConfigFromFile(
|
|
3290
|
+
{
|
|
3291
|
+
command: viteConfig.command,
|
|
3292
|
+
mode: viteConfig.mode
|
|
3293
|
+
},
|
|
3294
|
+
viteConfig.configFile
|
|
3295
|
+
);
|
|
3296
|
+
invariant(
|
|
3297
|
+
childCompilerConfigFile,
|
|
3298
|
+
"Vite config file was unable to be resolved for React Router child compiler"
|
|
3299
|
+
);
|
|
3300
|
+
const childCompilerPlugins = await asyncFlatten(
|
|
3301
|
+
childCompilerConfigFile.config.plugins ?? []
|
|
3302
|
+
);
|
|
3303
|
+
viteChildCompiler = await vite2.createServer({
|
|
3304
|
+
...viteUserConfig,
|
|
3305
|
+
// Ensure child compiler cannot overwrite the default cache directory
|
|
3306
|
+
cacheDir: "node_modules/.vite-child-compiler",
|
|
3307
|
+
mode: viteConfig.mode,
|
|
3308
|
+
server: {
|
|
3309
|
+
watch: viteConfig.command === "build" ? null : viteConfig.server.watch,
|
|
3310
|
+
preTransformRequests: false,
|
|
3311
|
+
hmr: false
|
|
3312
|
+
},
|
|
3313
|
+
configFile: false,
|
|
3314
|
+
envFile: false,
|
|
3315
|
+
plugins: [
|
|
3316
|
+
childCompilerPlugins.filter(
|
|
3317
|
+
(plugin) => typeof plugin === "object" && plugin !== null && "name" in plugin && plugin.name !== "react-router" && plugin.name !== "react-router:route-exports" && plugin.name !== "react-router:hmr-updates" && plugin.name !== "react-router:validate-plugin-order"
|
|
3318
|
+
).map((plugin) => ({
|
|
3319
|
+
...plugin,
|
|
3320
|
+
configureServer: void 0,
|
|
3321
|
+
configurePreviewServer: void 0
|
|
3322
|
+
}))
|
|
3323
|
+
]
|
|
3324
|
+
});
|
|
3325
|
+
await viteChildCompiler.pluginContainer.buildStart({});
|
|
3326
|
+
},
|
|
3327
|
+
async transform(code, id) {
|
|
3328
|
+
if (isCssModulesFile(id)) {
|
|
3329
|
+
cssModulesManifest[id] = code;
|
|
3330
|
+
}
|
|
3331
|
+
},
|
|
3332
|
+
buildStart() {
|
|
3333
|
+
invariant(viteConfig);
|
|
3334
|
+
if (viteCommand === "build" && viteConfig.mode === "production" && !viteConfig.build.ssr && viteConfig.build.sourcemap) {
|
|
3335
|
+
viteConfig.logger.warn(
|
|
3336
|
+
import_picocolors3.default.yellow(
|
|
3337
|
+
"\n" + import_picocolors3.default.bold(" \u26A0\uFE0F Source maps are enabled in production\n") + [
|
|
3338
|
+
"This makes your server code publicly",
|
|
3339
|
+
"visible in the browser. This is highly",
|
|
3340
|
+
"discouraged! If you insist, ensure that",
|
|
3341
|
+
"you are using environment variables for",
|
|
3342
|
+
"secrets and not hard-coding them in",
|
|
3343
|
+
"your source code."
|
|
3344
|
+
].map((line) => " " + line).join("\n") + "\n"
|
|
3345
|
+
)
|
|
3346
|
+
);
|
|
3347
|
+
}
|
|
3348
|
+
},
|
|
3349
|
+
async configureServer(viteDevServer) {
|
|
3350
|
+
(0, import_react_router2.unstable_setDevServerHooks)({
|
|
3351
|
+
// Give the request handler access to the critical CSS in dev to avoid a
|
|
3352
|
+
// flash of unstyled content since Vite injects CSS file contents via JS
|
|
3353
|
+
getCriticalCss: async (pathname) => {
|
|
3354
|
+
return getStylesForPathname({
|
|
3355
|
+
rootDirectory: ctx.rootDirectory,
|
|
3356
|
+
entryClientFilePath: ctx.entryClientFilePath,
|
|
3357
|
+
reactRouterConfig: ctx.reactRouterConfig,
|
|
3358
|
+
viteDevServer,
|
|
3359
|
+
loadCssContents,
|
|
3360
|
+
pathname
|
|
3361
|
+
});
|
|
3362
|
+
},
|
|
3363
|
+
// If an error is caught within the request handler, let Vite fix the
|
|
3364
|
+
// stack trace so it maps back to the actual source code
|
|
3365
|
+
processRequestError: (error) => {
|
|
3366
|
+
if (error instanceof Error) {
|
|
3367
|
+
viteDevServer.ssrFixStacktrace(error);
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
});
|
|
3371
|
+
reactRouterConfigLoader.onChange(
|
|
3372
|
+
async ({
|
|
3373
|
+
result,
|
|
3374
|
+
configCodeChanged,
|
|
3375
|
+
routeConfigCodeChanged,
|
|
3376
|
+
configChanged,
|
|
3377
|
+
routeConfigChanged
|
|
3378
|
+
}) => {
|
|
3379
|
+
if (!result.ok) {
|
|
3380
|
+
invalidateVirtualModules(viteDevServer);
|
|
3381
|
+
logger.error(result.error, {
|
|
3382
|
+
clear: true,
|
|
3383
|
+
timestamp: true
|
|
3384
|
+
});
|
|
3385
|
+
return;
|
|
3386
|
+
}
|
|
3387
|
+
let message = configChanged ? "Config changed." : routeConfigChanged ? "Route config changed." : configCodeChanged ? "Config saved." : routeConfigCodeChanged ? " Route config saved." : "Config saved";
|
|
3388
|
+
logger.info(import_picocolors3.default.green(message), {
|
|
3389
|
+
clear: true,
|
|
3390
|
+
timestamp: true
|
|
3391
|
+
});
|
|
3392
|
+
await updatePluginContext();
|
|
3393
|
+
if (configChanged || routeConfigChanged) {
|
|
3394
|
+
invalidateVirtualModules(viteDevServer);
|
|
3395
|
+
}
|
|
3396
|
+
}
|
|
3397
|
+
);
|
|
3398
|
+
if (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi) {
|
|
3399
|
+
viteDevServer.middlewares.use(async (req, res, next) => {
|
|
3400
|
+
let [reqPathname, reqSearch] = (req.url ?? "").split("?");
|
|
3401
|
+
if (reqPathname.endsWith("/@react-router/critical.css")) {
|
|
3402
|
+
let pathname = new URLSearchParams(reqSearch).get("pathname");
|
|
3403
|
+
if (!pathname) {
|
|
3404
|
+
return next("No pathname provided");
|
|
3405
|
+
}
|
|
3406
|
+
let css = await getStylesForPathname({
|
|
3407
|
+
rootDirectory: ctx.rootDirectory,
|
|
3408
|
+
entryClientFilePath: ctx.entryClientFilePath,
|
|
3409
|
+
reactRouterConfig: ctx.reactRouterConfig,
|
|
3410
|
+
viteDevServer,
|
|
3411
|
+
loadCssContents,
|
|
3412
|
+
pathname
|
|
3413
|
+
});
|
|
3414
|
+
res.setHeader("Content-Type", "text/css");
|
|
3415
|
+
res.end(css);
|
|
3416
|
+
} else {
|
|
3417
|
+
next();
|
|
3418
|
+
}
|
|
3419
|
+
});
|
|
3420
|
+
}
|
|
3421
|
+
return () => {
|
|
3422
|
+
if (!viteDevServer.config.server.middlewareMode) {
|
|
3423
|
+
viteDevServer.middlewares.use(async (req, res, next) => {
|
|
3424
|
+
try {
|
|
3425
|
+
let build;
|
|
3426
|
+
if (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi) {
|
|
3427
|
+
let vite2 = getVite();
|
|
3428
|
+
let ssrEnvironment = viteDevServer.environments.ssr;
|
|
3429
|
+
if (!vite2.isRunnableDevEnvironment(ssrEnvironment)) {
|
|
3430
|
+
next();
|
|
3431
|
+
return;
|
|
3432
|
+
}
|
|
3433
|
+
build = await ssrEnvironment.runner.import(
|
|
3434
|
+
virtual.serverBuild.id
|
|
3435
|
+
);
|
|
3436
|
+
} else {
|
|
3437
|
+
build = await viteDevServer.ssrLoadModule(
|
|
3438
|
+
virtual.serverBuild.id
|
|
3439
|
+
);
|
|
3440
|
+
}
|
|
3441
|
+
let handler = (0, import_react_router2.createRequestHandler)(build, "development");
|
|
3442
|
+
let nodeHandler = async (nodeReq, nodeRes) => {
|
|
3443
|
+
let req2 = fromNodeRequest(nodeReq, nodeRes);
|
|
3444
|
+
let res2 = await handler(
|
|
3445
|
+
req2,
|
|
3446
|
+
await reactRouterDevLoadContext(req2)
|
|
3447
|
+
);
|
|
3448
|
+
await toNodeRequest(res2, nodeRes);
|
|
3449
|
+
};
|
|
3450
|
+
await nodeHandler(req, res);
|
|
3451
|
+
} catch (error) {
|
|
3452
|
+
next(error);
|
|
3453
|
+
}
|
|
3454
|
+
});
|
|
3455
|
+
}
|
|
3456
|
+
};
|
|
3457
|
+
},
|
|
3458
|
+
writeBundle: {
|
|
3459
|
+
// After the SSR build is finished, we inspect the Vite manifest for
|
|
3460
|
+
// the SSR build and move server-only assets to client assets directory
|
|
3461
|
+
async handler() {
|
|
3462
|
+
let { future } = ctx.reactRouterConfig;
|
|
3463
|
+
if (future.unstable_viteEnvironmentApi ? this.environment.name === "client" : !viteConfigEnv.isSsrBuild) {
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3466
|
+
invariant(viteConfig);
|
|
3467
|
+
let clientBuildDirectory = getClientBuildDirectory(
|
|
3468
|
+
ctx.reactRouterConfig
|
|
3469
|
+
);
|
|
3470
|
+
let serverBuildDirectory = future.unstable_viteEnvironmentApi ? this.environment.config?.build?.outDir : ctx.environmentBuildContext?.options.build?.outDir ?? getServerBuildDirectory(ctx.reactRouterConfig);
|
|
3471
|
+
let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
|
|
3472
|
+
let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
|
|
3473
|
+
let userSsrEmitAssets = (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig.environments?.ssr?.build?.ssrEmitAssets ?? viteUserConfig.environments?.ssr?.build?.emitAssets : null) ?? viteUserConfig.build?.ssrEmitAssets ?? false;
|
|
3474
|
+
let movedAssetPaths = [];
|
|
3475
|
+
let removedAssetPaths = [];
|
|
3476
|
+
let copiedAssetPaths = [];
|
|
3477
|
+
for (let ssrAssetPath of ssrAssetPaths) {
|
|
3478
|
+
let src = path6.join(serverBuildDirectory, ssrAssetPath);
|
|
3479
|
+
let dest = path6.join(clientBuildDirectory, ssrAssetPath);
|
|
3480
|
+
if (!userSsrEmitAssets) {
|
|
3481
|
+
if (!(0, import_node_fs2.existsSync)(dest)) {
|
|
3482
|
+
await (0, import_promises2.mkdir)(path6.dirname(dest), { recursive: true });
|
|
3483
|
+
await (0, import_promises2.rename)(src, dest);
|
|
3484
|
+
movedAssetPaths.push(dest);
|
|
3485
|
+
} else {
|
|
3486
|
+
await (0, import_promises2.rm)(src, { force: true, recursive: true });
|
|
3487
|
+
removedAssetPaths.push(dest);
|
|
3488
|
+
}
|
|
3489
|
+
} else if (!(0, import_node_fs2.existsSync)(dest)) {
|
|
3490
|
+
await (0, import_promises2.cp)(src, dest, { recursive: true });
|
|
3491
|
+
copiedAssetPaths.push(dest);
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
if (!userSsrEmitAssets) {
|
|
3495
|
+
let ssrCssPaths = Object.values(ssrViteManifest).flatMap(
|
|
3496
|
+
(chunk) => chunk.css ?? []
|
|
3497
|
+
);
|
|
3498
|
+
await Promise.all(
|
|
3499
|
+
ssrCssPaths.map(async (cssPath) => {
|
|
3500
|
+
let src = path6.join(serverBuildDirectory, cssPath);
|
|
3501
|
+
await (0, import_promises2.rm)(src, { force: true, recursive: true });
|
|
3502
|
+
removedAssetPaths.push(src);
|
|
3503
|
+
})
|
|
3504
|
+
);
|
|
3505
|
+
}
|
|
3506
|
+
let cleanedAssetPaths = [...removedAssetPaths, ...movedAssetPaths];
|
|
3507
|
+
let handledAssetPaths = [...cleanedAssetPaths, ...copiedAssetPaths];
|
|
3508
|
+
let cleanedAssetDirs = new Set(cleanedAssetPaths.map(path6.dirname));
|
|
3509
|
+
await Promise.all(
|
|
3510
|
+
Array.from(cleanedAssetDirs).map(async (dir) => {
|
|
3511
|
+
try {
|
|
3512
|
+
const files = await (0, import_promises2.readdir)(dir, { recursive: true });
|
|
3513
|
+
if (files.length === 0) {
|
|
3514
|
+
await (0, import_promises2.rm)(dir, { force: true, recursive: true });
|
|
3515
|
+
}
|
|
3516
|
+
} catch {
|
|
3517
|
+
}
|
|
3518
|
+
})
|
|
3519
|
+
);
|
|
3520
|
+
if (handledAssetPaths.length) {
|
|
3521
|
+
viteConfig.logger.info("");
|
|
3522
|
+
}
|
|
3523
|
+
function logHandledAssets(paths, message) {
|
|
3524
|
+
invariant(viteConfig);
|
|
3525
|
+
if (paths.length) {
|
|
3526
|
+
viteConfig.logger.info(
|
|
3527
|
+
[
|
|
3528
|
+
`${import_picocolors3.default.green("\u2713")} ${message}`,
|
|
3529
|
+
...paths.map(
|
|
3530
|
+
(assetPath) => import_picocolors3.default.dim(path6.relative(ctx.rootDirectory, assetPath))
|
|
3531
|
+
)
|
|
3532
|
+
].join("\n")
|
|
3533
|
+
);
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
logHandledAssets(
|
|
3537
|
+
removedAssetPaths,
|
|
3538
|
+
`${removedAssetPaths.length} asset${removedAssetPaths.length > 1 ? "s" : ""} cleaned from React Router server build.`
|
|
3539
|
+
);
|
|
3540
|
+
logHandledAssets(
|
|
3541
|
+
movedAssetPaths,
|
|
3542
|
+
`${movedAssetPaths.length} asset${movedAssetPaths.length > 1 ? "s" : ""} moved from React Router server build to client assets.`
|
|
3543
|
+
);
|
|
3544
|
+
logHandledAssets(
|
|
3545
|
+
copiedAssetPaths,
|
|
3546
|
+
`${copiedAssetPaths.length} asset${copiedAssetPaths.length > 1 ? "s" : ""} copied from React Router server build to client assets.`
|
|
3547
|
+
);
|
|
3548
|
+
if (handledAssetPaths.length) {
|
|
3549
|
+
viteConfig.logger.info("");
|
|
3550
|
+
}
|
|
3551
|
+
process.env.IS_RR_BUILD_REQUEST = "yes";
|
|
3552
|
+
if (isPrerenderingEnabled(ctx.reactRouterConfig)) {
|
|
3553
|
+
await handlePrerender(
|
|
3554
|
+
viteConfig,
|
|
3555
|
+
ctx.reactRouterConfig,
|
|
3556
|
+
serverBuildDirectory,
|
|
3557
|
+
getServerBuildFile(ssrViteManifest),
|
|
3558
|
+
clientBuildDirectory
|
|
3559
|
+
);
|
|
3560
|
+
}
|
|
3561
|
+
if (!ctx.reactRouterConfig.ssr) {
|
|
3562
|
+
await handleSpaMode(
|
|
3563
|
+
viteConfig,
|
|
3564
|
+
ctx.reactRouterConfig,
|
|
3565
|
+
serverBuildDirectory,
|
|
3566
|
+
getServerBuildFile(ssrViteManifest),
|
|
3567
|
+
clientBuildDirectory
|
|
3568
|
+
);
|
|
3569
|
+
}
|
|
3570
|
+
if (!ctx.reactRouterConfig.ssr) {
|
|
3571
|
+
viteConfig.logger.info(
|
|
3572
|
+
[
|
|
3573
|
+
"Removing the server build in",
|
|
3574
|
+
import_picocolors3.default.green(serverBuildDirectory),
|
|
3575
|
+
"due to ssr:false"
|
|
3576
|
+
].join(" ")
|
|
3577
|
+
);
|
|
3578
|
+
(0, import_node_fs2.rmSync)(serverBuildDirectory, { force: true, recursive: true });
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
},
|
|
3582
|
+
async buildEnd() {
|
|
3583
|
+
await viteChildCompiler?.close();
|
|
3584
|
+
await reactRouterConfigLoader.close();
|
|
3585
|
+
let typegenWatcher = await typegenWatcherPromise;
|
|
3586
|
+
await typegenWatcher?.close();
|
|
3587
|
+
}
|
|
3588
|
+
},
|
|
3589
|
+
{
|
|
3590
|
+
name: "react-router:route-chunks-index",
|
|
3591
|
+
// This plugin provides the route module "index" since route modules can
|
|
3592
|
+
// be chunked and may be made up of multiple smaller modules. This plugin
|
|
3593
|
+
// primarily ensures code is never duplicated across a route module and
|
|
3594
|
+
// its chunks. If we didn't have this plugin, any app that explicitly
|
|
3595
|
+
// imports a route module would result in duplicate code since the app
|
|
3596
|
+
// would contain code for both the unprocessed route module and its
|
|
3597
|
+
// individual chunks. This is because, since they have different module
|
|
3598
|
+
// IDs, they are treated as completely separate modules even though they
|
|
3599
|
+
// all reference the same underlying file. This plugin addresses this by
|
|
3600
|
+
// ensuring that any explicit imports of a route module resolve to a
|
|
3601
|
+
// module that simply re-exports from its underlying chunks, if present.
|
|
3602
|
+
async transform(code, id, options) {
|
|
3603
|
+
if (viteCommand !== "build") return;
|
|
3604
|
+
if (options?.ssr) {
|
|
3605
|
+
return;
|
|
3606
|
+
}
|
|
3607
|
+
if (!isRoute(ctx.reactRouterConfig, id)) {
|
|
3608
|
+
return;
|
|
3609
|
+
}
|
|
3610
|
+
if (isRouteVirtualModule(id)) {
|
|
3611
|
+
return;
|
|
3612
|
+
}
|
|
3613
|
+
let { hasRouteChunks, chunkedExports } = await detectRouteChunksIfEnabled(cache, ctx, id, code);
|
|
3614
|
+
if (!hasRouteChunks) {
|
|
3615
|
+
return;
|
|
3616
|
+
}
|
|
3617
|
+
let sourceExports = await getRouteModuleExports(
|
|
3618
|
+
viteChildCompiler,
|
|
3619
|
+
ctx,
|
|
3620
|
+
id
|
|
3621
|
+
);
|
|
3622
|
+
let isMainChunkExport = (name) => !chunkedExports.includes(name);
|
|
3623
|
+
let mainChunkReexports = sourceExports.filter(isMainChunkExport).join(", ");
|
|
3624
|
+
let chunkBasePath = `./${path6.basename(id)}`;
|
|
3625
|
+
return [
|
|
3626
|
+
`export { ${mainChunkReexports} } from "${getRouteChunkModuleId(
|
|
3627
|
+
chunkBasePath,
|
|
3628
|
+
"main"
|
|
3629
|
+
)}";`,
|
|
3630
|
+
...chunkedExports.map(
|
|
3631
|
+
(exportName) => `export { ${exportName} } from "${getRouteChunkModuleId(
|
|
3632
|
+
chunkBasePath,
|
|
3633
|
+
exportName
|
|
3634
|
+
)}";`
|
|
3635
|
+
)
|
|
3636
|
+
].filter(Boolean).join("\n");
|
|
3637
|
+
}
|
|
3638
|
+
},
|
|
3639
|
+
{
|
|
3640
|
+
name: "react-router:build-client-route",
|
|
3641
|
+
async transform(code, id, options) {
|
|
3642
|
+
if (!id.endsWith(BUILD_CLIENT_ROUTE_QUERY_STRING)) return;
|
|
3643
|
+
let routeModuleId = id.replace(BUILD_CLIENT_ROUTE_QUERY_STRING, "");
|
|
3644
|
+
let routeFileName = path6.basename(routeModuleId);
|
|
3645
|
+
let sourceExports = await getRouteModuleExports(
|
|
3646
|
+
viteChildCompiler,
|
|
3647
|
+
ctx,
|
|
3648
|
+
routeModuleId
|
|
3649
|
+
);
|
|
3650
|
+
let { chunkedExports = [] } = options?.ssr ? {} : await detectRouteChunksIfEnabled(cache, ctx, id, code);
|
|
3651
|
+
let reexports = sourceExports.filter((exportName) => {
|
|
3652
|
+
let isRouteEntryExport = options?.ssr && SERVER_ONLY_ROUTE_EXPORTS.includes(exportName) || CLIENT_ROUTE_EXPORTS.includes(exportName);
|
|
3653
|
+
let isChunkedExport = chunkedExports.includes(
|
|
3654
|
+
exportName
|
|
3655
|
+
);
|
|
3656
|
+
return isRouteEntryExport && !isChunkedExport;
|
|
3657
|
+
}).join(", ");
|
|
3658
|
+
return `export { ${reexports} } from "./${routeFileName}";`;
|
|
3659
|
+
}
|
|
3660
|
+
},
|
|
3661
|
+
{
|
|
3662
|
+
name: "react-router:split-route-modules",
|
|
3663
|
+
async transform(code, id, options) {
|
|
3664
|
+
if (options?.ssr) return;
|
|
3665
|
+
if (!isRouteChunkModuleId(id)) return;
|
|
3666
|
+
invariant(
|
|
3667
|
+
viteCommand === "build",
|
|
3668
|
+
"Route modules are only split in build mode"
|
|
3669
|
+
);
|
|
3670
|
+
let chunkName = getRouteChunkNameFromModuleId(id);
|
|
3671
|
+
if (!chunkName) {
|
|
3672
|
+
throw new Error(`Invalid route chunk name "${chunkName}" in "${id}"`);
|
|
3673
|
+
}
|
|
3674
|
+
let chunk = await getRouteChunkIfEnabled(
|
|
3675
|
+
cache,
|
|
3676
|
+
ctx,
|
|
3677
|
+
id,
|
|
3678
|
+
chunkName,
|
|
3679
|
+
code
|
|
3680
|
+
);
|
|
3681
|
+
let preventEmptyChunkSnippet = ({ reason }) => `Math.random()<0&&console.log(${JSON.stringify(reason)});`;
|
|
3682
|
+
if (chunk === null) {
|
|
3683
|
+
return preventEmptyChunkSnippet({
|
|
3684
|
+
reason: "Split round modules disabled"
|
|
3685
|
+
});
|
|
3686
|
+
}
|
|
3687
|
+
let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
|
|
3688
|
+
if (enforceSplitRouteModules && chunkName === "main" && chunk) {
|
|
3689
|
+
let exportNames = getExportNames(chunk.code);
|
|
3690
|
+
validateRouteChunks({
|
|
3691
|
+
ctx,
|
|
3692
|
+
id,
|
|
3693
|
+
valid: {
|
|
3694
|
+
clientAction: !exportNames.includes("clientAction"),
|
|
3695
|
+
clientLoader: !exportNames.includes("clientLoader"),
|
|
3696
|
+
clientMiddleware: !exportNames.includes("clientMiddleware"),
|
|
3697
|
+
HydrateFallback: !exportNames.includes("HydrateFallback")
|
|
3698
|
+
}
|
|
3699
|
+
});
|
|
3700
|
+
}
|
|
3701
|
+
return chunk ?? preventEmptyChunkSnippet({ reason: `No ${chunkName} chunk` });
|
|
3702
|
+
}
|
|
3703
|
+
},
|
|
3704
|
+
{
|
|
3705
|
+
name: "react-router:virtual-modules",
|
|
3706
|
+
enforce: "pre",
|
|
3707
|
+
resolveId(id) {
|
|
3708
|
+
const vmod = Object.values(virtual).find((vmod2) => vmod2.id === id);
|
|
3709
|
+
if (vmod) return vmod.resolvedId;
|
|
3710
|
+
},
|
|
3711
|
+
async load(id) {
|
|
3712
|
+
switch (id) {
|
|
3713
|
+
case virtual.serverBuild.resolvedId: {
|
|
3714
|
+
let routeIds = getServerBundleRouteIds(this, ctx);
|
|
3715
|
+
return await getServerEntry({ routeIds });
|
|
3716
|
+
}
|
|
3717
|
+
case virtual.serverManifest.resolvedId: {
|
|
3718
|
+
let routeIds = getServerBundleRouteIds(this, ctx);
|
|
3719
|
+
invariant(viteConfig);
|
|
3720
|
+
let reactRouterManifest = viteCommand === "build" ? (await generateReactRouterManifestsForBuild({
|
|
3721
|
+
viteConfig,
|
|
3722
|
+
routeIds
|
|
3723
|
+
})).reactRouterServerManifest : await getReactRouterManifestForDev();
|
|
3724
|
+
if (!ctx.reactRouterConfig.ssr) {
|
|
3725
|
+
invariant(viteConfig);
|
|
3726
|
+
validateSsrFalsePrerenderExports(
|
|
3727
|
+
viteConfig,
|
|
3728
|
+
ctx,
|
|
3729
|
+
reactRouterManifest,
|
|
3730
|
+
viteChildCompiler
|
|
3731
|
+
);
|
|
3732
|
+
}
|
|
3733
|
+
return `export default ${(0, import_jsesc.default)(reactRouterManifest, {
|
|
3734
|
+
es6: true
|
|
3735
|
+
})};`;
|
|
3736
|
+
}
|
|
3737
|
+
case virtual.browserManifest.resolvedId: {
|
|
3738
|
+
if (viteCommand === "build") {
|
|
3739
|
+
throw new Error("This module only exists in development");
|
|
3740
|
+
}
|
|
3741
|
+
let reactRouterManifest = await getReactRouterManifestForDev();
|
|
3742
|
+
let reactRouterManifestString = (0, import_jsesc.default)(reactRouterManifest, {
|
|
3743
|
+
es6: true
|
|
3744
|
+
});
|
|
3745
|
+
return `window.__reactRouterManifest=${reactRouterManifestString};`;
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
}
|
|
3749
|
+
},
|
|
3750
|
+
{
|
|
3751
|
+
name: "react-router:dot-server",
|
|
3752
|
+
enforce: "pre",
|
|
3753
|
+
async resolveId(id, importer, options) {
|
|
3754
|
+
let isOptimizeDeps = viteCommand === "serve" && options?.scan === true;
|
|
3755
|
+
if (isOptimizeDeps || options?.ssr) return;
|
|
3756
|
+
let isResolving = options?.custom?.["react-router:dot-server"] ?? false;
|
|
3757
|
+
if (isResolving) return;
|
|
3758
|
+
options.custom = { ...options.custom, "react-router:dot-server": true };
|
|
3759
|
+
let resolved = await this.resolve(id, importer, options);
|
|
3760
|
+
if (!resolved) return;
|
|
3761
|
+
let serverFileRE = /\.server(\.[cm]?[jt]sx?)?$/;
|
|
3762
|
+
let serverDirRE = /\/\.server\//;
|
|
3763
|
+
let isDotServer = serverFileRE.test(resolved.id) || serverDirRE.test(resolved.id);
|
|
3764
|
+
if (!isDotServer) return;
|
|
3765
|
+
if (!importer) return;
|
|
3766
|
+
if (viteCommand !== "build" && importer.endsWith(".html")) {
|
|
3767
|
+
return;
|
|
3768
|
+
}
|
|
3769
|
+
let vite2 = getVite();
|
|
3770
|
+
let importerShort = vite2.normalizePath(
|
|
3771
|
+
path6.relative(ctx.rootDirectory, importer)
|
|
3772
|
+
);
|
|
3773
|
+
if (isRoute(ctx.reactRouterConfig, importer)) {
|
|
3774
|
+
let serverOnlyExports = SERVER_ONLY_ROUTE_EXPORTS.map(
|
|
3775
|
+
(xport) => `\`${xport}\``
|
|
3776
|
+
).join(", ");
|
|
3777
|
+
throw Error(
|
|
3778
|
+
[
|
|
3779
|
+
import_picocolors3.default.red(`Server-only module referenced by client`),
|
|
3780
|
+
"",
|
|
3781
|
+
` '${id}' imported by route '${importerShort}'`,
|
|
3782
|
+
"",
|
|
3783
|
+
` React Router automatically removes server-code from these exports:`,
|
|
3784
|
+
` ${serverOnlyExports}`,
|
|
3785
|
+
"",
|
|
3786
|
+
` But other route exports in '${importerShort}' depend on '${id}'.`,
|
|
3787
|
+
"",
|
|
3788
|
+
" See https://remix.run/docs/en/main/guides/vite#splitting-up-client-and-server-code",
|
|
3789
|
+
""
|
|
3790
|
+
].join("\n")
|
|
3791
|
+
);
|
|
3792
|
+
}
|
|
3793
|
+
throw Error(
|
|
3794
|
+
[
|
|
3795
|
+
import_picocolors3.default.red(`Server-only module referenced by client`),
|
|
3796
|
+
"",
|
|
3797
|
+
` '${id}' imported by '${importerShort}'`,
|
|
3798
|
+
"",
|
|
3799
|
+
" See https://remix.run/docs/en/main/guides/vite#splitting-up-client-and-server-code",
|
|
3800
|
+
""
|
|
3801
|
+
].join("\n")
|
|
3802
|
+
);
|
|
3803
|
+
}
|
|
3804
|
+
},
|
|
3805
|
+
{
|
|
3806
|
+
name: "react-router:dot-client",
|
|
3807
|
+
async transform(code, id, options) {
|
|
3808
|
+
if (!options?.ssr) return;
|
|
3809
|
+
let clientFileRE = /\.client(\.[cm]?[jt]sx?)?$/;
|
|
3810
|
+
let clientDirRE = /\/\.client\//;
|
|
3811
|
+
if (clientFileRE.test(id) || clientDirRE.test(id)) {
|
|
3812
|
+
let exports2 = getExportNames(code);
|
|
3813
|
+
return {
|
|
3814
|
+
code: exports2.map(
|
|
3815
|
+
(name) => name === "default" ? "export default undefined;" : `export const ${name} = undefined;`
|
|
3816
|
+
).join("\n"),
|
|
3817
|
+
map: null
|
|
3818
|
+
};
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
},
|
|
3822
|
+
{
|
|
3823
|
+
name: "react-router:route-exports",
|
|
3824
|
+
async transform(code, id, options) {
|
|
3825
|
+
if (isRouteChunkModuleId(id)) {
|
|
3826
|
+
id = id.split("?")[0];
|
|
3827
|
+
}
|
|
3828
|
+
let route = getRoute(ctx.reactRouterConfig, id);
|
|
3829
|
+
if (!route) return;
|
|
3830
|
+
if (!options?.ssr && isSpaModeEnabled(ctx.reactRouterConfig)) {
|
|
3831
|
+
let exportNames = getExportNames(code);
|
|
3832
|
+
let serverOnlyExports = exportNames.filter((exp) => {
|
|
3833
|
+
if (route.id === "root" && exp === "loader") {
|
|
3834
|
+
return false;
|
|
3835
|
+
}
|
|
3836
|
+
return SERVER_ONLY_ROUTE_EXPORTS.includes(exp);
|
|
3837
|
+
});
|
|
3838
|
+
if (serverOnlyExports.length > 0) {
|
|
3839
|
+
let str = serverOnlyExports.map((e) => `\`${e}\``).join(", ");
|
|
3840
|
+
let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://reactrouter.com/how-to/spa for more information.`;
|
|
3841
|
+
throw Error(message);
|
|
3842
|
+
}
|
|
3843
|
+
if (route.id !== "root") {
|
|
3844
|
+
let hasHydrateFallback = exportNames.some(
|
|
3845
|
+
(exp) => exp === "HydrateFallback"
|
|
3846
|
+
);
|
|
3847
|
+
if (hasHydrateFallback) {
|
|
3848
|
+
let message = `SPA Mode: Invalid \`HydrateFallback\` export found in \`${route.file}\`. \`HydrateFallback\` is only permitted on the root route in SPA Mode. See https://reactrouter.com/how-to/spa for more information.`;
|
|
3849
|
+
throw Error(message);
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
let [filepath] = id.split("?");
|
|
3854
|
+
let ast = (0, import_parser.parse)(code, { sourceType: "module" });
|
|
3855
|
+
if (!options?.ssr) {
|
|
3856
|
+
removeExports(ast, SERVER_ONLY_ROUTE_EXPORTS);
|
|
3857
|
+
}
|
|
3858
|
+
decorateComponentExportsWithProps(ast);
|
|
3859
|
+
return generate(ast, {
|
|
3860
|
+
sourceMaps: true,
|
|
3861
|
+
filename: id,
|
|
3862
|
+
sourceFileName: filepath
|
|
3863
|
+
});
|
|
3864
|
+
}
|
|
3865
|
+
},
|
|
3866
|
+
{
|
|
3867
|
+
name: "react-router:inject-hmr-runtime",
|
|
3868
|
+
enforce: "pre",
|
|
3869
|
+
resolveId(id) {
|
|
3870
|
+
if (id === virtualInjectHmrRuntime.id) {
|
|
3871
|
+
return virtualInjectHmrRuntime.resolvedId;
|
|
3872
|
+
}
|
|
3873
|
+
},
|
|
3874
|
+
async load(id) {
|
|
3875
|
+
if (id !== virtualInjectHmrRuntime.resolvedId) return;
|
|
3876
|
+
return [
|
|
3877
|
+
`import RefreshRuntime from "${virtualHmrRuntime.id}"`,
|
|
3878
|
+
"RefreshRuntime.injectIntoGlobalHook(window)",
|
|
3879
|
+
"window.$RefreshReg$ = () => {}",
|
|
3880
|
+
"window.$RefreshSig$ = () => (type) => type",
|
|
3881
|
+
"window.__vite_plugin_react_preamble_installed__ = true"
|
|
3882
|
+
].join("\n");
|
|
3883
|
+
}
|
|
3884
|
+
},
|
|
3885
|
+
{
|
|
3886
|
+
name: "react-router:hmr-runtime",
|
|
3887
|
+
enforce: "pre",
|
|
3888
|
+
resolveId(id) {
|
|
3889
|
+
if (id === virtualHmrRuntime.id) return virtualHmrRuntime.resolvedId;
|
|
3890
|
+
},
|
|
3891
|
+
async load(id) {
|
|
3892
|
+
if (id !== virtualHmrRuntime.resolvedId) return;
|
|
3893
|
+
let reactRefreshDir = path6.dirname(
|
|
3894
|
+
require.resolve("react-refresh/package.json")
|
|
3895
|
+
);
|
|
3896
|
+
let reactRefreshRuntimePath = path6.join(
|
|
3897
|
+
reactRefreshDir,
|
|
3898
|
+
"cjs/react-refresh-runtime.development.js"
|
|
3899
|
+
);
|
|
3900
|
+
return [
|
|
3901
|
+
"const exports = {}",
|
|
3902
|
+
await (0, import_promises2.readFile)(reactRefreshRuntimePath, "utf8"),
|
|
3903
|
+
await (0, import_promises2.readFile)(require.resolve("./static/refresh-utils.mjs"), "utf8"),
|
|
3904
|
+
"export default exports"
|
|
3905
|
+
].join("\n");
|
|
3906
|
+
}
|
|
3907
|
+
},
|
|
3908
|
+
{
|
|
3909
|
+
name: "react-router:react-refresh-babel",
|
|
3910
|
+
async transform(code, id, options) {
|
|
3911
|
+
if (viteCommand !== "serve") return;
|
|
3912
|
+
if (id.includes("/node_modules/")) return;
|
|
3913
|
+
let [filepath] = id.split("?");
|
|
3914
|
+
let extensionsRE = /\.(jsx?|tsx?|mdx?)$/;
|
|
3915
|
+
if (!extensionsRE.test(filepath)) return;
|
|
3916
|
+
let devRuntime = "react/jsx-dev-runtime";
|
|
3917
|
+
let ssr = options?.ssr === true;
|
|
3918
|
+
let isJSX = filepath.endsWith("x");
|
|
3919
|
+
let useFastRefresh = !ssr && (isJSX || code.includes(devRuntime));
|
|
3920
|
+
if (!useFastRefresh) return;
|
|
3921
|
+
if (isRouteVirtualModule(id)) {
|
|
3922
|
+
return { code: addRefreshWrapper(ctx.reactRouterConfig, code, id) };
|
|
3923
|
+
}
|
|
3924
|
+
let result = await babel.transformAsync(code, {
|
|
3925
|
+
babelrc: false,
|
|
3926
|
+
configFile: false,
|
|
3927
|
+
filename: id,
|
|
3928
|
+
sourceFileName: filepath,
|
|
3929
|
+
parserOpts: {
|
|
3930
|
+
sourceType: "module",
|
|
3931
|
+
allowAwaitOutsideFunction: true
|
|
3932
|
+
},
|
|
3933
|
+
plugins: [[require("react-refresh/babel"), { skipEnvCheck: true }]],
|
|
3934
|
+
sourceMaps: true
|
|
3935
|
+
});
|
|
3936
|
+
if (result === null) return;
|
|
3937
|
+
code = result.code;
|
|
3938
|
+
let refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
|
|
3939
|
+
if (refreshContentRE.test(code)) {
|
|
3940
|
+
code = addRefreshWrapper(ctx.reactRouterConfig, code, id);
|
|
3941
|
+
}
|
|
3942
|
+
return { code, map: result.map };
|
|
3943
|
+
}
|
|
3944
|
+
},
|
|
3945
|
+
{
|
|
3946
|
+
name: "react-router:hmr-updates",
|
|
3947
|
+
async handleHotUpdate({ server, file, modules, read }) {
|
|
3948
|
+
let route = getRoute(ctx.reactRouterConfig, file);
|
|
3949
|
+
let hmrEventData = { route: null };
|
|
3950
|
+
if (route) {
|
|
3951
|
+
let oldRouteMetadata = currentReactRouterManifestForDev?.routes[route.id];
|
|
3952
|
+
let newRouteMetadata = await getRouteMetadata(
|
|
3953
|
+
cache,
|
|
3954
|
+
ctx,
|
|
3955
|
+
viteChildCompiler,
|
|
3956
|
+
route,
|
|
3957
|
+
read
|
|
3958
|
+
);
|
|
3959
|
+
hmrEventData.route = newRouteMetadata;
|
|
3960
|
+
if (!oldRouteMetadata || [
|
|
3961
|
+
"hasLoader",
|
|
3962
|
+
"hasClientLoader",
|
|
3963
|
+
"clientLoaderModule",
|
|
3964
|
+
"hasAction",
|
|
3965
|
+
"hasClientAction",
|
|
3966
|
+
"clientActionModule",
|
|
3967
|
+
"hasClientMiddleware",
|
|
3968
|
+
"clientMiddlewareModule",
|
|
3969
|
+
"hasErrorBoundary",
|
|
3970
|
+
"hydrateFallbackModule"
|
|
3971
|
+
].some((key) => oldRouteMetadata[key] !== newRouteMetadata[key])) {
|
|
3972
|
+
invalidateVirtualModules(server);
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
server.hot.send({
|
|
3976
|
+
type: "custom",
|
|
3977
|
+
event: "react-router:hmr",
|
|
3978
|
+
data: hmrEventData
|
|
3979
|
+
});
|
|
3980
|
+
return modules;
|
|
3981
|
+
}
|
|
3982
|
+
},
|
|
3983
|
+
{
|
|
3984
|
+
name: "react-router-server-change-trigger-client-hmr",
|
|
3985
|
+
// This hook is only available in Vite v6+ so this is a no-op in v5.
|
|
3986
|
+
// Previously, the server and client modules were shared in a single module
|
|
3987
|
+
// graph. This meant that changes to server code automatically resulted in
|
|
3988
|
+
// client HMR updates. In Vite v6+, these module graphs are separate from
|
|
3989
|
+
// each other, so we need to manually trigger client HMR updates if server
|
|
3990
|
+
// code has changed.
|
|
3991
|
+
hotUpdate({ server, modules }) {
|
|
3992
|
+
if (this.environment.name !== "ssr" && modules.length <= 0) {
|
|
3993
|
+
return;
|
|
3994
|
+
}
|
|
3995
|
+
let clientModules = uniqueNodes(
|
|
3996
|
+
modules.flatMap(
|
|
3997
|
+
(mod) => getParentClientNodes(server.environments.client.moduleGraph, mod)
|
|
3998
|
+
)
|
|
3999
|
+
);
|
|
4000
|
+
for (let clientModule of clientModules) {
|
|
4001
|
+
server.environments.client.reloadModule(clientModule);
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
},
|
|
4005
|
+
validatePluginOrder()
|
|
4006
|
+
];
|
|
4007
|
+
};
|
|
4008
|
+
function getParentClientNodes(clientModuleGraph, module2) {
|
|
4009
|
+
if (!module2.id) {
|
|
4010
|
+
return [];
|
|
4011
|
+
}
|
|
4012
|
+
let clientModule = clientModuleGraph.getModuleById(module2.id);
|
|
4013
|
+
if (clientModule) {
|
|
4014
|
+
return [clientModule];
|
|
4015
|
+
}
|
|
4016
|
+
return [...module2.importers].flatMap(
|
|
4017
|
+
(importer) => getParentClientNodes(clientModuleGraph, importer)
|
|
4018
|
+
);
|
|
4019
|
+
}
|
|
4020
|
+
function uniqueNodes(nodes) {
|
|
4021
|
+
let nodeUrls = /* @__PURE__ */ new Set();
|
|
4022
|
+
let unique = [];
|
|
4023
|
+
for (let node of nodes) {
|
|
4024
|
+
if (nodeUrls.has(node.url)) {
|
|
4025
|
+
continue;
|
|
4026
|
+
}
|
|
4027
|
+
nodeUrls.add(node.url);
|
|
4028
|
+
unique.push(node);
|
|
4029
|
+
}
|
|
4030
|
+
return unique;
|
|
4031
|
+
}
|
|
4032
|
+
function addRefreshWrapper(reactRouterConfig, code, id) {
|
|
4033
|
+
let route = getRoute(reactRouterConfig, id);
|
|
4034
|
+
let acceptExports = route ? CLIENT_NON_COMPONENT_EXPORTS : [];
|
|
4035
|
+
return REACT_REFRESH_HEADER.replaceAll("__SOURCE__", JSON.stringify(id)) + code + REACT_REFRESH_FOOTER.replaceAll("__SOURCE__", JSON.stringify(id)).replaceAll("__ACCEPT_EXPORTS__", JSON.stringify(acceptExports)).replaceAll("__ROUTE_ID__", JSON.stringify(route?.id));
|
|
4036
|
+
}
|
|
4037
|
+
var REACT_REFRESH_HEADER = `
|
|
4038
|
+
import RefreshRuntime from "${virtualHmrRuntime.id}";
|
|
4039
|
+
|
|
4040
|
+
const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
|
|
4041
|
+
let prevRefreshReg;
|
|
4042
|
+
let prevRefreshSig;
|
|
4043
|
+
|
|
4044
|
+
if (import.meta.hot && !inWebWorker) {
|
|
4045
|
+
if (!window.__vite_plugin_react_preamble_installed__) {
|
|
4046
|
+
throw new Error(
|
|
4047
|
+
"React Router Vite plugin can't detect preamble. Something is wrong."
|
|
4048
|
+
);
|
|
4049
|
+
}
|
|
4050
|
+
|
|
4051
|
+
prevRefreshReg = window.$RefreshReg$;
|
|
4052
|
+
prevRefreshSig = window.$RefreshSig$;
|
|
4053
|
+
window.$RefreshReg$ = (type, id) => {
|
|
4054
|
+
RefreshRuntime.register(type, __SOURCE__ + " " + id)
|
|
4055
|
+
};
|
|
4056
|
+
window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
|
|
4057
|
+
}`.replaceAll("\n", "");
|
|
4058
|
+
var REACT_REFRESH_FOOTER = `
|
|
4059
|
+
if (import.meta.hot && !inWebWorker) {
|
|
4060
|
+
window.$RefreshReg$ = prevRefreshReg;
|
|
4061
|
+
window.$RefreshSig$ = prevRefreshSig;
|
|
4062
|
+
RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
|
|
4063
|
+
RefreshRuntime.registerExportsForReactRefresh(__SOURCE__, currentExports);
|
|
4064
|
+
import.meta.hot.accept((nextExports) => {
|
|
4065
|
+
if (!nextExports) return;
|
|
4066
|
+
__ROUTE_ID__ && window.__reactRouterRouteModuleUpdates.set(__ROUTE_ID__, nextExports);
|
|
4067
|
+
const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(currentExports, nextExports, __ACCEPT_EXPORTS__);
|
|
4068
|
+
if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
|
|
4069
|
+
});
|
|
4070
|
+
});
|
|
4071
|
+
}`;
|
|
4072
|
+
function getRoute(pluginConfig, file) {
|
|
4073
|
+
let vite2 = getVite();
|
|
4074
|
+
let routePath = vite2.normalizePath(
|
|
4075
|
+
path6.relative(pluginConfig.appDirectory, file)
|
|
4076
|
+
);
|
|
4077
|
+
let route = Object.values(pluginConfig.routes).find(
|
|
4078
|
+
(r) => vite2.normalizePath(r.file) === routePath
|
|
4079
|
+
);
|
|
4080
|
+
return route;
|
|
4081
|
+
}
|
|
4082
|
+
function isRoute(pluginConfig, file) {
|
|
4083
|
+
return Boolean(getRoute(pluginConfig, file));
|
|
4084
|
+
}
|
|
4085
|
+
async function getRouteMetadata(cache, ctx, viteChildCompiler, route, readRouteFile) {
|
|
4086
|
+
let routeFile = route.file;
|
|
4087
|
+
let sourceExports = await getRouteModuleExports(
|
|
4088
|
+
viteChildCompiler,
|
|
4089
|
+
ctx,
|
|
4090
|
+
route.file,
|
|
4091
|
+
readRouteFile
|
|
4092
|
+
);
|
|
4093
|
+
let { hasRouteChunkByExportName } = await detectRouteChunksIfEnabled(
|
|
4094
|
+
cache,
|
|
4095
|
+
ctx,
|
|
4096
|
+
routeFile,
|
|
4097
|
+
{ routeFile, readRouteFile, viteChildCompiler }
|
|
4098
|
+
);
|
|
4099
|
+
let moduleUrl = combineURLs(
|
|
4100
|
+
ctx.publicPath,
|
|
4101
|
+
`${resolveFileUrl(
|
|
4102
|
+
ctx,
|
|
4103
|
+
resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
|
|
4104
|
+
)}`
|
|
4105
|
+
);
|
|
4106
|
+
let info = {
|
|
4107
|
+
id: route.id,
|
|
4108
|
+
parentId: route.parentId,
|
|
4109
|
+
path: route.path,
|
|
4110
|
+
index: route.index,
|
|
4111
|
+
caseSensitive: route.caseSensitive,
|
|
4112
|
+
url: combineURLs(
|
|
4113
|
+
ctx.publicPath,
|
|
4114
|
+
"/" + path6.relative(
|
|
4115
|
+
ctx.rootDirectory,
|
|
4116
|
+
resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)
|
|
4117
|
+
)
|
|
4118
|
+
),
|
|
4119
|
+
module: `${moduleUrl}?import`,
|
|
4120
|
+
// Ensure the Vite dev server responds with a JS module
|
|
4121
|
+
clientActionModule: hasRouteChunkByExportName.clientAction ? `${getRouteChunkModuleId(moduleUrl, "clientAction")}` : void 0,
|
|
4122
|
+
clientLoaderModule: hasRouteChunkByExportName.clientLoader ? `${getRouteChunkModuleId(moduleUrl, "clientLoader")}` : void 0,
|
|
4123
|
+
clientMiddlewareModule: hasRouteChunkByExportName.clientMiddleware ? `${getRouteChunkModuleId(moduleUrl, "clientMiddleware")}` : void 0,
|
|
4124
|
+
hydrateFallbackModule: hasRouteChunkByExportName.HydrateFallback ? `${getRouteChunkModuleId(moduleUrl, "HydrateFallback")}` : void 0,
|
|
4125
|
+
hasAction: sourceExports.includes("action"),
|
|
4126
|
+
hasClientAction: sourceExports.includes("clientAction"),
|
|
4127
|
+
hasLoader: sourceExports.includes("loader"),
|
|
4128
|
+
hasClientLoader: sourceExports.includes("clientLoader"),
|
|
4129
|
+
hasClientMiddleware: sourceExports.includes("clientMiddleware"),
|
|
4130
|
+
hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
|
|
4131
|
+
imports: []
|
|
4132
|
+
};
|
|
4133
|
+
return info;
|
|
4134
|
+
}
|
|
4135
|
+
function isPrerenderingEnabled(reactRouterConfig) {
|
|
4136
|
+
return reactRouterConfig.prerender != null && reactRouterConfig.prerender !== false;
|
|
4137
|
+
}
|
|
4138
|
+
function isSpaModeEnabled(reactRouterConfig) {
|
|
4139
|
+
return reactRouterConfig.ssr === false && !isPrerenderingEnabled(reactRouterConfig);
|
|
4140
|
+
}
|
|
4141
|
+
async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, serverBuildFile) {
|
|
4142
|
+
let serverBuildPath = path6.join(serverBuildDirectory, serverBuildFile);
|
|
4143
|
+
let build = await import(url.pathToFileURL(serverBuildPath).toString());
|
|
4144
|
+
let { createRequestHandler: createHandler } = await import("react-router");
|
|
4145
|
+
return {
|
|
4146
|
+
build,
|
|
4147
|
+
handler: createHandler(build, viteConfig.mode)
|
|
4148
|
+
};
|
|
4149
|
+
}
|
|
4150
|
+
async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildFile, clientBuildDirectory) {
|
|
4151
|
+
let { build, handler } = await getPrerenderBuildAndHandler(
|
|
4152
|
+
viteConfig,
|
|
4153
|
+
serverBuildDirectory,
|
|
4154
|
+
serverBuildFile
|
|
4155
|
+
);
|
|
4156
|
+
let request = new Request(`http://localhost${reactRouterConfig.basename}`, {
|
|
4157
|
+
headers: {
|
|
4158
|
+
// Enable SPA mode in the server runtime and only render down to the root
|
|
4159
|
+
"X-React-Router-SPA-Mode": "yes"
|
|
4160
|
+
}
|
|
4161
|
+
});
|
|
4162
|
+
let response = await handler(request);
|
|
4163
|
+
let html = await response.text();
|
|
4164
|
+
let isPrerenderSpaFallback = build.prerender.includes("/");
|
|
4165
|
+
let filename2 = isPrerenderSpaFallback ? "__spa-fallback.html" : "index.html";
|
|
4166
|
+
if (response.status !== 200) {
|
|
4167
|
+
if (isPrerenderSpaFallback) {
|
|
4168
|
+
throw new Error(
|
|
4169
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename2}\` file.
|
|
4170
|
+
` + html
|
|
4171
|
+
);
|
|
4172
|
+
} else {
|
|
4173
|
+
throw new Error(
|
|
4174
|
+
`SPA Mode: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename2}\` file.
|
|
4175
|
+
` + html
|
|
4176
|
+
);
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
|
|
4180
|
+
throw new Error(
|
|
4181
|
+
"SPA Mode: Did you forget to include `<Scripts/>` in your root route? Your pre-rendered HTML cannot hydrate without `<Scripts />`."
|
|
4182
|
+
);
|
|
4183
|
+
}
|
|
4184
|
+
await (0, import_promises2.writeFile)(path6.join(clientBuildDirectory, filename2), html);
|
|
4185
|
+
let prettyDir = path6.relative(viteConfig.root, clientBuildDirectory);
|
|
4186
|
+
let prettyPath = path6.join(prettyDir, filename2);
|
|
4187
|
+
if (build.prerender.length > 0) {
|
|
4188
|
+
viteConfig.logger.info(
|
|
4189
|
+
`Prerender (html): SPA Fallback -> ${import_picocolors3.default.bold(prettyPath)}`
|
|
4190
|
+
);
|
|
4191
|
+
} else {
|
|
4192
|
+
viteConfig.logger.info(`SPA Mode: Generated ${import_picocolors3.default.bold(prettyPath)}`);
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildPath, clientBuildDirectory) {
|
|
4196
|
+
let { build, handler } = await getPrerenderBuildAndHandler(
|
|
4197
|
+
viteConfig,
|
|
4198
|
+
serverBuildDirectory,
|
|
4199
|
+
serverBuildPath
|
|
4200
|
+
);
|
|
4201
|
+
let routes = createPrerenderRoutes(reactRouterConfig.routes);
|
|
4202
|
+
for (let path7 of build.prerender) {
|
|
4203
|
+
let matches = (0, import_react_router2.matchRoutes)(routes, `/${path7}/`.replace(/^\/\/+/, "/"));
|
|
4204
|
+
if (!matches) {
|
|
4205
|
+
throw new Error(
|
|
4206
|
+
`Unable to prerender path because it does not match any routes: ${path7}`
|
|
4207
|
+
);
|
|
4208
|
+
}
|
|
4209
|
+
}
|
|
4210
|
+
let buildRoutes = createPrerenderRoutes(build.routes);
|
|
4211
|
+
for (let path7 of build.prerender) {
|
|
4212
|
+
let matches = (0, import_react_router2.matchRoutes)(buildRoutes, `/${path7}/`.replace(/^\/\/+/, "/"));
|
|
4213
|
+
if (!matches) {
|
|
4214
|
+
continue;
|
|
4215
|
+
}
|
|
4216
|
+
let leafRoute = matches ? matches[matches.length - 1].route : null;
|
|
4217
|
+
let manifestRoute = leafRoute ? build.routes[leafRoute.id]?.module : null;
|
|
4218
|
+
let isResourceRoute = manifestRoute && !manifestRoute.default && !manifestRoute.ErrorBoundary;
|
|
4219
|
+
if (isResourceRoute) {
|
|
4220
|
+
invariant(leafRoute);
|
|
4221
|
+
invariant(manifestRoute);
|
|
4222
|
+
if (manifestRoute.loader) {
|
|
4223
|
+
await prerenderData(
|
|
4224
|
+
handler,
|
|
4225
|
+
path7,
|
|
4226
|
+
[leafRoute.id],
|
|
4227
|
+
clientBuildDirectory,
|
|
4228
|
+
reactRouterConfig,
|
|
4229
|
+
viteConfig
|
|
4230
|
+
);
|
|
4231
|
+
await prerenderResourceRoute(
|
|
4232
|
+
handler,
|
|
4233
|
+
path7,
|
|
4234
|
+
clientBuildDirectory,
|
|
4235
|
+
reactRouterConfig,
|
|
4236
|
+
viteConfig
|
|
4237
|
+
);
|
|
4238
|
+
} else {
|
|
4239
|
+
viteConfig.logger.warn(
|
|
4240
|
+
`\u26A0\uFE0F Skipping prerendering for resource route without a loader: ${leafRoute?.id}`
|
|
4241
|
+
);
|
|
4242
|
+
}
|
|
4243
|
+
} else {
|
|
4244
|
+
let hasLoaders = matches.some(
|
|
4245
|
+
(m) => build.assets.routes[m.route.id]?.hasLoader
|
|
4246
|
+
);
|
|
4247
|
+
let data;
|
|
4248
|
+
if (!isResourceRoute && hasLoaders) {
|
|
4249
|
+
data = await prerenderData(
|
|
4250
|
+
handler,
|
|
4251
|
+
path7,
|
|
4252
|
+
null,
|
|
4253
|
+
clientBuildDirectory,
|
|
4254
|
+
reactRouterConfig,
|
|
4255
|
+
viteConfig
|
|
4256
|
+
);
|
|
4257
|
+
}
|
|
4258
|
+
await prerenderRoute(
|
|
4259
|
+
handler,
|
|
4260
|
+
path7,
|
|
4261
|
+
clientBuildDirectory,
|
|
4262
|
+
reactRouterConfig,
|
|
4263
|
+
viteConfig,
|
|
4264
|
+
data ? {
|
|
4265
|
+
headers: {
|
|
4266
|
+
"X-React-Router-Prerender-Data": encodeURI(data)
|
|
4267
|
+
}
|
|
4268
|
+
} : void 0
|
|
4269
|
+
);
|
|
4270
|
+
}
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
function getStaticPrerenderPaths(routes) {
|
|
4274
|
+
let paths = ["/"];
|
|
4275
|
+
let paramRoutes = [];
|
|
4276
|
+
function recurse(subtree, prefix = "") {
|
|
4277
|
+
for (let route of subtree) {
|
|
4278
|
+
let newPath = [prefix, route.path].join("/").replace(/\/\/+/g, "/");
|
|
4279
|
+
if (route.path) {
|
|
4280
|
+
let segments = route.path.split("/");
|
|
4281
|
+
if (segments.some((s) => s.startsWith(":") || s === "*")) {
|
|
4282
|
+
paramRoutes.push(route.path);
|
|
4283
|
+
} else {
|
|
4284
|
+
paths.push(newPath);
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
if (route.children) {
|
|
4288
|
+
recurse(route.children, newPath);
|
|
4289
|
+
}
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4292
|
+
recurse(routes);
|
|
4293
|
+
return {
|
|
4294
|
+
paths: paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1")),
|
|
4295
|
+
paramRoutes
|
|
4296
|
+
};
|
|
4297
|
+
}
|
|
4298
|
+
async function prerenderData(handler, prerenderPath, onlyRoutes, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
4299
|
+
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
|
|
4300
|
+
let url2 = new URL(`http://localhost${normalizedPath}`);
|
|
4301
|
+
if (onlyRoutes?.length) {
|
|
4302
|
+
url2.searchParams.set("_routes", onlyRoutes.join(","));
|
|
4303
|
+
}
|
|
4304
|
+
let request = new Request(url2, requestInit);
|
|
4305
|
+
let response = await handler(request);
|
|
4306
|
+
let data = await response.text();
|
|
4307
|
+
if (response.status !== 200 && response.status !== 202) {
|
|
4308
|
+
throw new Error(
|
|
4309
|
+
`Prerender (data): Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${prerenderPath}\` path.
|
|
4310
|
+
${normalizedPath}`
|
|
4311
|
+
);
|
|
4312
|
+
}
|
|
4313
|
+
let outfile = path6.join(clientBuildDirectory, ...normalizedPath.split("/"));
|
|
4314
|
+
await (0, import_promises2.mkdir)(path6.dirname(outfile), { recursive: true });
|
|
4315
|
+
await (0, import_promises2.writeFile)(outfile, data);
|
|
4316
|
+
viteConfig.logger.info(
|
|
4317
|
+
`Prerender (data): ${prerenderPath} -> ${import_picocolors3.default.bold(
|
|
4318
|
+
path6.relative(viteConfig.root, outfile)
|
|
4319
|
+
)}`
|
|
4320
|
+
);
|
|
4321
|
+
return data;
|
|
4322
|
+
}
|
|
4323
|
+
var redirectStatusCodes = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
4324
|
+
async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
4325
|
+
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(
|
|
4326
|
+
/\/\/+/g,
|
|
4327
|
+
"/"
|
|
4328
|
+
);
|
|
4329
|
+
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
4330
|
+
let response = await handler(request);
|
|
4331
|
+
let html = await response.text();
|
|
4332
|
+
if (redirectStatusCodes.has(response.status)) {
|
|
4333
|
+
let location = response.headers.get("Location");
|
|
4334
|
+
let delay = response.status === 302 ? 2 : 0;
|
|
4335
|
+
html = `<!doctype html>
|
|
4336
|
+
<head>
|
|
4337
|
+
<title>Redirecting to: ${location}</title>
|
|
4338
|
+
<meta http-equiv="refresh" content="${delay};url=${location}">
|
|
4339
|
+
<meta name="robots" content="noindex">
|
|
4340
|
+
</head>
|
|
4341
|
+
<body>
|
|
4342
|
+
<a href="${location}">
|
|
4343
|
+
Redirecting from <code>${normalizedPath}</code> to <code>${location}</code>
|
|
4344
|
+
</a>
|
|
4345
|
+
</body>
|
|
4346
|
+
</html>`;
|
|
4347
|
+
} else if (response.status !== 200) {
|
|
4348
|
+
throw new Error(
|
|
4349
|
+
`Prerender (html): Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
|
|
4350
|
+
${html}`
|
|
4351
|
+
);
|
|
4352
|
+
}
|
|
4353
|
+
let outfile = path6.join(
|
|
4354
|
+
clientBuildDirectory,
|
|
4355
|
+
...normalizedPath.split("/"),
|
|
4356
|
+
"index.html"
|
|
4357
|
+
);
|
|
4358
|
+
await (0, import_promises2.mkdir)(path6.dirname(outfile), { recursive: true });
|
|
4359
|
+
await (0, import_promises2.writeFile)(outfile, html);
|
|
4360
|
+
viteConfig.logger.info(
|
|
4361
|
+
`Prerender (html): ${prerenderPath} -> ${import_picocolors3.default.bold(
|
|
4362
|
+
path6.relative(viteConfig.root, outfile)
|
|
4363
|
+
)}`
|
|
4364
|
+
);
|
|
4365
|
+
}
|
|
4366
|
+
async function prerenderResourceRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
4367
|
+
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/").replace(/\/$/g, "");
|
|
4368
|
+
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
4369
|
+
let response = await handler(request);
|
|
4370
|
+
let content = Buffer.from(await response.arrayBuffer());
|
|
4371
|
+
if (response.status !== 200) {
|
|
4372
|
+
throw new Error(
|
|
4373
|
+
`Prerender (resource): Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
|
|
4374
|
+
${content.toString("utf8")}`
|
|
4375
|
+
);
|
|
4376
|
+
}
|
|
4377
|
+
let outfile = path6.join(clientBuildDirectory, ...normalizedPath.split("/"));
|
|
4378
|
+
await (0, import_promises2.mkdir)(path6.dirname(outfile), { recursive: true });
|
|
4379
|
+
await (0, import_promises2.writeFile)(outfile, content);
|
|
4380
|
+
viteConfig.logger.info(
|
|
4381
|
+
`Prerender (resource): ${prerenderPath} -> ${import_picocolors3.default.bold(
|
|
4382
|
+
path6.relative(viteConfig.root, outfile)
|
|
4383
|
+
)}`
|
|
4384
|
+
);
|
|
4385
|
+
}
|
|
4386
|
+
async function getPrerenderPaths(prerender, ssr, routes, logWarning = false) {
|
|
4387
|
+
let prerenderPaths = [];
|
|
4388
|
+
if (prerender != null && prerender !== false) {
|
|
4389
|
+
let prerenderRoutes = createPrerenderRoutes(routes);
|
|
4390
|
+
if (prerender === true) {
|
|
4391
|
+
let { paths, paramRoutes } = getStaticPrerenderPaths(prerenderRoutes);
|
|
4392
|
+
if (logWarning && !ssr && paramRoutes.length > 0) {
|
|
4393
|
+
console.warn(
|
|
4394
|
+
import_picocolors3.default.yellow(
|
|
4395
|
+
[
|
|
4396
|
+
"\u26A0\uFE0F Paths with dynamic/splat params cannot be prerendered when using `prerender: true`. You may want to use the `prerender()` API to prerender the following paths:",
|
|
4397
|
+
...paramRoutes.map((p) => " - " + p)
|
|
4398
|
+
].join("\n")
|
|
4399
|
+
)
|
|
4400
|
+
);
|
|
4401
|
+
}
|
|
4402
|
+
prerenderPaths = paths;
|
|
4403
|
+
} else if (typeof prerender === "function") {
|
|
4404
|
+
prerenderPaths = await prerender({
|
|
4405
|
+
getStaticPaths: () => getStaticPrerenderPaths(prerenderRoutes).paths
|
|
4406
|
+
});
|
|
4407
|
+
} else {
|
|
4408
|
+
prerenderPaths = prerender || ["/"];
|
|
4409
|
+
}
|
|
4410
|
+
}
|
|
4411
|
+
return prerenderPaths;
|
|
4412
|
+
}
|
|
4413
|
+
function groupRoutesByParentId2(manifest) {
|
|
4414
|
+
let routes = {};
|
|
4415
|
+
Object.values(manifest).forEach((route) => {
|
|
4416
|
+
if (route) {
|
|
4417
|
+
let parentId = route.parentId || "";
|
|
4418
|
+
if (!routes[parentId]) {
|
|
4419
|
+
routes[parentId] = [];
|
|
4420
|
+
}
|
|
4421
|
+
routes[parentId].push(route);
|
|
4422
|
+
}
|
|
4423
|
+
});
|
|
4424
|
+
return routes;
|
|
4425
|
+
}
|
|
4426
|
+
function createPrerenderRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
|
|
4427
|
+
return (routesByParentId[parentId] || []).map((route) => {
|
|
4428
|
+
let commonRoute = {
|
|
4429
|
+
id: route.id,
|
|
4430
|
+
path: route.path
|
|
4431
|
+
};
|
|
4432
|
+
if (route.index) {
|
|
4433
|
+
return {
|
|
4434
|
+
index: true,
|
|
4435
|
+
...commonRoute
|
|
4436
|
+
};
|
|
4437
|
+
}
|
|
4438
|
+
return {
|
|
4439
|
+
children: createPrerenderRoutes(manifest, route.id, routesByParentId),
|
|
4440
|
+
...commonRoute
|
|
4441
|
+
};
|
|
4442
|
+
});
|
|
4443
|
+
}
|
|
4444
|
+
async function validateSsrFalsePrerenderExports(viteConfig, ctx, manifest, viteChildCompiler) {
|
|
4445
|
+
let prerenderPaths = await getPrerenderPaths(
|
|
4446
|
+
ctx.reactRouterConfig.prerender,
|
|
4447
|
+
ctx.reactRouterConfig.ssr,
|
|
4448
|
+
manifest.routes,
|
|
4449
|
+
true
|
|
4450
|
+
);
|
|
4451
|
+
if (prerenderPaths.length === 0) {
|
|
4452
|
+
return;
|
|
4453
|
+
}
|
|
4454
|
+
let prerenderRoutes = createPrerenderRoutes(manifest.routes);
|
|
4455
|
+
let prerenderedRoutes = /* @__PURE__ */ new Set();
|
|
4456
|
+
for (let path7 of prerenderPaths) {
|
|
4457
|
+
let matches = (0, import_react_router2.matchRoutes)(
|
|
4458
|
+
prerenderRoutes,
|
|
4459
|
+
`/${path7}/`.replace(/^\/\/+/, "/")
|
|
4460
|
+
);
|
|
4461
|
+
invariant(
|
|
4462
|
+
matches,
|
|
4463
|
+
`Unable to prerender path because it does not match any routes: ${path7}`
|
|
4464
|
+
);
|
|
4465
|
+
matches.forEach((m) => prerenderedRoutes.add(m.route.id));
|
|
4466
|
+
}
|
|
4467
|
+
let errors = [];
|
|
4468
|
+
let routeExports = await getRouteManifestModuleExports(
|
|
4469
|
+
viteChildCompiler,
|
|
4470
|
+
ctx
|
|
4471
|
+
);
|
|
4472
|
+
for (let [routeId, route] of Object.entries(manifest.routes)) {
|
|
4473
|
+
let invalidApis = [];
|
|
4474
|
+
invariant(route, "Expected a route object in validateSsrFalseExports");
|
|
4475
|
+
let exports2 = routeExports[route.id];
|
|
4476
|
+
if (exports2.includes("headers")) invalidApis.push("headers");
|
|
4477
|
+
if (exports2.includes("action")) invalidApis.push("action");
|
|
4478
|
+
if (invalidApis.length > 0) {
|
|
4479
|
+
errors.push(
|
|
4480
|
+
`Prerender: ${invalidApis.length} invalid route export(s) in \`${route.id}\` when pre-rendering with \`ssr:false\`: ${invalidApis.map((a) => `\`${a}\``).join(", ")}. See https://reactrouter.com/how-to/pre-rendering#invalid-exports for more information.`
|
|
4481
|
+
);
|
|
4482
|
+
}
|
|
4483
|
+
if (!prerenderedRoutes.has(routeId)) {
|
|
4484
|
+
if (exports2.includes("loader")) {
|
|
4485
|
+
errors.push(
|
|
4486
|
+
`Prerender: 1 invalid route export in \`${route.id}\` when pre-rendering with \`ssr:false\`: \`loader\`. See https://reactrouter.com/how-to/pre-rendering#invalid-exports for more information.`
|
|
4487
|
+
);
|
|
4488
|
+
}
|
|
4489
|
+
let parentRoute = route.parentId ? manifest.routes[route.parentId] : null;
|
|
4490
|
+
while (parentRoute && parentRoute.id !== "root") {
|
|
4491
|
+
if (parentRoute.hasLoader && !parentRoute.hasClientLoader) {
|
|
4492
|
+
errors.push(
|
|
4493
|
+
`Prerender: 1 invalid route export in \`${parentRoute.id}\` when pre-rendering with \`ssr:false\`: \`loader\`. See https://reactrouter.com/how-to/pre-rendering#invalid-exports for more information.`
|
|
4494
|
+
);
|
|
4495
|
+
}
|
|
4496
|
+
parentRoute = parentRoute.parentId && parentRoute.parentId !== "root" ? manifest.routes[parentRoute.parentId] : null;
|
|
4497
|
+
}
|
|
4498
|
+
}
|
|
4499
|
+
}
|
|
4500
|
+
if (errors.length > 0) {
|
|
4501
|
+
viteConfig.logger.error(import_picocolors3.default.red(errors.join("\n")));
|
|
4502
|
+
throw new Error(
|
|
4503
|
+
"Invalid route exports found when prerendering with `ssr:false`"
|
|
4504
|
+
);
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4507
|
+
function getAddressableRoutes(routes) {
|
|
4508
|
+
let nonAddressableIds = /* @__PURE__ */ new Set();
|
|
4509
|
+
for (let id in routes) {
|
|
4510
|
+
let route = routes[id];
|
|
4511
|
+
if (route.index) {
|
|
4512
|
+
invariant(
|
|
4513
|
+
route.parentId,
|
|
4514
|
+
`Expected index route "${route.id}" to have "parentId" set`
|
|
4515
|
+
);
|
|
4516
|
+
nonAddressableIds.add(route.parentId);
|
|
4517
|
+
}
|
|
4518
|
+
if (typeof route.path !== "string" && !route.index) {
|
|
4519
|
+
nonAddressableIds.add(id);
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4522
|
+
return Object.values(routes).filter(
|
|
4523
|
+
(route) => !nonAddressableIds.has(route.id)
|
|
4524
|
+
);
|
|
4525
|
+
}
|
|
4526
|
+
function getRouteBranch(routes, routeId) {
|
|
4527
|
+
let branch = [];
|
|
4528
|
+
let currentRouteId = routeId;
|
|
4529
|
+
while (currentRouteId) {
|
|
4530
|
+
let route = routes[currentRouteId];
|
|
4531
|
+
invariant(route, `Missing route for ${currentRouteId}`);
|
|
4532
|
+
branch.push(route);
|
|
4533
|
+
currentRouteId = route.parentId;
|
|
4534
|
+
}
|
|
4535
|
+
return branch.reverse();
|
|
4536
|
+
}
|
|
4537
|
+
function getServerBundleIds(ctx) {
|
|
4538
|
+
return ctx.buildManifest?.serverBundles ? Object.keys(ctx.buildManifest.serverBundles) : void 0;
|
|
4539
|
+
}
|
|
4540
|
+
function getRoutesByServerBundleId(buildManifest) {
|
|
4541
|
+
if (!buildManifest.routeIdToServerBundleId) {
|
|
4542
|
+
return {};
|
|
4543
|
+
}
|
|
4544
|
+
let routesByServerBundleId = {};
|
|
4545
|
+
for (let [routeId, serverBundleId] of Object.entries(
|
|
4546
|
+
buildManifest.routeIdToServerBundleId
|
|
4547
|
+
)) {
|
|
4548
|
+
routesByServerBundleId[serverBundleId] ??= {};
|
|
4549
|
+
let branch = getRouteBranch(buildManifest.routes, routeId);
|
|
4550
|
+
for (let route of branch) {
|
|
4551
|
+
routesByServerBundleId[serverBundleId][route.id] = route;
|
|
4552
|
+
}
|
|
4553
|
+
}
|
|
4554
|
+
return routesByServerBundleId;
|
|
4555
|
+
}
|
|
4556
|
+
var resolveRouteFileCode = async (ctx, input) => {
|
|
4557
|
+
if (typeof input === "string") return input;
|
|
4558
|
+
invariant(input.viteChildCompiler);
|
|
4559
|
+
return await compileRouteFile(
|
|
4560
|
+
input.viteChildCompiler,
|
|
4561
|
+
ctx,
|
|
4562
|
+
input.routeFile,
|
|
4563
|
+
input.readRouteFile
|
|
4564
|
+
);
|
|
4565
|
+
};
|
|
4566
|
+
function isRootRouteModuleId(ctx, id) {
|
|
4567
|
+
return normalizeRelativeFilePath(id, ctx.reactRouterConfig) === ctx.reactRouterConfig.routes.root.file;
|
|
4568
|
+
}
|
|
4569
|
+
async function detectRouteChunksIfEnabled(cache, ctx, id, input) {
|
|
4570
|
+
function noRouteChunks() {
|
|
4571
|
+
return {
|
|
4572
|
+
chunkedExports: [],
|
|
4573
|
+
hasRouteChunks: false,
|
|
4574
|
+
hasRouteChunkByExportName: {
|
|
4575
|
+
clientAction: false,
|
|
4576
|
+
clientLoader: false,
|
|
4577
|
+
clientMiddleware: false,
|
|
4578
|
+
HydrateFallback: false
|
|
4579
|
+
}
|
|
4580
|
+
};
|
|
4581
|
+
}
|
|
4582
|
+
if (!ctx.reactRouterConfig.future.unstable_splitRouteModules) {
|
|
4583
|
+
return noRouteChunks();
|
|
4584
|
+
}
|
|
4585
|
+
if (isRootRouteModuleId(ctx, id)) {
|
|
4586
|
+
return noRouteChunks();
|
|
4587
|
+
}
|
|
4588
|
+
let code = await resolveRouteFileCode(ctx, input);
|
|
4589
|
+
if (!routeChunkExportNames.some((exportName) => code.includes(exportName))) {
|
|
4590
|
+
return noRouteChunks();
|
|
4591
|
+
}
|
|
4592
|
+
let cacheKey = normalizeRelativeFilePath(id, ctx.reactRouterConfig) + (typeof input === "string" ? "" : "?read");
|
|
4593
|
+
return detectRouteChunks(code, cache, cacheKey);
|
|
4594
|
+
}
|
|
4595
|
+
async function getRouteChunkIfEnabled(cache, ctx, id, chunkName, input) {
|
|
4596
|
+
if (!ctx.reactRouterConfig.future.unstable_splitRouteModules) {
|
|
4597
|
+
return null;
|
|
4598
|
+
}
|
|
4599
|
+
let code = await resolveRouteFileCode(ctx, input);
|
|
4600
|
+
let cacheKey = normalizeRelativeFilePath(id, ctx.reactRouterConfig) + (typeof input === "string" ? "" : "?read");
|
|
4601
|
+
return getRouteChunkCode(code, chunkName, cache, cacheKey);
|
|
4602
|
+
}
|
|
4603
|
+
function validateRouteChunks({
|
|
4604
|
+
ctx,
|
|
4605
|
+
id,
|
|
4606
|
+
valid
|
|
4607
|
+
}) {
|
|
4608
|
+
if (isRootRouteModuleId(ctx, id)) {
|
|
4609
|
+
return;
|
|
4610
|
+
}
|
|
4611
|
+
let invalidChunks = Object.entries(valid).filter(([_, isValid]) => !isValid).map(([chunkName]) => chunkName);
|
|
4612
|
+
if (invalidChunks.length === 0) {
|
|
4613
|
+
return;
|
|
4614
|
+
}
|
|
4615
|
+
let plural = invalidChunks.length > 1;
|
|
4616
|
+
throw new Error(
|
|
4617
|
+
[
|
|
4618
|
+
`Error splitting route module: ${normalizeRelativeFilePath(
|
|
4619
|
+
id,
|
|
4620
|
+
ctx.reactRouterConfig
|
|
4621
|
+
)}`,
|
|
4622
|
+
invalidChunks.map((name) => `- ${name}`).join("\n"),
|
|
4623
|
+
`${plural ? "These exports" : "This export"} could not be split into ${plural ? "their own chunks" : "its own chunk"} because ${plural ? "they share" : "it shares"} code with other exports. You should extract any shared code into its own module and then import it within the route module.`
|
|
4624
|
+
].join("\n\n")
|
|
4625
|
+
);
|
|
4626
|
+
}
|
|
4627
|
+
async function cleanBuildDirectory(viteConfig, ctx) {
|
|
4628
|
+
let buildDirectory = ctx.reactRouterConfig.buildDirectory;
|
|
4629
|
+
let isWithinRoot = () => {
|
|
4630
|
+
let relativePath = path6.relative(ctx.rootDirectory, buildDirectory);
|
|
4631
|
+
return !relativePath.startsWith("..") && !path6.isAbsolute(relativePath);
|
|
4632
|
+
};
|
|
4633
|
+
if (viteConfig.build.emptyOutDir ?? isWithinRoot()) {
|
|
4634
|
+
await (0, import_promises2.rm)(buildDirectory, { force: true, recursive: true });
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
async function cleanViteManifests(environmentsOptions, ctx) {
|
|
4638
|
+
let viteManifestPaths = Object.entries(environmentsOptions).map(
|
|
4639
|
+
([environmentName, options]) => {
|
|
4640
|
+
let outDir = options.build?.outDir;
|
|
4641
|
+
invariant(outDir, `Expected build.outDir for ${environmentName}`);
|
|
4642
|
+
return path6.join(outDir, ".vite/manifest.json");
|
|
4643
|
+
}
|
|
4644
|
+
);
|
|
4645
|
+
await Promise.all(
|
|
4646
|
+
viteManifestPaths.map(async (viteManifestPath) => {
|
|
4647
|
+
let manifestExists = (0, import_node_fs2.existsSync)(viteManifestPath);
|
|
4648
|
+
if (!manifestExists) return;
|
|
4649
|
+
if (!ctx.viteManifestEnabled) {
|
|
4650
|
+
await (0, import_promises2.rm)(viteManifestPath, { force: true, recursive: true });
|
|
4651
|
+
}
|
|
4652
|
+
let viteDir = path6.dirname(viteManifestPath);
|
|
4653
|
+
let viteDirFiles = await (0, import_promises2.readdir)(viteDir, { recursive: true });
|
|
4654
|
+
if (viteDirFiles.length === 0) {
|
|
4655
|
+
await (0, import_promises2.rm)(viteDir, { force: true, recursive: true });
|
|
4656
|
+
}
|
|
4657
|
+
})
|
|
4658
|
+
);
|
|
4659
|
+
}
|
|
4660
|
+
async function getBuildManifest({
|
|
4661
|
+
reactRouterConfig,
|
|
4662
|
+
rootDirectory
|
|
4663
|
+
}) {
|
|
4664
|
+
let { routes, serverBundles, appDirectory } = reactRouterConfig;
|
|
4665
|
+
if (!serverBundles) {
|
|
4666
|
+
return { routes };
|
|
4667
|
+
}
|
|
4668
|
+
let { normalizePath } = await import("vite");
|
|
4669
|
+
let serverBuildDirectory = getServerBuildDirectory(reactRouterConfig);
|
|
4670
|
+
let resolvedAppDirectory = path6.resolve(rootDirectory, appDirectory);
|
|
4671
|
+
let rootRelativeRoutes = Object.fromEntries(
|
|
4672
|
+
Object.entries(routes).map(([id, route]) => {
|
|
4673
|
+
let filePath = path6.join(resolvedAppDirectory, route.file);
|
|
4674
|
+
let rootRelativeFilePath = normalizePath(
|
|
4675
|
+
path6.relative(rootDirectory, filePath)
|
|
4676
|
+
);
|
|
4677
|
+
return [id, { ...route, file: rootRelativeFilePath }];
|
|
4678
|
+
})
|
|
4679
|
+
);
|
|
4680
|
+
let buildManifest = {
|
|
4681
|
+
serverBundles: {},
|
|
4682
|
+
routeIdToServerBundleId: {},
|
|
4683
|
+
routes: rootRelativeRoutes
|
|
4684
|
+
};
|
|
4685
|
+
await Promise.all(
|
|
4686
|
+
getAddressableRoutes(routes).map(async (route) => {
|
|
4687
|
+
let branch = getRouteBranch(routes, route.id);
|
|
4688
|
+
let serverBundleId = await serverBundles({
|
|
4689
|
+
branch: branch.map(
|
|
4690
|
+
(route2) => configRouteToBranchRoute({
|
|
4691
|
+
...route2,
|
|
4692
|
+
// Ensure absolute paths are passed to the serverBundles function
|
|
4693
|
+
file: path6.join(resolvedAppDirectory, route2.file)
|
|
4694
|
+
})
|
|
4695
|
+
)
|
|
4696
|
+
});
|
|
4697
|
+
if (typeof serverBundleId !== "string") {
|
|
4698
|
+
throw new Error(`The "serverBundles" function must return a string`);
|
|
4699
|
+
}
|
|
4700
|
+
if (reactRouterConfig.future.unstable_viteEnvironmentApi) {
|
|
4701
|
+
if (!/^[a-zA-Z0-9_]+$/.test(serverBundleId)) {
|
|
4702
|
+
throw new Error(
|
|
4703
|
+
`The "serverBundles" function must only return strings containing alphanumeric characters and underscores.`
|
|
4704
|
+
);
|
|
4705
|
+
}
|
|
4706
|
+
} else {
|
|
4707
|
+
if (!/^[a-zA-Z0-9-_]+$/.test(serverBundleId)) {
|
|
4708
|
+
throw new Error(
|
|
4709
|
+
`The "serverBundles" function must only return strings containing alphanumeric characters, hyphens and underscores.`
|
|
4710
|
+
);
|
|
4711
|
+
}
|
|
4712
|
+
}
|
|
4713
|
+
buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;
|
|
4714
|
+
buildManifest.serverBundles[serverBundleId] ??= {
|
|
4715
|
+
id: serverBundleId,
|
|
4716
|
+
file: normalizePath(
|
|
4717
|
+
path6.join(
|
|
4718
|
+
path6.relative(
|
|
4719
|
+
rootDirectory,
|
|
4720
|
+
path6.join(serverBuildDirectory, serverBundleId)
|
|
4721
|
+
),
|
|
4722
|
+
reactRouterConfig.serverBuildFile
|
|
4723
|
+
)
|
|
4724
|
+
)
|
|
4725
|
+
};
|
|
4726
|
+
})
|
|
4727
|
+
);
|
|
4728
|
+
return buildManifest;
|
|
4729
|
+
}
|
|
4730
|
+
function mergeEnvironmentOptions(base, ...overrides) {
|
|
4731
|
+
let vite2 = getVite();
|
|
4732
|
+
return overrides.reduce(
|
|
4733
|
+
(merged, override) => vite2.mergeConfig(merged, override, false),
|
|
4734
|
+
base
|
|
4735
|
+
);
|
|
4736
|
+
}
|
|
4737
|
+
async function getEnvironmentOptionsResolvers(ctx, viteCommand) {
|
|
4738
|
+
let { serverBuildFile, serverModuleFormat } = ctx.reactRouterConfig;
|
|
4739
|
+
let packageRoot = path6.dirname(
|
|
4740
|
+
require.resolve("@react-router/dev/package.json")
|
|
4741
|
+
);
|
|
4742
|
+
let { moduleSyncEnabled } = await import(`file:///${path6.join(packageRoot, "module-sync-enabled/index.mjs")}`);
|
|
4743
|
+
let vite2 = getVite();
|
|
4744
|
+
function getBaseOptions({
|
|
4745
|
+
viteUserConfig
|
|
4746
|
+
}) {
|
|
4747
|
+
const rollupOptions = {
|
|
4748
|
+
preserveEntrySignatures: "exports-only",
|
|
4749
|
+
// Silence Rollup "use client" warnings
|
|
4750
|
+
// Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
|
|
4751
|
+
onwarn(warning, defaultHandler) {
|
|
4752
|
+
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
|
|
4753
|
+
return;
|
|
4754
|
+
}
|
|
4755
|
+
let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
|
|
4756
|
+
if (userHandler) {
|
|
4757
|
+
userHandler(warning, defaultHandler);
|
|
4758
|
+
} else {
|
|
4759
|
+
defaultHandler(warning);
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
};
|
|
4763
|
+
return {
|
|
4764
|
+
build: {
|
|
4765
|
+
cssMinify: viteUserConfig.build?.cssMinify ?? true,
|
|
4766
|
+
manifest: true,
|
|
4767
|
+
// The manifest is enabled for all builds to detect SSR-only assets
|
|
4768
|
+
rollupOptions
|
|
4769
|
+
}
|
|
4770
|
+
};
|
|
4771
|
+
}
|
|
4772
|
+
function getBaseServerOptions({
|
|
4773
|
+
viteUserConfig
|
|
4774
|
+
}) {
|
|
4775
|
+
let maybeModuleSyncConditions = [
|
|
4776
|
+
...moduleSyncEnabled ? ["module-sync"] : []
|
|
4777
|
+
];
|
|
4778
|
+
let maybeDevelopmentConditions = viteCommand === "build" ? [] : ["development"];
|
|
4779
|
+
let maybeDefaultServerConditions = vite2.defaultServerConditions || [];
|
|
4780
|
+
let defaultExternalConditions = ["node"];
|
|
4781
|
+
let baseConditions = [
|
|
4782
|
+
...maybeDevelopmentConditions,
|
|
4783
|
+
...maybeModuleSyncConditions
|
|
4784
|
+
];
|
|
4785
|
+
return mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
|
|
4786
|
+
resolve: {
|
|
4787
|
+
external: (
|
|
4788
|
+
// If `unstable_viteEnvironmentApi` is `true`, `resolve.external` is set in the `configEnvironment` hook
|
|
4789
|
+
ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? void 0 : ssrExternals
|
|
4790
|
+
),
|
|
4791
|
+
conditions: [...baseConditions, ...maybeDefaultServerConditions],
|
|
4792
|
+
externalConditions: [...baseConditions, ...defaultExternalConditions]
|
|
4793
|
+
},
|
|
4794
|
+
build: {
|
|
4795
|
+
// We move SSR-only assets to client assets. Note that the
|
|
4796
|
+
// SSR build can also emit code-split JS files (e.g., by
|
|
4797
|
+
// dynamic import) under the same assets directory
|
|
4798
|
+
// regardless of "ssrEmitAssets" option, so we also need to
|
|
4799
|
+
// keep these JS files to be kept as-is.
|
|
4800
|
+
ssrEmitAssets: true,
|
|
4801
|
+
copyPublicDir: false,
|
|
4802
|
+
// The client only uses assets in the public directory
|
|
4803
|
+
rollupOptions: {
|
|
4804
|
+
input: (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig.environments?.ssr?.build?.rollupOptions?.input : viteUserConfig.build?.rollupOptions?.input) ?? virtual.serverBuild.id,
|
|
4805
|
+
output: {
|
|
4806
|
+
entryFileNames: serverBuildFile,
|
|
4807
|
+
format: serverModuleFormat
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
}
|
|
4811
|
+
});
|
|
4812
|
+
}
|
|
4813
|
+
let environmentOptionsResolvers = {
|
|
4814
|
+
client: ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
|
|
4815
|
+
build: {
|
|
4816
|
+
rollupOptions: {
|
|
4817
|
+
input: [
|
|
4818
|
+
ctx.entryClientFilePath,
|
|
4819
|
+
...Object.values(ctx.reactRouterConfig.routes).flatMap(
|
|
4820
|
+
(route) => {
|
|
4821
|
+
let routeFilePath = path6.resolve(
|
|
4822
|
+
ctx.reactRouterConfig.appDirectory,
|
|
4823
|
+
route.file
|
|
4824
|
+
);
|
|
4825
|
+
let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
|
|
4826
|
+
let code = (0, import_node_fs2.readFileSync)(routeFilePath, "utf-8");
|
|
4827
|
+
return [
|
|
4828
|
+
`${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
4829
|
+
...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
|
|
4830
|
+
(exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
|
|
4831
|
+
) : []
|
|
4832
|
+
].filter(isNonNullable);
|
|
4833
|
+
}
|
|
4834
|
+
)
|
|
4835
|
+
],
|
|
4836
|
+
output: (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig?.environments?.client?.build?.rollupOptions?.output : viteUserConfig?.build?.rollupOptions?.output) ?? {
|
|
4837
|
+
entryFileNames: ({ moduleIds }) => {
|
|
4838
|
+
let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
|
|
4839
|
+
let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(routeChunkModuleId)?.replace(
|
|
4840
|
+
"unstable_",
|
|
4841
|
+
""
|
|
4842
|
+
) : null;
|
|
4843
|
+
let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
|
|
4844
|
+
let assetsDir = (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig?.environments?.client?.build?.assetsDir : null) ?? viteUserConfig?.build?.assetsDir ?? "assets";
|
|
4845
|
+
return path6.posix.join(
|
|
4846
|
+
assetsDir,
|
|
4847
|
+
`[name]${routeChunkSuffix}-[hash].js`
|
|
4848
|
+
);
|
|
4849
|
+
}
|
|
4850
|
+
}
|
|
4851
|
+
},
|
|
4852
|
+
outDir: getClientBuildDirectory(ctx.reactRouterConfig)
|
|
4853
|
+
}
|
|
4854
|
+
})
|
|
4855
|
+
};
|
|
4856
|
+
let serverBundleIds = getServerBundleIds(ctx);
|
|
4857
|
+
if (serverBundleIds) {
|
|
4858
|
+
for (let serverBundleId of serverBundleIds) {
|
|
4859
|
+
const environmentName = `${SSR_BUNDLE_PREFIX}${serverBundleId}`;
|
|
4860
|
+
environmentOptionsResolvers[environmentName] = ({ viteUserConfig }) => mergeEnvironmentOptions(
|
|
4861
|
+
getBaseServerOptions({ viteUserConfig }),
|
|
4862
|
+
{
|
|
4863
|
+
build: {
|
|
4864
|
+
outDir: getServerBuildDirectory(ctx.reactRouterConfig, {
|
|
4865
|
+
serverBundleId
|
|
4866
|
+
})
|
|
4867
|
+
}
|
|
4868
|
+
},
|
|
4869
|
+
// Ensure server bundle environments extend the user's SSR
|
|
4870
|
+
// environment config if it exists
|
|
4871
|
+
viteUserConfig.environments?.ssr ?? {}
|
|
4872
|
+
);
|
|
4873
|
+
}
|
|
4874
|
+
} else {
|
|
4875
|
+
environmentOptionsResolvers.ssr = ({ viteUserConfig }) => mergeEnvironmentOptions(getBaseServerOptions({ viteUserConfig }), {
|
|
4876
|
+
build: {
|
|
4877
|
+
outDir: getServerBuildDirectory(ctx.reactRouterConfig)
|
|
4878
|
+
}
|
|
4879
|
+
});
|
|
4880
|
+
}
|
|
4881
|
+
return environmentOptionsResolvers;
|
|
4882
|
+
}
|
|
4883
|
+
function resolveEnvironmentsOptions(environmentResolvers, resolverOptions) {
|
|
4884
|
+
let environmentOptions = {};
|
|
4885
|
+
for (let [environmentName, resolver] of Object.entries(
|
|
4886
|
+
environmentResolvers
|
|
4887
|
+
)) {
|
|
4888
|
+
environmentOptions[environmentName] = resolver(resolverOptions);
|
|
4889
|
+
}
|
|
4890
|
+
return environmentOptions;
|
|
4891
|
+
}
|
|
4892
|
+
async function getEnvironmentsOptions(ctx, viteCommand, resolverOptions) {
|
|
4893
|
+
let environmentOptionsResolvers = await getEnvironmentOptionsResolvers(
|
|
4894
|
+
ctx,
|
|
4895
|
+
viteCommand
|
|
4896
|
+
);
|
|
4897
|
+
return resolveEnvironmentsOptions(
|
|
4898
|
+
environmentOptionsResolvers,
|
|
4899
|
+
resolverOptions
|
|
4900
|
+
);
|
|
4901
|
+
}
|
|
4902
|
+
function isNonNullable(x) {
|
|
4903
|
+
return x != null;
|
|
4904
|
+
}
|
|
4905
|
+
async function asyncFlatten(arr) {
|
|
4906
|
+
do {
|
|
4907
|
+
arr = (await Promise.all(arr)).flat(Infinity);
|
|
4908
|
+
} while (arr.some((v2) => v2?.then));
|
|
4909
|
+
return arr;
|
|
4910
|
+
}
|
|
4911
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
4912
|
+
0 && (module.exports = {
|
|
4913
|
+
reactRouter
|
|
4914
|
+
});
|