@react-router/dev 7.0.0-pre.2 → 7.0.0-pre.3

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.
Files changed (67) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/cli/index.d.ts +2 -1
  3. package/dist/cli/index.js +1352 -8
  4. package/dist/routes.d.ts +4 -2
  5. package/dist/routes.js +181 -11
  6. package/dist/typescript/plugin.d.ts +5 -2
  7. package/dist/typescript/plugin.js +479 -31
  8. package/dist/vite/cloudflare.d.ts +1 -1
  9. package/dist/vite/cloudflare.js +171 -5
  10. package/dist/vite.d.ts +2 -2
  11. package/dist/vite.js +2394 -5
  12. package/package.json +28 -7
  13. package/dist/cli/commands.d.ts +0 -13
  14. package/dist/cli/commands.js +0 -179
  15. package/dist/cli/detectPackageManager.d.ts +0 -10
  16. package/dist/cli/detectPackageManager.js +0 -39
  17. package/dist/cli/run.d.ts +0 -5
  18. package/dist/cli/run.js +0 -188
  19. package/dist/cli/useJavascript.d.ts +0 -4
  20. package/dist/cli/useJavascript.js +0 -66
  21. package/dist/colors.d.ts +0 -17
  22. package/dist/colors.js +0 -49
  23. package/dist/config/format.d.ts +0 -5
  24. package/dist/config/format.js +0 -68
  25. package/dist/config/routes.d.ts +0 -129
  26. package/dist/config/routes.js +0 -253
  27. package/dist/config/serverModes.d.ts +0 -9
  28. package/dist/invariant.d.ts +0 -2
  29. package/dist/invariant.js +0 -20
  30. package/dist/manifest.d.ts +0 -28
  31. package/dist/typescript/typegen.d.ts +0 -10
  32. package/dist/typescript/typegen.js +0 -190
  33. package/dist/vite/babel.d.ts +0 -20
  34. package/dist/vite/babel.js +0 -49
  35. package/dist/vite/build.d.ts +0 -15
  36. package/dist/vite/build.js +0 -249
  37. package/dist/vite/cloudflare-dev-proxy.d.ts +0 -21
  38. package/dist/vite/cloudflare-dev-proxy.js +0 -89
  39. package/dist/vite/combine-urls-test.d.ts +0 -1
  40. package/dist/vite/combine-urls.d.ts +0 -1
  41. package/dist/vite/combine-urls.js +0 -20
  42. package/dist/vite/config.d.ts +0 -234
  43. package/dist/vite/config.js +0 -282
  44. package/dist/vite/dev.d.ts +0 -15
  45. package/dist/vite/dev.js +0 -81
  46. package/dist/vite/import-vite-esm-sync.d.ts +0 -4
  47. package/dist/vite/import-vite-esm-sync.js +0 -28
  48. package/dist/vite/node-adapter.d.ts +0 -6
  49. package/dist/vite/node-adapter.js +0 -90
  50. package/dist/vite/plugin.d.ts +0 -75
  51. package/dist/vite/plugin.js +0 -1301
  52. package/dist/vite/profiler.d.ts +0 -5
  53. package/dist/vite/profiler.js +0 -55
  54. package/dist/vite/remove-exports-test.d.ts +0 -1
  55. package/dist/vite/remove-exports.d.ts +0 -2
  56. package/dist/vite/remove-exports.js +0 -148
  57. package/dist/vite/resolve-file-url.d.ts +0 -3
  58. package/dist/vite/resolve-file-url.js +0 -53
  59. package/dist/vite/styles.d.ts +0 -14
  60. package/dist/vite/styles.js +0 -199
  61. package/dist/vite/vite-node.d.ts +0 -9
  62. package/dist/vite/vite-node.js +0 -57
  63. package/dist/vite/vmod.d.ts +0 -3
  64. package/dist/vite/vmod.js +0 -21
  65. package/dist/vite/with-props.d.ts +0 -4
  66. package/dist/vite/with-props.js +0 -151
  67. /package/dist/{vite/static → static}/refresh-utils.cjs +0 -0
@@ -1,1301 +0,0 @@
1
- /**
2
- * @react-router/dev v7.0.0-pre.2
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
-
13
- Object.defineProperty(exports, '__esModule', { value: true });
14
-
15
- var node_crypto = require('node:crypto');
16
- var path = require('node:path');
17
- var url = require('node:url');
18
- var fse = require('fs-extra');
19
- var babel$1 = require('@babel/core');
20
- var reactRouter = require('react-router');
21
- var esModuleLexer = require('es-module-lexer');
22
- var jsesc = require('jsesc');
23
- var colors = require('picocolors');
24
- var invariant = require('../invariant.js');
25
- var babel = require('./babel.js');
26
- var nodeAdapter = require('./node-adapter.js');
27
- var styles = require('./styles.js');
28
- var vmod = require('./vmod.js');
29
- var resolveFileUrl = require('./resolve-file-url.js');
30
- var combineUrls = require('./combine-urls.js');
31
- var removeExports = require('./remove-exports.js');
32
- var importViteEsmSync = require('./import-vite-esm-sync.js');
33
- var config = require('./config.js');
34
- var withProps = require('./with-props.js');
35
- var viteNode = require('./vite-node.js');
36
- var parser = require('@babel/parser');
37
-
38
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
39
-
40
- function _interopNamespace(e) {
41
- if (e && e.__esModule) return e;
42
- var n = Object.create(null);
43
- if (e) {
44
- Object.keys(e).forEach(function (k) {
45
- if (k !== 'default') {
46
- var d = Object.getOwnPropertyDescriptor(e, k);
47
- Object.defineProperty(n, k, d.get ? d : {
48
- enumerable: true,
49
- get: function () { return e[k]; }
50
- });
51
- }
52
- });
53
- }
54
- n["default"] = e;
55
- return Object.freeze(n);
56
- }
57
-
58
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
59
- var url__namespace = /*#__PURE__*/_interopNamespace(url);
60
- var fse__namespace = /*#__PURE__*/_interopNamespace(fse);
61
- var babel__default = /*#__PURE__*/_interopDefaultLegacy(babel$1);
62
- var jsesc__default = /*#__PURE__*/_interopDefaultLegacy(jsesc);
63
- var colors__default = /*#__PURE__*/_interopDefaultLegacy(colors);
64
-
65
- async function resolveViteConfig({
66
- configFile,
67
- mode,
68
- root
69
- }) {
70
- let vite = await import('vite');
71
- let viteConfig = await vite.resolveConfig({
72
- mode,
73
- configFile,
74
- root
75
- }, "build",
76
- // command
77
- "production",
78
- // default mode
79
- "production" // default NODE_ENV
80
- );
81
- if (typeof viteConfig.build.manifest === "string") {
82
- throw new Error("Custom Vite manifest paths are not supported");
83
- }
84
- return viteConfig;
85
- }
86
- async function extractPluginContext(viteConfig) {
87
- return viteConfig["__reactRouterPluginContext"];
88
- }
89
- async function loadPluginContext({
90
- configFile,
91
- root
92
- }) {
93
- if (!root) {
94
- root = process.env.REACT_ROUTER_ROOT || process.cwd();
95
- }
96
- configFile = configFile ?? findConfig(root, "vite.config", [".ts", ".cts", ".mts", ".js", ".cjs", ".mjs"]);
97
- if (!configFile) {
98
- console.error(colors__default["default"].red("Vite config file not found"));
99
- process.exit(1);
100
- }
101
- let viteConfig = await resolveViteConfig({
102
- configFile,
103
- root
104
- });
105
- let ctx = await extractPluginContext(viteConfig);
106
- if (!ctx) {
107
- console.error(colors__default["default"].red("React Router Vite plugin not found in Vite config"));
108
- process.exit(1);
109
- }
110
- return ctx;
111
- }
112
- const SERVER_ONLY_ROUTE_EXPORTS = ["loader", "action", "headers"];
113
- const CLIENT_ROUTE_EXPORTS = ["clientAction", "clientLoader", "default", "ErrorBoundary", "handle", "HydrateFallback", "Layout", "links", "meta", "shouldRevalidate"];
114
- // Each route gets its own virtual module marked with an entry query string
115
- const ROUTE_ENTRY_QUERY_STRING = "?route-entry=1";
116
- const isRouteEntry = id => {
117
- return id.endsWith(ROUTE_ENTRY_QUERY_STRING);
118
- };
119
- let serverBuildId = vmod.id("server-build");
120
- let serverManifestId = vmod.id("server-manifest");
121
- let browserManifestId = vmod.id("browser-manifest");
122
- let hmrRuntimeId = vmod.id("hmr-runtime");
123
- let injectHmrRuntimeId = vmod.id("inject-hmr-runtime");
124
- const resolveRelativeRouteFilePath = (route, reactRouterConfig) => {
125
- let vite = importViteEsmSync.importViteEsmSync();
126
- let file = route.file;
127
- let fullPath = path__namespace.resolve(reactRouterConfig.appDirectory, file);
128
- return vite.normalizePath(fullPath);
129
- };
130
- let vmods = [serverBuildId, serverManifestId, browserManifestId];
131
- const invalidateVirtualModules = viteDevServer => {
132
- vmods.forEach(vmod$1 => {
133
- let mod = viteDevServer.moduleGraph.getModuleById(vmod.resolve(vmod$1));
134
- if (mod) {
135
- viteDevServer.moduleGraph.invalidateModule(mod);
136
- }
137
- });
138
- };
139
- const getHash = (source, maxLength) => {
140
- let hash = node_crypto.createHash("sha256").update(source).digest("hex");
141
- return typeof maxLength === "number" ? hash.slice(0, maxLength) : hash;
142
- };
143
- const resolveChunk = (ctx, viteManifest, absoluteFilePath) => {
144
- let vite = importViteEsmSync.importViteEsmSync();
145
- let rootRelativeFilePath = vite.normalizePath(path__namespace.relative(ctx.rootDirectory, absoluteFilePath));
146
- let entryChunk = viteManifest[rootRelativeFilePath + ROUTE_ENTRY_QUERY_STRING] ?? viteManifest[rootRelativeFilePath];
147
- if (!entryChunk) {
148
- let knownManifestKeys = Object.keys(viteManifest).map(key => '"' + key + '"').join(", ");
149
- throw new Error(`No manifest entry found for "${rootRelativeFilePath}". Known manifest keys: ${knownManifestKeys}`);
150
- }
151
- return entryChunk;
152
- };
153
- const getReactRouterManifestBuildAssets = (ctx, viteManifest, entryFilePath, prependedAssetFilePaths = []) => {
154
- let entryChunk = resolveChunk(ctx, viteManifest, entryFilePath);
155
- // This is here to support prepending client entry assets to the root route
156
- let prependedAssetChunks = prependedAssetFilePaths.map(filePath => resolveChunk(ctx, viteManifest, filePath));
157
- let chunks = resolveDependantChunks(viteManifest, [...prependedAssetChunks, entryChunk]);
158
- return {
159
- module: `${ctx.publicPath}${entryChunk.file}`,
160
- imports: dedupe(chunks.flatMap(e => e.imports ?? [])).map(imported => {
161
- return `${ctx.publicPath}${viteManifest[imported].file}`;
162
- }) ?? [],
163
- css: dedupe(chunks.flatMap(e => e.css ?? [])).map(href => {
164
- return `${ctx.publicPath}${href}`;
165
- }) ?? []
166
- };
167
- };
168
- function resolveDependantChunks(viteManifest, entryChunks) {
169
- let chunks = new Set();
170
- function walk(chunk) {
171
- if (chunks.has(chunk)) {
172
- return;
173
- }
174
- chunks.add(chunk);
175
- if (chunk.imports) {
176
- for (let importKey of chunk.imports) {
177
- walk(viteManifest[importKey]);
178
- }
179
- }
180
- }
181
- for (let entryChunk of entryChunks) {
182
- walk(entryChunk);
183
- }
184
- return Array.from(chunks);
185
- }
186
- function dedupe(array) {
187
- return [...new Set(array)];
188
- }
189
- const writeFileSafe = async (file, contents) => {
190
- await fse__namespace.ensureDir(path__namespace.dirname(file));
191
- await fse__namespace.writeFile(file, contents);
192
- };
193
- const getRouteManifestModuleExports = async (viteChildCompiler, ctx) => {
194
- let entries = await Promise.all(Object.entries(ctx.reactRouterConfig.routes).map(async ([key, route]) => {
195
- let sourceExports = await getRouteModuleExports(viteChildCompiler, ctx, route.file);
196
- return [key, sourceExports];
197
- }));
198
- return Object.fromEntries(entries);
199
- };
200
- const getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
201
- if (!viteChildCompiler) {
202
- throw new Error("Vite child compiler not found");
203
- }
204
- // We transform the route module code with the Vite child compiler so that we
205
- // can parse the exports from non-JS files like MDX. This ensures that we can
206
- // understand the exports from anything that Vite can compile to JS, not just
207
- // the route file formats that the Remix compiler historically supported.
208
- let ssr = true;
209
- let {
210
- pluginContainer,
211
- moduleGraph
212
- } = viteChildCompiler;
213
- let routePath = path__namespace.resolve(ctx.reactRouterConfig.appDirectory, routeFile);
214
- let url = resolveFileUrl.resolveFileUrl(ctx, routePath);
215
- let resolveId = async () => {
216
- let result = await pluginContainer.resolveId(url, undefined, {
217
- ssr
218
- });
219
- if (!result) throw new Error(`Could not resolve module ID for ${url}`);
220
- return result.id;
221
- };
222
- let [id, code] = await Promise.all([resolveId(), (readRouteFile === null || readRouteFile === void 0 ? void 0 : readRouteFile()) ?? fse__namespace.readFile(routePath, "utf-8"),
223
- // pluginContainer.transform(...) fails if we don't do this first:
224
- moduleGraph.ensureEntryFromUrl(url, ssr)]);
225
- let transformed = await pluginContainer.transform(code, id, {
226
- ssr
227
- });
228
- let [, exports] = esModuleLexer.parse(transformed.code);
229
- let exportNames = exports.map(e => e.n);
230
- return exportNames;
231
- };
232
- const getServerBundleBuildConfig = viteUserConfig => {
233
- if (!("__reactRouterServerBundleBuildConfig" in viteUserConfig) || !viteUserConfig.__reactRouterServerBundleBuildConfig) {
234
- return null;
235
- }
236
- return viteUserConfig.__reactRouterServerBundleBuildConfig;
237
- };
238
- let getServerBuildDirectory = ctx => path__namespace.join(ctx.reactRouterConfig.buildDirectory, "server", ...(ctx.serverBundleBuildConfig ? [ctx.serverBundleBuildConfig.serverBundleId] : []));
239
- let getClientBuildDirectory = reactRouterConfig => path__namespace.join(reactRouterConfig.buildDirectory, "client");
240
- let defaultEntriesDir = path__namespace.resolve(__dirname, "..", "config", "defaults");
241
- let defaultEntries = fse__namespace.readdirSync(defaultEntriesDir).map(filename => path__namespace.join(defaultEntriesDir, filename));
242
- invariant(defaultEntries.length > 0, "No default entries found");
243
- let reactRouterDevLoadContext = () => ({});
244
- // Inlined from https://github.com/jsdf/deep-freeze
245
- let deepFreeze = o => {
246
- Object.freeze(o);
247
- let oIsFunction = typeof o === "function";
248
- let hasOwnProp = Object.prototype.hasOwnProperty;
249
- Object.getOwnPropertyNames(o).forEach(function (prop) {
250
- 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])) {
251
- deepFreeze(o[prop]);
252
- }
253
- });
254
- return o;
255
- };
256
- /**
257
- * React Router [Vite plugin.](https://vitejs.dev/guide/using-plugins.html)
258
- */
259
- const reactRouterVitePlugin = _config => {
260
- let reactRouterUserConfig = _config ?? {};
261
- // Prevent mutations to the user config
262
- reactRouterUserConfig = deepFreeze(reactRouterUserConfig);
263
- let viteCommand;
264
- let viteUserConfig;
265
- let viteConfigEnv;
266
- let viteConfig;
267
- let cssModulesManifest = {};
268
- let viteChildCompiler = null;
269
- let routesViteNodeContext = null;
270
- let ssrExternals = isInReactRouterMonorepo() ? [
271
- // This is only needed within this repo because these packages
272
- // are linked to a directory outside of node_modules so Vite
273
- // treats them as internal code by default.
274
- "react-router", "react-router-dom", "@react-router/architect", "@react-router/cloudflare", "@react-router/dev", "@react-router/express", "@react-router/node", "@react-router/serve"] : undefined;
275
- // This is initialized by `updatePluginContext` during Vite's `config`
276
- // hook, so most of the code can assume this defined without null check.
277
- // During dev, `updatePluginContext` is called again on every config file
278
- // change or route file addition/removal.
279
- let ctx;
280
- /** Mutates `ctx` as a side-effect */
281
- let updatePluginContext = async ({
282
- routeConfigChanged = false
283
- } = {}) => {
284
- var _viteUserConfig$build;
285
- let rootDirectory = viteUserConfig.root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd();
286
- invariant(routesViteNodeContext);
287
- let reactRouterConfig = await config.resolveReactRouterConfig({
288
- rootDirectory,
289
- reactRouterUserConfig,
290
- routeConfigChanged,
291
- viteUserConfig,
292
- viteCommand,
293
- routesViteNodeContext
294
- });
295
- let {
296
- entryClientFilePath,
297
- entryServerFilePath
298
- } = await config.resolveEntryFiles({
299
- rootDirectory,
300
- reactRouterConfig
301
- });
302
- let publicPath = config.resolvePublicPath(viteUserConfig);
303
- let viteManifestEnabled = ((_viteUserConfig$build = viteUserConfig.build) === null || _viteUserConfig$build === void 0 ? void 0 : _viteUserConfig$build.manifest) === true;
304
- let ssrBuildCtx = viteConfigEnv.isSsrBuild && viteCommand === "build" ? {
305
- isSsrBuild: true,
306
- getReactRouterServerManifest: async () => (await generateReactRouterManifestsForBuild()).reactRouterServerManifest,
307
- serverBundleBuildConfig: getServerBundleBuildConfig(viteUserConfig)
308
- } : {
309
- isSsrBuild: false
310
- };
311
- ctx = {
312
- reactRouterConfig,
313
- rootDirectory,
314
- entryClientFilePath,
315
- entryServerFilePath,
316
- publicPath,
317
- viteManifestEnabled,
318
- ...ssrBuildCtx
319
- };
320
- };
321
- let pluginIndex = pluginName => {
322
- invariant(viteConfig);
323
- return viteConfig.plugins.findIndex(plugin => plugin.name === pluginName);
324
- };
325
- let getServerEntry = async () => {
326
- invariant(viteConfig, "viteconfig required to generate the server entry");
327
- let routes = ctx.serverBundleBuildConfig ?
328
- // For server bundle builds, the server build should only import the
329
- // routes for this bundle rather than importing all routes
330
- ctx.serverBundleBuildConfig.routes :
331
- // Otherwise, all routes are imported as usual
332
- ctx.reactRouterConfig.routes;
333
- return `
334
- import * as entryServer from ${JSON.stringify(resolveFileUrl.resolveFileUrl(ctx, ctx.entryServerFilePath))};
335
- ${Object.keys(routes).map((key, index) => {
336
- let route = routes[key];
337
- return `import * as route${index} from ${JSON.stringify(resolveFileUrl.resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)) + ROUTE_ENTRY_QUERY_STRING)};`;
338
- }).join("\n")}
339
- export { default as assets } from ${JSON.stringify(serverManifestId)};
340
- export const assetsBuildDirectory = ${JSON.stringify(path__namespace.relative(ctx.rootDirectory, getClientBuildDirectory(ctx.reactRouterConfig)))};
341
- export const basename = ${JSON.stringify(ctx.reactRouterConfig.basename)};
342
- export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
343
- export const isSpaMode = ${!ctx.reactRouterConfig.ssr && ctx.reactRouterConfig.prerender == null};
344
- export const publicPath = ${JSON.stringify(ctx.publicPath)};
345
- export const entry = { module: entryServer };
346
- export const routes = {
347
- ${Object.keys(routes).map((key, index) => {
348
- let route = routes[key];
349
- return `${JSON.stringify(key)}: {
350
- id: ${JSON.stringify(route.id)},
351
- parentId: ${JSON.stringify(route.parentId)},
352
- path: ${JSON.stringify(route.path)},
353
- index: ${JSON.stringify(route.index)},
354
- caseSensitive: ${JSON.stringify(route.caseSensitive)},
355
- module: route${index}
356
- }`;
357
- }).join(",\n ")}
358
- };`;
359
- };
360
- let loadViteManifest = async directory => {
361
- let manifestContents = await fse__namespace.readFile(path__namespace.resolve(directory, ".vite", "manifest.json"), "utf-8");
362
- return JSON.parse(manifestContents);
363
- };
364
- let hasDependency = name => {
365
- try {
366
- return Boolean(require.resolve(name, {
367
- paths: [ctx.rootDirectory]
368
- }));
369
- } catch (err) {
370
- return false;
371
- }
372
- };
373
- let getViteManifestAssetPaths = viteManifest => {
374
- // Get .css?url imports and CSS entry points
375
- let cssUrlPaths = Object.values(viteManifest).filter(chunk => chunk.file.endsWith(".css")).map(chunk => chunk.file);
376
- // Get bundled CSS files and generic asset types
377
- let chunkAssetPaths = Object.values(viteManifest).flatMap(chunk => chunk.assets ?? []);
378
- return new Set([...cssUrlPaths, ...chunkAssetPaths]);
379
- };
380
- let generateReactRouterManifestsForBuild = async () => {
381
- invariant(viteConfig);
382
- let viteManifest = await loadViteManifest(getClientBuildDirectory(ctx.reactRouterConfig));
383
- let entry = getReactRouterManifestBuildAssets(ctx, viteManifest, ctx.entryClientFilePath);
384
- let browserRoutes = {};
385
- let serverRoutes = {};
386
- let routeManifestExports = await getRouteManifestModuleExports(viteChildCompiler, ctx);
387
- for (let [key, route] of Object.entries(ctx.reactRouterConfig.routes)) {
388
- var _ctx$serverBundleBuil;
389
- let routeFilePath = path__namespace.join(ctx.reactRouterConfig.appDirectory, route.file);
390
- let sourceExports = routeManifestExports[key];
391
- let isRootRoute = route.parentId === undefined;
392
- let routeManifestEntry = {
393
- id: route.id,
394
- parentId: route.parentId,
395
- path: route.path,
396
- index: route.index,
397
- caseSensitive: route.caseSensitive,
398
- hasAction: sourceExports.includes("action"),
399
- hasLoader: sourceExports.includes("loader"),
400
- hasClientAction: sourceExports.includes("clientAction"),
401
- hasClientLoader: sourceExports.includes("clientLoader"),
402
- hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
403
- ...getReactRouterManifestBuildAssets(ctx, viteManifest, routeFilePath,
404
- // If this is the root route, we also need to include assets from the
405
- // client entry file as this is a common way for consumers to import
406
- // global reset styles, etc.
407
- isRootRoute ? [ctx.entryClientFilePath] : [])
408
- };
409
- browserRoutes[key] = routeManifestEntry;
410
- let serverBundleRoutes = (_ctx$serverBundleBuil = ctx.serverBundleBuildConfig) === null || _ctx$serverBundleBuil === void 0 ? void 0 : _ctx$serverBundleBuil.routes;
411
- if (!serverBundleRoutes || serverBundleRoutes[key]) {
412
- serverRoutes[key] = routeManifestEntry;
413
- }
414
- }
415
- let fingerprintedValues = {
416
- entry,
417
- routes: browserRoutes
418
- };
419
- let version = getHash(JSON.stringify(fingerprintedValues), 8);
420
- let manifestPath = path__namespace.posix.join(viteConfig.build.assetsDir, `manifest-${version}.js`);
421
- let url = `${ctx.publicPath}${manifestPath}`;
422
- let nonFingerprintedValues = {
423
- url,
424
- version
425
- };
426
- let reactRouterBrowserManifest = {
427
- ...fingerprintedValues,
428
- ...nonFingerprintedValues
429
- };
430
- // Write the browser manifest to disk as part of the build process
431
- await writeFileSafe(path__namespace.join(getClientBuildDirectory(ctx.reactRouterConfig), manifestPath), `window.__reactRouterManifest=${JSON.stringify(reactRouterBrowserManifest)};`);
432
- // The server manifest is the same as the browser manifest, except for
433
- // server bundle builds which only includes routes for the current bundle,
434
- // otherwise the server and client have the same routes
435
- let reactRouterServerManifest = {
436
- ...reactRouterBrowserManifest,
437
- routes: serverRoutes
438
- };
439
- return {
440
- reactRouterBrowserManifest,
441
- reactRouterServerManifest
442
- };
443
- };
444
- // In dev, the server and browser manifests are the same
445
- let getReactRouterManifestForDev = async () => {
446
- let routes = {};
447
- let routeManifestExports = await getRouteManifestModuleExports(viteChildCompiler, ctx);
448
- for (let [key, route] of Object.entries(ctx.reactRouterConfig.routes)) {
449
- let sourceExports = routeManifestExports[key];
450
- routes[key] = {
451
- id: route.id,
452
- parentId: route.parentId,
453
- path: route.path,
454
- index: route.index,
455
- caseSensitive: route.caseSensitive,
456
- module: combineUrls.combineURLs(ctx.publicPath, `${resolveFileUrl.resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig))}${ROUTE_ENTRY_QUERY_STRING}`),
457
- hasAction: sourceExports.includes("action"),
458
- hasLoader: sourceExports.includes("loader"),
459
- hasClientAction: sourceExports.includes("clientAction"),
460
- hasClientLoader: sourceExports.includes("clientLoader"),
461
- hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
462
- imports: []
463
- };
464
- }
465
- return {
466
- version: String(Math.random()),
467
- url: combineUrls.combineURLs(ctx.publicPath, vmod.url(browserManifestId)),
468
- hmr: {
469
- runtime: combineUrls.combineURLs(ctx.publicPath, vmod.url(injectHmrRuntimeId))
470
- },
471
- entry: {
472
- module: combineUrls.combineURLs(ctx.publicPath, resolveFileUrl.resolveFileUrl(ctx, ctx.entryClientFilePath)),
473
- imports: []
474
- },
475
- routes
476
- };
477
- };
478
- return [{
479
- name: "react-router",
480
- config: async (_viteUserConfig, _viteConfigEnv) => {
481
- var _viteUserConfig$serve, _viteUserConfig$serve2, _viteUserConfig$build4, _viteUserConfig$build5, _viteUserConfig$build6;
482
- // Preload Vite's ESM build up-front as soon as we're in an async context
483
- await importViteEsmSync.preloadViteEsm();
484
- // Ensure sync import of Vite works after async preload
485
- let vite = importViteEsmSync.importViteEsmSync();
486
- viteUserConfig = _viteUserConfig;
487
- viteConfigEnv = _viteConfigEnv;
488
- viteCommand = viteConfigEnv.command;
489
- routesViteNodeContext = await viteNode.createContext({
490
- root: viteUserConfig.root,
491
- mode: viteConfigEnv.mode,
492
- server: {
493
- watch: viteCommand === "build" ? null : undefined
494
- },
495
- ssr: {
496
- external: ssrExternals
497
- }
498
- });
499
- await updatePluginContext();
500
- Object.assign(process.env, vite.loadEnv(viteConfigEnv.mode, ctx.rootDirectory,
501
- // We override default prefix of "VITE_" with a blank string since
502
- // we're targeting the server, so we want to load all environment
503
- // variables, not just those explicitly marked for the client
504
- ""));
505
- let baseRollupOptions = {
506
- // Silence Rollup "use client" warnings
507
- // Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
508
- onwarn(warning, defaultHandler) {
509
- var _viteUserConfig$build2, _viteUserConfig$build3;
510
- if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
511
- return;
512
- }
513
- if ((_viteUserConfig$build2 = viteUserConfig.build) !== null && _viteUserConfig$build2 !== void 0 && (_viteUserConfig$build3 = _viteUserConfig$build2.rollupOptions) !== null && _viteUserConfig$build3 !== void 0 && _viteUserConfig$build3.onwarn) {
514
- viteUserConfig.build.rollupOptions.onwarn(warning, defaultHandler);
515
- } else {
516
- defaultHandler(warning);
517
- }
518
- }
519
- };
520
- return {
521
- __reactRouterPluginContext: ctx,
522
- appType: viteCommand === "serve" && viteConfigEnv.mode === "production" && ctx.reactRouterConfig.ssr === false ? "spa" : "custom",
523
- ssr: {
524
- external: ssrExternals
525
- },
526
- optimizeDeps: {
527
- include: [
528
- // Pre-bundle React dependencies to avoid React duplicates,
529
- // even if React dependencies are not direct dependencies.
530
- // https://react.dev/warnings/invalid-hook-call-warning#duplicate-react
531
- "react", "react/jsx-runtime", "react/jsx-dev-runtime", "react-dom", "react-dom/client",
532
- // Pre-bundle router dependencies to avoid router duplicates.
533
- // Mismatching routers cause `Error: You must render this element inside a <Remix> element`.
534
- "react-router",
535
- // Check to avoid "Failed to resolve dependency: react-router-dom, present in 'optimizeDeps.include'"
536
- ...(hasDependency("react-router-dom") ? ["react-router-dom"] : [])]
537
- },
538
- esbuild: {
539
- jsx: "automatic",
540
- jsxDev: viteCommand !== "build"
541
- },
542
- resolve: {
543
- dedupe: [
544
- // https://react.dev/warnings/invalid-hook-call-warning#duplicate-react
545
- "react", "react-dom",
546
- // see description for `optimizeDeps.include`
547
- "react-router", "react-router-dom"]
548
- },
549
- base: viteUserConfig.base,
550
- // When consumer provides an allow list for files that can be read by
551
- // the server, ensure that the default entry files are included.
552
- // If we don't do this and a default entry file is used, the server
553
- // will throw an error that the file is not allowed to be read.
554
- // https://vitejs.dev/config/server-options#server-fs-allow
555
- server: (_viteUserConfig$serve = viteUserConfig.server) !== null && _viteUserConfig$serve !== void 0 && (_viteUserConfig$serve2 = _viteUserConfig$serve.fs) !== null && _viteUserConfig$serve2 !== void 0 && _viteUserConfig$serve2.allow ? {
556
- fs: {
557
- allow: defaultEntries
558
- }
559
- } : undefined,
560
- // Vite config options for building
561
- ...(viteCommand === "build" ? {
562
- build: {
563
- cssMinify: ((_viteUserConfig$build4 = viteUserConfig.build) === null || _viteUserConfig$build4 === void 0 ? void 0 : _viteUserConfig$build4.cssMinify) ?? true,
564
- ...(!viteConfigEnv.isSsrBuild ? {
565
- manifest: true,
566
- outDir: getClientBuildDirectory(ctx.reactRouterConfig),
567
- rollupOptions: {
568
- ...baseRollupOptions,
569
- preserveEntrySignatures: "exports-only",
570
- input: [ctx.entryClientFilePath, ...Object.values(ctx.reactRouterConfig.routes).map(route => `${path__namespace.resolve(ctx.reactRouterConfig.appDirectory, route.file)}${ROUTE_ENTRY_QUERY_STRING}`)]
571
- }
572
- } : {
573
- // We move SSR-only assets to client assets. Note that the
574
- // SSR build can also emit code-split JS files (e.g. by
575
- // dynamic import) under the same assets directory
576
- // regardless of "ssrEmitAssets" option, so we also need to
577
- // keep these JS files have to be kept as-is.
578
- ssrEmitAssets: true,
579
- copyPublicDir: false,
580
- // Assets in the public directory are only used by the client
581
- manifest: true,
582
- // We need the manifest to detect SSR-only assets
583
- outDir: getServerBuildDirectory(ctx),
584
- rollupOptions: {
585
- ...baseRollupOptions,
586
- preserveEntrySignatures: "exports-only",
587
- input: ((_viteUserConfig$build5 = viteUserConfig.build) === null || _viteUserConfig$build5 === void 0 ? void 0 : (_viteUserConfig$build6 = _viteUserConfig$build5.rollupOptions) === null || _viteUserConfig$build6 === void 0 ? void 0 : _viteUserConfig$build6.input) ?? serverBuildId,
588
- output: {
589
- entryFileNames: ctx.reactRouterConfig.serverBuildFile,
590
- format: ctx.reactRouterConfig.serverModuleFormat
591
- }
592
- }
593
- })
594
- }
595
- } : undefined),
596
- // Vite config options for SPA preview mode
597
- ...(viteCommand === "serve" && ctx.reactRouterConfig.ssr === false ? {
598
- build: {
599
- manifest: true,
600
- outDir: getClientBuildDirectory(ctx.reactRouterConfig)
601
- }
602
- } : undefined)
603
- };
604
- },
605
- async configResolved(resolvedViteConfig) {
606
- await esModuleLexer.init;
607
- viteConfig = resolvedViteConfig;
608
- invariant(viteConfig);
609
- // We load the same Vite config file again for the child compiler so
610
- // that both parent and child compiler's plugins have independent state.
611
- // If we re-used the `viteUserConfig.plugins` array for the child
612
- // compiler, it could lead to mutating shared state between plugin
613
- // instances in unexpected ways, e.g. during `vite build` the
614
- // `configResolved` plugin hook would be called with `command = "build"`
615
- // by parent and then `command = "serve"` by child, which some plugins
616
- // may respond to by updating state referenced by the parent.
617
- if (!viteConfig.configFile) {
618
- throw new Error("The React Router Vite plugin requires the use of a Vite config file");
619
- }
620
- let vite = importViteEsmSync.importViteEsmSync();
621
- let childCompilerConfigFile = await vite.loadConfigFromFile({
622
- command: viteConfig.command,
623
- mode: viteConfig.mode,
624
- isSsrBuild: ctx.isSsrBuild
625
- }, viteConfig.configFile);
626
- invariant(childCompilerConfigFile, "Vite config file was unable to be resolved for React Router child compiler");
627
- // Validate that commonly used Rollup plugins that need to run before
628
- // ours are in the correct order. This is because Rollup plugins can't
629
- // set `enforce: "pre"` like Vite plugins can. Explicitly validating
630
- // this provides a much nicer developer experience.
631
- let rollupPrePlugins = [{
632
- pluginName: "@mdx-js/rollup",
633
- displayName: "@mdx-js/rollup"
634
- }];
635
- for (let prePlugin of rollupPrePlugins) {
636
- let prePluginIndex = pluginIndex(prePlugin.pluginName);
637
- if (prePluginIndex >= 0 && prePluginIndex > pluginIndex("react-router")) {
638
- throw new Error(`The "${prePlugin.displayName}" plugin should be placed before the React Router plugin in your Vite config file`);
639
- }
640
- }
641
- viteChildCompiler = await vite.createServer({
642
- ...viteUserConfig,
643
- mode: viteConfig.mode,
644
- server: {
645
- watch: viteConfig.command === "build" ? null : undefined,
646
- preTransformRequests: false,
647
- hmr: false
648
- },
649
- configFile: false,
650
- envFile: false,
651
- plugins: [...(childCompilerConfigFile.config.plugins ?? []).flat()
652
- // Exclude this plugin from the child compiler to prevent an
653
- // infinite loop (plugin creates a child compiler with the same
654
- // plugin that creates another child compiler, repeat ad
655
- // infinitum), and to prevent the manifest from being written to
656
- // disk from the child compiler. This is important in the
657
- // production build because the child compiler is a Vite dev
658
- // server and will generate incorrect manifests.
659
- .filter(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")]
660
- });
661
- await viteChildCompiler.pluginContainer.buildStart({});
662
- },
663
- async transform(code, id) {
664
- if (styles.isCssModulesFile(id)) {
665
- cssModulesManifest[id] = code;
666
- }
667
- },
668
- buildStart() {
669
- invariant(viteConfig);
670
- if (viteCommand === "build" && viteConfig.mode === "production" && !viteConfig.build.ssr && viteConfig.build.sourcemap) {
671
- viteConfig.logger.warn(colors__default["default"].yellow("\n" + colors__default["default"].bold(" ⚠️ Source maps are enabled in production\n") + ["This makes your server code publicly", "visible in the browser. This is highly", "discouraged! If you insist, ensure that", "you are using environment variables for", "secrets and not hard-coding them in", "your source code."].map(line => " " + line).join("\n") + "\n"));
672
- }
673
- },
674
- async configureServer(viteDevServer) {
675
- reactRouter.unstable_setDevServerHooks({
676
- // Give the request handler access to the critical CSS in dev to avoid a
677
- // flash of unstyled content since Vite injects CSS file contents via JS
678
- getCriticalCss: async (build, url) => {
679
- return styles.getStylesForUrl({
680
- rootDirectory: ctx.rootDirectory,
681
- entryClientFilePath: ctx.entryClientFilePath,
682
- reactRouterConfig: ctx.reactRouterConfig,
683
- viteDevServer,
684
- cssModulesManifest,
685
- build,
686
- url
687
- });
688
- },
689
- // If an error is caught within the request handler, let Vite fix the
690
- // stack trace so it maps back to the actual source code
691
- processRequestError: error => {
692
- if (error instanceof Error) {
693
- viteDevServer.ssrFixStacktrace(error);
694
- }
695
- }
696
- });
697
- // Invalidate virtual modules and update cached plugin config via file watcher
698
- viteDevServer.watcher.on("all", async (eventName, rawFilepath) => {
699
- var _viteConfig, _routesViteNodeContex, _routesViteNodeContex2;
700
- let {
701
- normalizePath
702
- } = importViteEsmSync.importViteEsmSync();
703
- let filepath = normalizePath(rawFilepath);
704
- let appFileAddedOrRemoved = (eventName === "add" || eventName === "unlink") && filepath.startsWith(normalizePath(ctx.reactRouterConfig.appDirectory));
705
- invariant((_viteConfig = viteConfig) === null || _viteConfig === void 0 ? void 0 : _viteConfig.configFile);
706
- let viteConfigChanged = eventName === "change" && filepath === normalizePath(viteConfig.configFile);
707
- let routeConfigChanged = Boolean((_routesViteNodeContex = routesViteNodeContext) === null || _routesViteNodeContex === void 0 ? void 0 : (_routesViteNodeContex2 = _routesViteNodeContex.devServer) === null || _routesViteNodeContex2 === void 0 ? void 0 : _routesViteNodeContex2.moduleGraph.getModuleById(filepath));
708
- if (routeConfigChanged || appFileAddedOrRemoved) {
709
- var _routesViteNodeContex3, _routesViteNodeContex4, _routesViteNodeContex5, _routesViteNodeContex6;
710
- (_routesViteNodeContex3 = routesViteNodeContext) === null || _routesViteNodeContex3 === void 0 ? void 0 : (_routesViteNodeContex4 = _routesViteNodeContex3.devServer) === null || _routesViteNodeContex4 === void 0 ? void 0 : _routesViteNodeContex4.moduleGraph.invalidateAll();
711
- (_routesViteNodeContex5 = routesViteNodeContext) === null || _routesViteNodeContex5 === void 0 ? void 0 : (_routesViteNodeContex6 = _routesViteNodeContex5.runner) === null || _routesViteNodeContex6 === void 0 ? void 0 : _routesViteNodeContex6.moduleCache.clear();
712
- }
713
- if (appFileAddedOrRemoved || viteConfigChanged || routeConfigChanged) {
714
- let lastReactRouterConfig = ctx.reactRouterConfig;
715
- await updatePluginContext({
716
- routeConfigChanged
717
- });
718
- if (!isEqualJson(lastReactRouterConfig, ctx.reactRouterConfig)) {
719
- invalidateVirtualModules(viteDevServer);
720
- }
721
- }
722
- });
723
- return () => {
724
- // Let user servers handle SSR requests in middleware mode,
725
- // otherwise the Vite plugin will handle the request
726
- if (!viteDevServer.config.server.middlewareMode) {
727
- viteDevServer.middlewares.use(async (req, res, next) => {
728
- try {
729
- let build = await viteDevServer.ssrLoadModule(serverBuildId);
730
- let handler = reactRouter.createRequestHandler(build, "development");
731
- let nodeHandler = async (nodeReq, nodeRes) => {
732
- let req = nodeAdapter.fromNodeRequest(nodeReq, nodeRes);
733
- let res = await handler(req, await reactRouterDevLoadContext(req));
734
- await nodeAdapter.toNodeRequest(res, nodeRes);
735
- };
736
- await nodeHandler(req, res);
737
- } catch (error) {
738
- next(error);
739
- }
740
- });
741
- }
742
- };
743
- },
744
- writeBundle: {
745
- // After the SSR build is finished, we inspect the Vite manifest for
746
- // the SSR build and move server-only assets to client assets directory
747
- async handler() {
748
- if (!ctx.isSsrBuild) {
749
- return;
750
- }
751
- invariant(viteConfig);
752
- let clientBuildDirectory = getClientBuildDirectory(ctx.reactRouterConfig);
753
- let serverBuildDirectory = getServerBuildDirectory(ctx);
754
- let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
755
- let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
756
- // We only move assets that aren't in the client build, otherwise we
757
- // remove them. These assets only exist because we explicitly set
758
- // `ssrEmitAssets: true` in the SSR Vite config. These assets
759
- // typically wouldn't exist by default, which is why we assume it's
760
- // safe to remove them. We're aiming for a clean build output so that
761
- // unnecessary assets don't get deployed alongside the server code.
762
- let movedAssetPaths = [];
763
- for (let ssrAssetPath of ssrAssetPaths) {
764
- let src = path__namespace.join(serverBuildDirectory, ssrAssetPath);
765
- let dest = path__namespace.join(clientBuildDirectory, ssrAssetPath);
766
- if (!fse__namespace.existsSync(dest)) {
767
- await fse__namespace.move(src, dest);
768
- movedAssetPaths.push(dest);
769
- } else {
770
- await fse__namespace.remove(src);
771
- }
772
- }
773
- // We assume CSS assets from the SSR build are unnecessary and remove
774
- // them for the same reasons as above.
775
- let ssrCssPaths = Object.values(ssrViteManifest).flatMap(chunk => chunk.css ?? []);
776
- await Promise.all(ssrCssPaths.map(cssPath => fse__namespace.remove(path__namespace.join(serverBuildDirectory, cssPath))));
777
- if (movedAssetPaths.length) {
778
- viteConfig.logger.info(["", `${colors__default["default"].green("✓")} ${movedAssetPaths.length} asset${movedAssetPaths.length > 1 ? "s" : ""} moved from React Router server build to client assets.`, ...movedAssetPaths.map(movedAssetPath => colors__default["default"].dim(path__namespace.relative(ctx.rootDirectory, movedAssetPath))), ""].join("\n"));
779
- }
780
- if (ctx.reactRouterConfig.prerender != null && ctx.reactRouterConfig.prerender !== false) {
781
- // If we have prerender routes, that takes precedence over SPA mode
782
- // which is ssr:false and only the rot route being rendered
783
- await handlePrerender(viteConfig, ctx.reactRouterConfig, serverBuildDirectory, clientBuildDirectory);
784
- } else if (!ctx.reactRouterConfig.ssr) {
785
- await handleSpaMode(viteConfig, ctx.reactRouterConfig, serverBuildDirectory, clientBuildDirectory);
786
- }
787
- // For both SPA mode and prerendering, we can remove the server builds
788
- // if ssr:false is set
789
- if (!ctx.reactRouterConfig.ssr) {
790
- // Cleanup - we no longer need the server build assets
791
- viteConfig.logger.info(["Removing the server build in", colors__default["default"].green(serverBuildDirectory), "due to ssr:false"].join(" "));
792
- fse__namespace.removeSync(serverBuildDirectory);
793
- }
794
- }
795
- },
796
- async buildEnd() {
797
- var _viteChildCompiler, _routesViteNodeContex7, _routesViteNodeContex8;
798
- await ((_viteChildCompiler = viteChildCompiler) === null || _viteChildCompiler === void 0 ? void 0 : _viteChildCompiler.close());
799
- await ((_routesViteNodeContex7 = routesViteNodeContext) === null || _routesViteNodeContex7 === void 0 ? void 0 : (_routesViteNodeContex8 = _routesViteNodeContex7.devServer) === null || _routesViteNodeContex8 === void 0 ? void 0 : _routesViteNodeContex8.close());
800
- }
801
- }, {
802
- name: "react-router-route-entry",
803
- enforce: "pre",
804
- async transform(_code, id, options) {
805
- if (!isRouteEntry(id)) return;
806
- let routeModuleId = id.replace(ROUTE_ENTRY_QUERY_STRING, "");
807
- let routeFileName = path__namespace.basename(routeModuleId);
808
- let sourceExports = await getRouteModuleExports(viteChildCompiler, ctx, routeModuleId);
809
- let reexports = sourceExports.filter(exportName => (options === null || options === void 0 ? void 0 : options.ssr) && SERVER_ONLY_ROUTE_EXPORTS.includes(exportName) || CLIENT_ROUTE_EXPORTS.includes(exportName)).join(", ");
810
- return `export { ${reexports} } from "./${routeFileName}";`;
811
- }
812
- }, {
813
- name: "react-router-virtual-modules",
814
- enforce: "pre",
815
- resolveId(id) {
816
- if (vmods.includes(id)) return vmod.resolve(id);
817
- },
818
- async load(id) {
819
- switch (id) {
820
- case vmod.resolve(serverBuildId):
821
- {
822
- return await getServerEntry();
823
- }
824
- case vmod.resolve(serverManifestId):
825
- {
826
- let reactRouterManifest = ctx.isSsrBuild ? await ctx.getReactRouterServerManifest() : await getReactRouterManifestForDev();
827
- return `export default ${jsesc__default["default"](reactRouterManifest, {
828
- es6: true
829
- })};`;
830
- }
831
- case vmod.resolve(browserManifestId):
832
- {
833
- if (viteCommand === "build") {
834
- throw new Error("This module only exists in development");
835
- }
836
- let reactRouterManifest = await getReactRouterManifestForDev();
837
- let reactRouterManifestString = jsesc__default["default"](reactRouterManifest, {
838
- es6: true
839
- });
840
- return `window.__reactRouterManifest=${reactRouterManifestString};`;
841
- }
842
- }
843
- }
844
- }, {
845
- name: "react-router-dot-server",
846
- enforce: "pre",
847
- async resolveId(id, importer, options) {
848
- var _options$custom;
849
- // https://vitejs.dev/config/dep-optimization-options
850
- let isOptimizeDeps = viteCommand === "serve" && (options === null || options === void 0 ? void 0 : options.scan) === true;
851
- if (isOptimizeDeps || options !== null && options !== void 0 && options.ssr) return;
852
- let isResolving = (options === null || options === void 0 ? void 0 : (_options$custom = options.custom) === null || _options$custom === void 0 ? void 0 : _options$custom["react-router-dot-server"]) ?? false;
853
- if (isResolving) return;
854
- options.custom = {
855
- ...options.custom,
856
- "react-router-dot-server": true
857
- };
858
- let resolved = await this.resolve(id, importer, options);
859
- if (!resolved) return;
860
- let serverFileRE = /\.server(\.[cm]?[jt]sx?)?$/;
861
- let serverDirRE = /\/\.server\//;
862
- let isDotServer = serverFileRE.test(resolved.id) || serverDirRE.test(resolved.id);
863
- if (!isDotServer) return;
864
- if (!importer) return;
865
- if (viteCommand !== "build" && importer.endsWith(".html")) {
866
- // Vite has a special `index.html` importer for `resolveId` within `transformRequest`
867
- // https://github.com/vitejs/vite/blob/5684fcd8d27110d098b3e1c19d851f44251588f1/packages/vite/src/node/server/transformRequest.ts#L158
868
- // https://github.com/vitejs/vite/blob/5684fcd8d27110d098b3e1c19d851f44251588f1/packages/vite/src/node/server/pluginContainer.ts#L668
869
- return;
870
- }
871
- let vite = importViteEsmSync.importViteEsmSync();
872
- let importerShort = vite.normalizePath(path__namespace.relative(ctx.rootDirectory, importer));
873
- let isRoute = getRoute(ctx.reactRouterConfig, importer);
874
- if (isRoute) {
875
- let serverOnlyExports = SERVER_ONLY_ROUTE_EXPORTS.map(xport => `\`${xport}\``).join(", ");
876
- throw Error([colors__default["default"].red(`Server-only module referenced by client`), "", ` '${id}' imported by route '${importerShort}'`, "", ` React Router automatically removes server-code from these exports:`, ` ${serverOnlyExports}`, "", ` But other route exports in '${importerShort}' depend on '${id}'.`, "", " See https://remix.run/docs/en/main/guides/vite#splitting-up-client-and-server-code", ""].join("\n"));
877
- }
878
- throw Error([colors__default["default"].red(`Server-only module referenced by client`), "", ` '${id}' imported by '${importerShort}'`, "", " See https://remix.run/docs/en/main/guides/vite#splitting-up-client-and-server-code", ""].join("\n"));
879
- }
880
- }, {
881
- name: "react-router-dot-client",
882
- async transform(code, id, options) {
883
- if (!(options !== null && options !== void 0 && options.ssr)) return;
884
- let clientFileRE = /\.client(\.[cm]?[jt]sx?)?$/;
885
- let clientDirRE = /\/\.client\//;
886
- if (clientFileRE.test(id) || clientDirRE.test(id)) {
887
- let exports = esModuleLexer.parse(code)[1];
888
- return {
889
- code: exports.map(({
890
- n: name
891
- }) => name === "default" ? "export default undefined;" : `export const ${name} = undefined;`).join("\n"),
892
- map: null
893
- };
894
- }
895
- }
896
- }, withProps.plugin, {
897
- name: "react-router-route-exports",
898
- async transform(code, id, options) {
899
- let route = getRoute(ctx.reactRouterConfig, id);
900
- if (!route) return;
901
- if (!(options !== null && options !== void 0 && options.ssr) && !ctx.reactRouterConfig.ssr) {
902
- let serverOnlyExports = esModuleLexer.parse(code)[1].map(exp => exp.n).filter(exp => SERVER_ONLY_ROUTE_EXPORTS.includes(exp));
903
- if (serverOnlyExports.length > 0) {
904
- let str = serverOnlyExports.map(e => `\`${e}\``).join(", ");
905
- let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in ` + `\`${route.file}\`: ${str}. See https://remix.run/guides/spa-mode ` + `for more information.`;
906
- throw Error(message);
907
- }
908
- if (route.id !== "root") {
909
- let hasHydrateFallback = esModuleLexer.parse(code)[1].map(exp => exp.n).some(exp => exp === "HydrateFallback");
910
- if (hasHydrateFallback) {
911
- let message = `SPA Mode: Invalid \`HydrateFallback\` export found in ` + `\`${route.file}\`. \`HydrateFallback\` is only permitted on ` + `the root route in SPA Mode. See https://remix.run/guides/spa-mode ` + `for more information.`;
912
- throw Error(message);
913
- }
914
- }
915
- }
916
- let [filepath] = id.split("?");
917
- let ast = parser.parse(code, {
918
- sourceType: "module"
919
- });
920
- if (!(options !== null && options !== void 0 && options.ssr)) {
921
- removeExports.removeExports(ast, SERVER_ONLY_ROUTE_EXPORTS);
922
- }
923
- withProps.transform(ast);
924
- return babel.generate(ast, {
925
- sourceMaps: true,
926
- filename: id,
927
- sourceFileName: filepath
928
- });
929
- }
930
- }, {
931
- name: "react-router-inject-hmr-runtime",
932
- enforce: "pre",
933
- resolveId(id) {
934
- if (id === injectHmrRuntimeId) return vmod.resolve(injectHmrRuntimeId);
935
- },
936
- async load(id) {
937
- if (id !== vmod.resolve(injectHmrRuntimeId)) return;
938
- return [`import RefreshRuntime from "${hmrRuntimeId}"`, "RefreshRuntime.injectIntoGlobalHook(window)", "window.$RefreshReg$ = () => {}", "window.$RefreshSig$ = () => (type) => type", "window.__vite_plugin_react_preamble_installed__ = true"].join("\n");
939
- }
940
- }, {
941
- name: "react-router-hmr-runtime",
942
- enforce: "pre",
943
- resolveId(id) {
944
- if (id === hmrRuntimeId) return vmod.resolve(hmrRuntimeId);
945
- },
946
- async load(id) {
947
- if (id !== vmod.resolve(hmrRuntimeId)) return;
948
- let reactRefreshDir = path__namespace.dirname(require.resolve("react-refresh/package.json"));
949
- let reactRefreshRuntimePath = path__namespace.join(reactRefreshDir, "cjs/react-refresh-runtime.development.js");
950
- return ["const exports = {}", await fse__namespace.readFile(reactRefreshRuntimePath, "utf8"), await fse__namespace.readFile(require.resolve("./static/refresh-utils.cjs"), "utf8"), "export default exports"].join("\n");
951
- }
952
- }, {
953
- name: "react-router-react-refresh-babel",
954
- async transform(code, id, options) {
955
- if (viteCommand !== "serve") return;
956
- if (id.includes("/node_modules/")) return;
957
- let [filepath] = id.split("?");
958
- let extensionsRE = /\.(jsx?|tsx?|mdx?)$/;
959
- if (!extensionsRE.test(filepath)) return;
960
- let devRuntime = "react/jsx-dev-runtime";
961
- let ssr = (options === null || options === void 0 ? void 0 : options.ssr) === true;
962
- let isJSX = filepath.endsWith("x");
963
- let useFastRefresh = !ssr && (isJSX || code.includes(devRuntime));
964
- if (!useFastRefresh) return;
965
- if (isRouteEntry(id)) {
966
- return {
967
- code: addRefreshWrapper(ctx.reactRouterConfig, code, id)
968
- };
969
- }
970
- let result = await babel__default["default"].transformAsync(code, {
971
- babelrc: false,
972
- configFile: false,
973
- filename: id,
974
- sourceFileName: filepath,
975
- parserOpts: {
976
- sourceType: "module",
977
- allowAwaitOutsideFunction: true
978
- },
979
- plugins: [[require("react-refresh/babel"), {
980
- skipEnvCheck: true
981
- }]],
982
- sourceMaps: true
983
- });
984
- if (result === null) return;
985
- code = result.code;
986
- let refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
987
- if (refreshContentRE.test(code)) {
988
- code = addRefreshWrapper(ctx.reactRouterConfig, code, id);
989
- }
990
- return {
991
- code,
992
- map: result.map
993
- };
994
- }
995
- }, {
996
- name: "react-router-hmr-updates",
997
- async handleHotUpdate({
998
- server,
999
- file,
1000
- modules,
1001
- read
1002
- }) {
1003
- let route = getRoute(ctx.reactRouterConfig, file);
1004
- let hmrEventData = {
1005
- route: null
1006
- };
1007
- if (route) {
1008
- // invalidate manifest on route exports change
1009
- let serverManifest = (await server.ssrLoadModule(serverManifestId)).default;
1010
- let oldRouteMetadata = serverManifest.routes[route.id];
1011
- let newRouteMetadata = await getRouteMetadata(ctx, viteChildCompiler, route, read);
1012
- hmrEventData.route = newRouteMetadata;
1013
- if (!oldRouteMetadata || ["hasLoader", "hasClientLoader", "hasAction", "hasClientAction", "hasErrorBoundary"].some(key => oldRouteMetadata[key] !== newRouteMetadata[key])) {
1014
- invalidateVirtualModules(server);
1015
- }
1016
- }
1017
- server.hot.send({
1018
- type: "custom",
1019
- event: "react-router:hmr",
1020
- data: hmrEventData
1021
- });
1022
- return modules;
1023
- }
1024
- }];
1025
- };
1026
- function findConfig(dir, basename, extensions) {
1027
- for (let ext of extensions) {
1028
- let name = basename + ext;
1029
- let file = path__namespace.join(dir, name);
1030
- if (fse__namespace.existsSync(file)) return file;
1031
- }
1032
- return undefined;
1033
- }
1034
- function isInReactRouterMonorepo() {
1035
- // We use '@react-router/node' for this check since it's a
1036
- // dependency of this package and guaranteed to be in node_modules
1037
- let serverRuntimePath = path__namespace.dirname(require.resolve("@react-router/node/package.json"));
1038
- let serverRuntimeParentDir = path__namespace.basename(path__namespace.resolve(serverRuntimePath, ".."));
1039
- return serverRuntimeParentDir === "packages";
1040
- }
1041
- function isEqualJson(v1, v2) {
1042
- return JSON.stringify(v1) === JSON.stringify(v2);
1043
- }
1044
- function addRefreshWrapper(reactRouterConfig, code, id) {
1045
- let route = getRoute(reactRouterConfig, id);
1046
- let acceptExports = route || isRouteEntry(id) ? ["clientAction", "clientLoader", "handle", "meta", "links", "shouldRevalidate"] : [];
1047
- return "\n\n" + withCommentBoundaries("REACT REFRESH HEADER", REACT_REFRESH_HEADER.replaceAll("__SOURCE__", JSON.stringify(id))) + "\n\n" + withCommentBoundaries("REACT REFRESH BODY", code) + "\n\n" + withCommentBoundaries("REACT REFRESH FOOTER", REACT_REFRESH_FOOTER.replaceAll("__SOURCE__", JSON.stringify(id)).replaceAll("__ACCEPT_EXPORTS__", JSON.stringify(acceptExports)).replaceAll("__ROUTE_ID__", JSON.stringify(route === null || route === void 0 ? void 0 : route.id))) + "\n";
1048
- }
1049
- function withCommentBoundaries(label, text) {
1050
- let begin = `// [BEGIN] ${label} `;
1051
- begin += "-".repeat(80 - begin.length);
1052
- let end = `// [END] ${label} `;
1053
- end += "-".repeat(80 - end.length);
1054
- return `${begin}\n${text}\n${end}`;
1055
- }
1056
- const REACT_REFRESH_HEADER = `
1057
- import RefreshRuntime from "${hmrRuntimeId}";
1058
-
1059
- const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
1060
- let prevRefreshReg;
1061
- let prevRefreshSig;
1062
-
1063
- if (import.meta.hot && !inWebWorker) {
1064
- if (!window.__vite_plugin_react_preamble_installed__) {
1065
- throw new Error(
1066
- "React Router Vite plugin can't detect preamble. Something is wrong."
1067
- );
1068
- }
1069
-
1070
- prevRefreshReg = window.$RefreshReg$;
1071
- prevRefreshSig = window.$RefreshSig$;
1072
- window.$RefreshReg$ = (type, id) => {
1073
- RefreshRuntime.register(type, __SOURCE__ + " " + id)
1074
- };
1075
- window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
1076
- }`.trim();
1077
- const REACT_REFRESH_FOOTER = `
1078
- if (import.meta.hot && !inWebWorker) {
1079
- window.$RefreshReg$ = prevRefreshReg;
1080
- window.$RefreshSig$ = prevRefreshSig;
1081
- RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
1082
- RefreshRuntime.registerExportsForReactRefresh(__SOURCE__, currentExports);
1083
- import.meta.hot.accept((nextExports) => {
1084
- if (!nextExports) return;
1085
- __ROUTE_ID__ && window.__reactRouterRouteModuleUpdates.set(__ROUTE_ID__, nextExports);
1086
- const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(currentExports, nextExports, __ACCEPT_EXPORTS__);
1087
- if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
1088
- });
1089
- });
1090
- }`.trim();
1091
- function getRoute(pluginConfig, file) {
1092
- let vite = importViteEsmSync.importViteEsmSync();
1093
- let routePath = vite.normalizePath(path__namespace.relative(pluginConfig.appDirectory, file));
1094
- let route = Object.values(pluginConfig.routes).find(r => vite.normalizePath(r.file) === routePath);
1095
- return route;
1096
- }
1097
- async function getRouteMetadata(ctx, viteChildCompiler, route, readRouteFile) {
1098
- let sourceExports = await getRouteModuleExports(viteChildCompiler, ctx, route.file, readRouteFile);
1099
- let info = {
1100
- id: route.id,
1101
- parentId: route.parentId,
1102
- path: route.path,
1103
- index: route.index,
1104
- caseSensitive: route.caseSensitive,
1105
- url: combineUrls.combineURLs(ctx.publicPath, "/" + path__namespace.relative(ctx.rootDirectory, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig))),
1106
- module: combineUrls.combineURLs(ctx.publicPath, `${resolveFileUrl.resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig))}?import`),
1107
- // Ensure the Vite dev server responds with a JS module
1108
- hasAction: sourceExports.includes("action"),
1109
- hasClientAction: sourceExports.includes("clientAction"),
1110
- hasLoader: sourceExports.includes("loader"),
1111
- hasClientLoader: sourceExports.includes("clientLoader"),
1112
- hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
1113
- imports: []
1114
- };
1115
- return info;
1116
- }
1117
- async function getPrerenderBuildAndHandler(viteConfig, reactRouterConfig, serverBuildDirectory) {
1118
- let serverBuildPath = path__namespace.join(serverBuildDirectory, reactRouterConfig.serverBuildFile);
1119
- let build = await import(url__namespace.pathToFileURL(serverBuildPath).toString());
1120
- let {
1121
- createRequestHandler: createHandler
1122
- } = await import('react-router');
1123
- return {
1124
- build,
1125
- handler: createHandler(build, viteConfig.mode)
1126
- };
1127
- }
1128
- async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory, clientBuildDirectory) {
1129
- let {
1130
- handler
1131
- } = await getPrerenderBuildAndHandler(viteConfig, reactRouterConfig, serverBuildDirectory);
1132
- let request = new Request(`http://localhost${reactRouterConfig.basename}`);
1133
- let response = await handler(request);
1134
- let html = await response.text();
1135
- validatePrerenderedResponse(response, html, "SPA Mode", "/");
1136
- validatePrerenderedHtml(html, "SPA Mode");
1137
- // Write out the index.html file for the SPA
1138
- await fse__namespace.writeFile(path__namespace.join(clientBuildDirectory, "index.html"), html);
1139
- viteConfig.logger.info("SPA Mode: index.html has been written to your " + colors__default["default"].bold(path__namespace.relative(process.cwd(), clientBuildDirectory)) + " directory");
1140
- }
1141
- async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirectory, clientBuildDirectory) {
1142
- let {
1143
- build,
1144
- handler
1145
- } = await getPrerenderBuildAndHandler(viteConfig, reactRouterConfig, serverBuildDirectory);
1146
- let routes = createPrerenderRoutes(build.routes);
1147
- let routesToPrerender;
1148
- if (typeof reactRouterConfig.prerender === "boolean") {
1149
- invariant(reactRouterConfig.prerender, "Expected prerender:true");
1150
- routesToPrerender = determineStaticPrerenderRoutes(routes, viteConfig, true);
1151
- } else if (typeof reactRouterConfig.prerender === "function") {
1152
- routesToPrerender = await reactRouterConfig.prerender({
1153
- getStaticPaths: () => determineStaticPrerenderRoutes(routes, viteConfig, false)
1154
- });
1155
- } else {
1156
- routesToPrerender = reactRouterConfig.prerender || ["/"];
1157
- }
1158
- let headers = {
1159
- // Header that can be used in the loader to know if you're running at
1160
- // build time or runtime
1161
- "X-React-Router-Prerender": "yes"
1162
- };
1163
- for (let path of routesToPrerender) {
1164
- var _matchRoutes;
1165
- let hasLoaders = (_matchRoutes = reactRouter.matchRoutes(routes, path)) === null || _matchRoutes === void 0 ? void 0 : _matchRoutes.some(m => m.route.loader);
1166
- let data;
1167
- if (hasLoaders) {
1168
- data = await prerenderData(handler, path, clientBuildDirectory, reactRouterConfig, viteConfig, {
1169
- headers
1170
- });
1171
- }
1172
- await prerenderRoute(handler, path, clientBuildDirectory, reactRouterConfig, viteConfig, data ? {
1173
- headers: {
1174
- ...headers,
1175
- "X-React-Router-Prerender-Data": data
1176
- }
1177
- } : {
1178
- headers
1179
- });
1180
- }
1181
- await prerenderManifest(build, clientBuildDirectory, reactRouterConfig, viteConfig);
1182
- }
1183
- function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = false) {
1184
- // Always start with the root/index route included
1185
- let paths = ["/"];
1186
- let paramRoutes = [];
1187
- // Then recursively add any new path defined by the tree
1188
- function recurse(subtree, prefix = "") {
1189
- for (let route of subtree) {
1190
- let newPath = [prefix, route.path].join("/").replace(/\/\/+/g, "/");
1191
- if (route.path) {
1192
- let segments = route.path.split("/");
1193
- if (segments.some(s => s.startsWith(":") || s === "*")) {
1194
- paramRoutes.push(route.path);
1195
- } else {
1196
- paths.push(newPath);
1197
- }
1198
- }
1199
- if (route.children) {
1200
- recurse(route.children, newPath);
1201
- }
1202
- }
1203
- }
1204
- recurse(routes);
1205
- if (isBooleanUsage && paramRoutes.length > 0) {
1206
- viteConfig.logger.warn(["⚠️ 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:", ...paramRoutes.map(p => " - " + p)].join("\n"));
1207
- }
1208
- // Clean double slashes and remove trailing slashes
1209
- return paths.map(p => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1"));
1210
- }
1211
- async function prerenderData(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
1212
- let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
1213
- let request = new Request(`http://localhost${normalizedPath}`, requestInit);
1214
- let response = await handler(request);
1215
- let data = await response.text();
1216
- validatePrerenderedResponse(response, data, "Prerender", normalizedPath);
1217
- // Write out the .data file
1218
- let outdir = path__namespace.relative(process.cwd(), clientBuildDirectory);
1219
- let outfile = path__namespace.join(outdir, ...normalizedPath.split("/"));
1220
- await fse__namespace.ensureDir(path__namespace.dirname(outfile));
1221
- await fse__namespace.outputFile(outfile, data);
1222
- viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
1223
- return data;
1224
- }
1225
- async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
1226
- let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/");
1227
- let request = new Request(`http://localhost${normalizedPath}`, requestInit);
1228
- let response = await handler(request);
1229
- let html = await response.text();
1230
- validatePrerenderedResponse(response, html, "Prerender", normalizedPath);
1231
- if (!reactRouterConfig.ssr) {
1232
- validatePrerenderedHtml(html, "Prerender");
1233
- }
1234
- // Write out the HTML file
1235
- let outdir = path__namespace.relative(process.cwd(), clientBuildDirectory);
1236
- let outfile = path__namespace.join(outdir, ...normalizedPath.split("/"), "index.html");
1237
- await fse__namespace.ensureDir(path__namespace.dirname(outfile));
1238
- await fse__namespace.outputFile(outfile, html);
1239
- viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
1240
- }
1241
- async function prerenderManifest(build, clientBuildDirectory, reactRouterConfig, viteConfig) {
1242
- let normalizedPath = `${reactRouterConfig.basename}/__manifest`.replace(/\/\/+/g, "/");
1243
- let outdir = path__namespace.relative(process.cwd(), clientBuildDirectory);
1244
- let outfile = path__namespace.join(outdir, ...normalizedPath.split("/"));
1245
- await fse__namespace.ensureDir(path__namespace.dirname(outfile));
1246
- let manifestData = JSON.stringify(build.assets.routes);
1247
- await fse__namespace.outputFile(outfile, manifestData);
1248
- viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
1249
- }
1250
- function validatePrerenderedResponse(response, html, prefix, path) {
1251
- if (response.status !== 200) {
1252
- throw new Error(`${prefix}: Received a ${response.status} status code from ` + `\`entry.server.tsx\` while prerendering the \`${path}\` ` + `path.\n${html}`);
1253
- }
1254
- }
1255
- function validatePrerenderedHtml(html, prefix) {
1256
- if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
1257
- throw new Error(`${prefix}: Did you forget to include <Scripts/> in your root route? ` + "Your pre-rendered HTML files cannot hydrate without `<Scripts />`.");
1258
- }
1259
- }
1260
- // Note: Duplicated from react-router/lib/server-runtime
1261
- function groupRoutesByParentId(manifest) {
1262
- let routes = {};
1263
- Object.values(manifest).forEach(route => {
1264
- if (route) {
1265
- let parentId = route.parentId || "";
1266
- if (!routes[parentId]) {
1267
- routes[parentId] = [];
1268
- }
1269
- routes[parentId].push(route);
1270
- }
1271
- });
1272
- return routes;
1273
- }
1274
- // Note: Duplicated from react-router/lib/server-runtime
1275
- function createPrerenderRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId(manifest)) {
1276
- return (routesByParentId[parentId] || []).map(route => {
1277
- let commonRoute = {
1278
- // Always include root due to default boundaries
1279
- hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
1280
- id: route.id,
1281
- path: route.path,
1282
- loader: route.module.loader ? () => null : undefined,
1283
- action: undefined,
1284
- handle: route.module.handle
1285
- };
1286
- return route.index ? {
1287
- index: true,
1288
- ...commonRoute
1289
- } : {
1290
- caseSensitive: route.caseSensitive,
1291
- children: createPrerenderRoutes(manifest, route.id, routesByParentId),
1292
- ...commonRoute
1293
- };
1294
- });
1295
- }
1296
-
1297
- exports.extractPluginContext = extractPluginContext;
1298
- exports.getServerBuildDirectory = getServerBuildDirectory;
1299
- exports.loadPluginContext = loadPluginContext;
1300
- exports.reactRouterVitePlugin = reactRouterVitePlugin;
1301
- exports.resolveViteConfig = resolveViteConfig;