@react-router/dev 0.0.0-experimental-4996fbe2b → 0.0.0-experimental-ecd35cd60

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/bin.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("./dist/cli");
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/cli/run.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/cli.js CHANGED
@@ -1,6 +1,5 @@
1
- #!/usr/bin/env node
2
1
  /**
3
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
4
3
  *
5
4
  * Copyright (c) Remix Software Inc.
6
5
  *
package/dist/colors.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -3,7 +3,8 @@ import { PassThrough } from "node:stream";
3
3
  import type { AppLoadContext, EntryContext } from "react-router";
4
4
  import { createReadableStreamFromReadable } from "@react-router/node";
5
5
  import { ServerRouter } from "react-router";
6
- import * as isbotModule from "isbot";
6
+ import { isbot } from "isbot";
7
+ import type { RenderToPipeableStreamOptions } from "react-dom/server";
7
8
  import { renderToPipeableStream } from "react-dom/server";
8
9
 
9
10
  const ABORT_DELAY = 5_000;
@@ -12,114 +13,28 @@ export default function handleRequest(
12
13
  request: Request,
13
14
  responseStatusCode: number,
14
15
  responseHeaders: Headers,
15
- remixContext: EntryContext,
16
+ routerContext: EntryContext,
16
17
  loadContext: AppLoadContext
17
- ) {
18
- let prohibitOutOfOrderStreaming =
19
- isBotRequest(request.headers.get("user-agent")) || remixContext.isSpaMode;
20
-
21
- return prohibitOutOfOrderStreaming
22
- ? handleBotRequest(
23
- request,
24
- responseStatusCode,
25
- responseHeaders,
26
- remixContext
27
- )
28
- : handleBrowserRequest(
29
- request,
30
- responseStatusCode,
31
- responseHeaders,
32
- remixContext
33
- );
34
- }
35
-
36
- // We have some Remix apps in the wild already running with isbot@3 so we need
37
- // to maintain backwards compatibility even though we want new apps to use
38
- // isbot@4. That way, we can ship this as a minor Semver update to @react-router/dev.
39
- function isBotRequest(userAgent: string | null) {
40
- if (!userAgent) {
41
- return false;
42
- }
43
-
44
- // isbot >= 3.8.0, >4
45
- if ("isbot" in isbotModule && typeof isbotModule.isbot === "function") {
46
- return isbotModule.isbot(userAgent);
47
- }
48
-
49
- // isbot < 3.8.0
50
- if ("default" in isbotModule && typeof isbotModule.default === "function") {
51
- return isbotModule.default(userAgent);
52
- }
53
-
54
- return false;
55
- }
56
-
57
- function handleBotRequest(
58
- request: Request,
59
- responseStatusCode: number,
60
- responseHeaders: Headers,
61
- remixContext: EntryContext
62
18
  ) {
63
19
  return new Promise((resolve, reject) => {
64
20
  let shellRendered = false;
65
- const { pipe, abort } = renderToPipeableStream(
66
- <ServerRouter
67
- context={remixContext}
68
- url={request.url}
69
- abortDelay={ABORT_DELAY}
70
- />,
71
- {
72
- onAllReady() {
73
- shellRendered = true;
74
- const body = new PassThrough();
75
- const stream = createReadableStreamFromReadable(body);
76
-
77
- responseHeaders.set("Content-Type", "text/html");
78
-
79
- resolve(
80
- new Response(stream, {
81
- headers: responseHeaders,
82
- status: responseStatusCode,
83
- })
84
- );
85
-
86
- pipe(body);
87
- },
88
- onShellError(error: unknown) {
89
- reject(error);
90
- },
91
- onError(error: unknown) {
92
- responseStatusCode = 500;
93
- // Log streaming rendering errors from inside the shell. Don't log
94
- // errors encountered during initial shell rendering since they'll
95
- // reject and get logged in handleDocumentRequest.
96
- if (shellRendered) {
97
- console.error(error);
98
- }
99
- },
100
- }
101
- );
21
+ let userAgent = request.headers.get("user-agent");
102
22
 
103
- setTimeout(abort, ABORT_DELAY);
104
- });
105
- }
23
+ // Ensure requests from bots and SPA Mode renders wait for all content to load before responding
24
+ // https://react.dev/reference/react-dom/server/renderToPipeableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation
25
+ let readyOption: keyof RenderToPipeableStreamOptions =
26
+ (userAgent && isbot(userAgent)) || routerContext.isSpaMode
27
+ ? "onAllReady"
28
+ : "onShellReady";
106
29
 
107
- function handleBrowserRequest(
108
- request: Request,
109
- responseStatusCode: number,
110
- responseHeaders: Headers,
111
- remixContext: EntryContext
112
- ) {
113
- return new Promise((resolve, reject) => {
114
- let shellRendered = false;
115
30
  const { pipe, abort } = renderToPipeableStream(
116
31
  <ServerRouter
117
- context={remixContext}
32
+ context={routerContext}
118
33
  url={request.url}
119
34
  abortDelay={ABORT_DELAY}
120
35
  />,
121
36
  {
122
- onShellReady() {
37
+ [readyOption]() {
123
38
  shellRendered = true;
124
39
  const body = new PassThrough();
125
40
  const stream = createReadableStreamFromReadable(body);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/invariant.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,2 +1,5 @@
1
- export declare function transform(code: string): void;
1
+ export declare function transform(code: string, id: string, options?: {
2
+ ssr?: boolean;
3
+ }): string | import("@babel/generator").GeneratorResult;
4
+ export declare function parseFields(code: string): string[];
2
5
  export declare function assertNotImported(code: string): void;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -13,6 +13,7 @@
13
13
  Object.defineProperty(exports, '__esModule', { value: true });
14
14
 
15
15
  var babel$1 = require('@babel/core');
16
+ var babelDeadCodeElimination = require('babel-dead-code-elimination');
16
17
  var babel = require('./babel.js');
17
18
  var t = require('@babel/types');
18
19
  var parser = require('@babel/parser');
@@ -38,23 +39,41 @@ function _interopNamespace(e) {
38
39
  var babel__namespace = /*#__PURE__*/_interopNamespace(babel$1);
39
40
  var t__namespace = /*#__PURE__*/_interopNamespace(t);
40
41
 
41
- function transform(code) {
42
+ function transform(code, id, options = {}) {
43
+ if (options !== null && options !== void 0 && options.ssr) return code;
42
44
  let ast = parse(code);
45
+ let refs = babelDeadCodeElimination.findReferencedIdentifiers(ast);
46
+ let markedForRemoval = [];
47
+ assertDefineRouteOnlyAfterExportDefault(ast);
43
48
  babel.traverse(ast, {
44
- Identifier(path) {
45
- if (!isDefineRoute(path)) return;
46
- if (t__namespace.isImportSpecifier(path.parent)) return;
47
- if (!t__namespace.isCallExpression(path.parent)) {
48
- throw path.buildCodeFrameError("`defineRoute` must be a function call immediately after `export default`");
49
- }
50
- if (!t__namespace.isExportDefaultDeclaration(path.parentPath.parent)) {
51
- throw path.buildCodeFrameError("`defineRoute` must be a function call immediately after `export default`");
49
+ ExportDefaultDeclaration(path) {
50
+ let analysis = analyzeRouteExport(path);
51
+ for (let [key, fieldPath] of Object.entries(analysis)) {
52
+ if (["headers", "serverLoader", "serverAction"].includes(key)) {
53
+ if (!fieldPath) continue;
54
+ markedForRemoval.push(fieldPath);
55
+ }
52
56
  }
53
- },
57
+ }
58
+ });
59
+ markedForRemoval.forEach(path => path.remove());
60
+ babelDeadCodeElimination.deadCodeElimination(ast, refs);
61
+ return babel.generate(ast, {
62
+ sourceMaps: true,
63
+ sourceFileName: id
64
+ }, code);
65
+ }
66
+ function parseFields(code) {
67
+ let fields = [];
68
+ let ast = parse(code);
69
+ assertDefineRouteOnlyAfterExportDefault(ast);
70
+ babel.traverse(ast, {
54
71
  ExportDefaultDeclaration(path) {
55
- analyzeRouteExport(path);
72
+ let analysis = analyzeRouteExport(path);
73
+ fields = Object.keys(analysis);
56
74
  }
57
75
  });
76
+ return fields;
58
77
  }
59
78
  function analyzeRouteExport(path) {
60
79
  let route = path.node.declaration;
@@ -82,6 +101,7 @@ function analyzeRouteExport(path) {
82
101
  throw path.get("declaration").buildCodeFrameError("Default export of a route module must be either a literal object or a call to `defineRoute`");
83
102
  }
84
103
  function analyzeRoute(path) {
104
+ let analysis = {};
85
105
  for (let [i, property] of path.node.properties.entries()) {
86
106
  // spread: defineRoute({ ...dynamic })
87
107
  if (!t__namespace.isObjectProperty(property) && !t__namespace.isObjectMethod(property)) {
@@ -109,10 +129,10 @@ function analyzeRoute(path) {
109
129
  throw elementPath.buildCodeFrameError("Route param must be a literal string");
110
130
  }
111
131
  }
112
- continue;
113
132
  }
133
+ analysis[key] = propertyPath;
114
134
  }
115
- throw path.buildCodeFrameError("TODO: not yet implemented");
135
+ return analysis;
116
136
  }
117
137
  function assertNotImported(code) {
118
138
  let ast = parse(code);
@@ -142,6 +162,20 @@ function parse(source) {
142
162
  });
143
163
  return ast;
144
164
  }
165
+ function assertDefineRouteOnlyAfterExportDefault(ast) {
166
+ babel.traverse(ast, {
167
+ Identifier(path) {
168
+ if (!isDefineRoute(path)) return;
169
+ if (t__namespace.isImportSpecifier(path.parent)) return;
170
+ if (!t__namespace.isCallExpression(path.parent)) {
171
+ throw path.buildCodeFrameError("`defineRoute` must be a function call immediately after `export default`");
172
+ }
173
+ if (!t__namespace.isExportDefaultDeclaration(path.parentPath.parent)) {
174
+ throw path.buildCodeFrameError("`defineRoute` must be a function call immediately after `export default`");
175
+ }
176
+ }
177
+ });
178
+ }
145
179
  function isDefineRoute(path) {
146
180
  if (!t__namespace.isIdentifier(path.node)) return false;
147
181
  let binding = path.scope.getBinding(path.node.name);
@@ -169,4 +203,5 @@ function isCanonicallyImportedAs(binding, {
169
203
  }
170
204
 
171
205
  exports.assertNotImported = assertNotImported;
206
+ exports.parseFields = parseFields;
172
207
  exports.transform = transform;
package/dist/vite/dev.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -108,11 +108,11 @@ async function loadPluginContext({
108
108
  }
109
109
  const SERVER_ONLY_ROUTE_EXPORTS = ["loader", "action", "headers"];
110
110
  const CLIENT_ROUTE_EXPORTS = ["clientAction", "clientLoader", "default", "ErrorBoundary", "handle", "HydrateFallback", "Layout", "links", "meta", "shouldRevalidate"];
111
- /** This is used to manage a build optimization to remove unused route exports
112
- from the client build output. This is important in cases where custom route
113
- exports are only ever used on the server. Without this optimization we can't
114
- tree-shake any unused custom exports because routes are entry points. */
115
- const BUILD_CLIENT_ROUTE_QUERY_STRING = "?__remix-build-client-route";
111
+ // Each route gets its own virtual module marked with an entry query string
112
+ const ROUTE_ENTRY_QUERY_STRING = "?route-entry=1";
113
+ const isRouteEntry = id => {
114
+ return id.endsWith(ROUTE_ENTRY_QUERY_STRING);
115
+ };
116
116
  let serverBuildId = vmod.id("server-build");
117
117
  let serverManifestId = vmod.id("server-manifest");
118
118
  let browserManifestId = vmod.id("browser-manifest");
@@ -140,7 +140,7 @@ const getHash = (source, maxLength) => {
140
140
  const resolveChunk = (ctx, viteManifest, absoluteFilePath) => {
141
141
  let vite = importViteEsmSync.importViteEsmSync();
142
142
  let rootRelativeFilePath = vite.normalizePath(path__namespace.relative(ctx.rootDirectory, absoluteFilePath));
143
- let entryChunk = viteManifest[rootRelativeFilePath + BUILD_CLIENT_ROUTE_QUERY_STRING] ?? viteManifest[rootRelativeFilePath];
143
+ let entryChunk = viteManifest[rootRelativeFilePath + ROUTE_ENTRY_QUERY_STRING] ?? viteManifest[rootRelativeFilePath];
144
144
  if (!entryChunk) {
145
145
  let knownManifestKeys = Object.keys(viteManifest).map(key => '"' + key + '"').join(", ");
146
146
  throw new Error(`No manifest entry found for "${rootRelativeFilePath}". Known manifest keys: ${knownManifestKeys}`);
@@ -195,6 +195,20 @@ const getRouteManifestModuleExports = async (viteChildCompiler, ctx) => {
195
195
  return Object.fromEntries(entries);
196
196
  };
197
197
  const getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
198
+ let routePath = path__namespace.resolve(ctx.reactRouterConfig.appDirectory, routeFile);
199
+ let code = await ((readRouteFile === null || readRouteFile === void 0 ? void 0 : readRouteFile()) ?? fse__namespace.readFile(routePath, "utf-8"));
200
+ if (!code.includes("defineRoute")) {
201
+ return _getRouteModuleExports(viteChildCompiler, ctx, routeFile, readRouteFile);
202
+ }
203
+ let renameFields = ["Component", "serverLoader", "actionLoader"];
204
+ let fields = defineRoute.parseFields(code);
205
+ let exports = fields.filter(exportName => !renameFields.includes(exportName));
206
+ if (fields.includes("Component")) exports.push("default");
207
+ if (fields.includes("serverLoader")) exports.push("loader");
208
+ if (fields.includes("serverAction")) exports.push("action");
209
+ return exports;
210
+ };
211
+ const _getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
198
212
  if (!viteChildCompiler) {
199
213
  throw new Error("Vite child compiler not found");
200
214
  }
@@ -320,7 +334,7 @@ const reactRouterVitePlugin = _config => {
320
334
  import * as entryServer from ${JSON.stringify(resolveFileUrl.resolveFileUrl(ctx, ctx.entryServerFilePath))};
321
335
  ${Object.keys(routes).map((key, index) => {
322
336
  let route = routes[key];
323
- return `import * as route${index} from ${JSON.stringify(resolveFileUrl.resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)))};`;
337
+ return `import * as route${index} from ${JSON.stringify(resolveFileUrl.resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)) + ROUTE_ENTRY_QUERY_STRING)};`;
324
338
  }).join("\n")}
325
339
  export { default as assets } from ${JSON.stringify(serverManifestId)};
326
340
  export const assetsBuildDirectory = ${JSON.stringify(path__namespace.relative(ctx.rootDirectory, getClientBuildDirectory(ctx.reactRouterConfig)))};
@@ -434,7 +448,7 @@ const reactRouterVitePlugin = _config => {
434
448
  path: route.path,
435
449
  index: route.index,
436
450
  caseSensitive: route.caseSensitive,
437
- module: path__namespace.posix.join(ctx.publicPath, `${resolveFileUrl.resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig))}`),
451
+ module: path__namespace.posix.join(ctx.publicPath, `${resolveFileUrl.resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig))}${ROUTE_ENTRY_QUERY_STRING}`),
438
452
  hasAction: sourceExports.includes("action"),
439
453
  hasLoader: sourceExports.includes("loader"),
440
454
  hasClientAction: sourceExports.includes("clientAction"),
@@ -540,7 +554,7 @@ const reactRouterVitePlugin = _config => {
540
554
  rollupOptions: {
541
555
  ...baseRollupOptions,
542
556
  preserveEntrySignatures: "exports-only",
543
- input: [ctx.entryClientFilePath, ...Object.values(ctx.reactRouterConfig.routes).map(route => `${path__namespace.resolve(ctx.reactRouterConfig.appDirectory, route.file)}${BUILD_CLIENT_ROUTE_QUERY_STRING}`)]
557
+ input: [ctx.entryClientFilePath, ...Object.values(ctx.reactRouterConfig.routes).map(route => `${path__namespace.resolve(ctx.reactRouterConfig.appDirectory, route.file)}${ROUTE_ENTRY_QUERY_STRING}`)]
544
558
  }
545
559
  } : {
546
560
  // We move SSR-only assets to client assets. Note that the
@@ -637,13 +651,6 @@ const reactRouterVitePlugin = _config => {
637
651
  if (styles.isCssModulesFile(id)) {
638
652
  cssModulesManifest[id] = code;
639
653
  }
640
- if (id.endsWith(BUILD_CLIENT_ROUTE_QUERY_STRING)) {
641
- let routeModuleId = id.replace(BUILD_CLIENT_ROUTE_QUERY_STRING, "");
642
- let sourceExports = await getRouteModuleExports(viteChildCompiler, ctx, routeModuleId);
643
- let routeFileName = path__namespace.basename(routeModuleId);
644
- let clientExports = sourceExports.filter(exportName => CLIENT_ROUTE_EXPORTS.includes(exportName)).join(", ");
645
- return `export { ${clientExports} } from "./${routeFileName}";`;
646
- }
647
654
  },
648
655
  buildStart() {
649
656
  invariant["default"](viteConfig);
@@ -770,6 +777,34 @@ const reactRouterVitePlugin = _config => {
770
777
  var _viteChildCompiler;
771
778
  await ((_viteChildCompiler = viteChildCompiler) === null || _viteChildCompiler === void 0 ? void 0 : _viteChildCompiler.close());
772
779
  }
780
+ }, {
781
+ name: "react-router-route-entry",
782
+ enforce: "pre",
783
+ async transform(code, id, options) {
784
+ if (!isRouteEntry(id)) return;
785
+ let routeModuleId = id.replace(ROUTE_ENTRY_QUERY_STRING, "");
786
+ let routeFileName = path__namespace.basename(routeModuleId);
787
+ if (!code.includes("defineRoute")) {
788
+ let sourceExports = await getRouteModuleExports(viteChildCompiler, ctx, routeModuleId);
789
+ 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(", ");
790
+ return `export { ${reexports} } from "./${routeFileName}";`;
791
+ }
792
+ let renameFields = ["Component", "serverLoader", "serverAction"];
793
+ let fields = defineRoute.parseFields(code);
794
+ let reexports = fields.filter(exportName => !renameFields.includes(exportName)).filter(exportName => (options === null || options === void 0 ? void 0 : options.ssr) && SERVER_ONLY_ROUTE_EXPORTS.includes(exportName) || CLIENT_ROUTE_EXPORTS.includes(exportName)).map(reexport => `export const ${reexport} = route.${reexport};`);
795
+ let content = `import route from "./${routeFileName}";`;
796
+ if (fields.includes("Component")) {
797
+ content += `\n` + [`import { createElement } from "react";`, `import { useParams, useLoaderData, useActionData } from "react-router";`, `export default function Route() {`, ` let params = useParams();`, ` let loaderData = useLoaderData();`, ` let actionData = useActionData();`, ` return createElement(route.Component, { params, loaderData, actionData });`, `}`].join("\n");
798
+ }
799
+ if (options !== null && options !== void 0 && options.ssr && fields.includes("serverLoader")) {
800
+ content += `\nexport const loader = route.serverLoader;`;
801
+ }
802
+ if (options !== null && options !== void 0 && options.ssr && fields.includes("serverAction")) {
803
+ content += `\nexport const action = route.serverAction;`;
804
+ }
805
+ content += "\n" + reexports.join("\n");
806
+ return content;
807
+ }
773
808
  }, {
774
809
  name: "react-router-virtual-modules",
775
810
  enforce: "pre",
@@ -807,13 +842,13 @@ const reactRouterVitePlugin = _config => {
807
842
  enforce: "pre",
808
843
  async transform(code, id, options) {
809
844
  if (options !== null && options !== void 0 && options.ssr) return;
810
- if (id.endsWith(BUILD_CLIENT_ROUTE_QUERY_STRING)) return;
845
+ if (!code.includes("defineRoute")) return; // temporary back compat, remove once old style routes are unsupported
846
+ if (id.endsWith(ROUTE_ENTRY_QUERY_STRING)) return;
811
847
  let route = getRoute(ctx.reactRouterConfig, id);
812
848
  if (!route && code.includes("defineRoute")) {
813
849
  return defineRoute.assertNotImported(code);
814
850
  }
815
- if (!code.includes("defineRoute")) return; // temporary back compat, remove once old style routes are unsupported
816
- defineRoute.transform(code);
851
+ return defineRoute.transform(code, id, options);
817
852
  }
818
853
  }, {
819
854
  name: "react-router-dot-server",
@@ -928,6 +963,11 @@ const reactRouterVitePlugin = _config => {
928
963
  let isJSX = filepath.endsWith("x");
929
964
  let useFastRefresh = !ssr && (isJSX || code.includes(devRuntime));
930
965
  if (!useFastRefresh) return;
966
+ if (isRouteEntry(id)) {
967
+ return {
968
+ code: addRefreshWrapper(ctx.reactRouterConfig, code, id)
969
+ };
970
+ }
931
971
  let result = await babel__default["default"].transformAsync(code, {
932
972
  babelrc: false,
933
973
  configFile: false,
@@ -996,7 +1036,7 @@ function isEqualJson(v1, v2) {
996
1036
  }
997
1037
  function addRefreshWrapper(reactRouterConfig, code, id) {
998
1038
  let route = getRoute(reactRouterConfig, id);
999
- let acceptExports = route ? ["clientAction", "clientLoader", "handle", "meta", "links", "shouldRevalidate"] : [];
1039
+ let acceptExports = route || isRouteEntry(id) ? ["clientAction", "clientLoader", "handle", "meta", "links", "shouldRevalidate"] : [];
1000
1040
  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 === null || route === void 0 ? void 0 : route.id));
1001
1041
  }
1002
1042
  const REACT_REFRESH_HEADER = `
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/vite/vmod.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-ecd35cd60
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-router/dev",
3
- "version": "0.0.0-experimental-4996fbe2b",
3
+ "version": "0.0.0-experimental-ecd35cd60",
4
4
  "description": "Dev tools and CLI for React Router",
5
5
  "homepage": "https://reactrouter.com",
6
6
  "bugs": {
@@ -15,7 +15,7 @@
15
15
  "main": "dist/index.js",
16
16
  "typings": "dist/index.d.ts",
17
17
  "bin": {
18
- "react-router": "dist/cli.js"
18
+ "react-router": "bin.js"
19
19
  },
20
20
  "dependencies": {
21
21
  "@babel/core": "^7.21.8",
@@ -28,6 +28,7 @@
28
28
  "@babel/types": "^7.22.5",
29
29
  "@npmcli/package-json": "^4.0.1",
30
30
  "arg": "^5.0.1",
31
+ "babel-dead-code-elimination": "^1.0.6",
31
32
  "chalk": "^4.1.2",
32
33
  "es-module-lexer": "^1.3.1",
33
34
  "exit-hook": "2.2.1",
@@ -42,7 +43,7 @@
42
43
  "react-refresh": "^0.14.0",
43
44
  "semver": "^7.3.7",
44
45
  "set-cookie-parser": "^2.6.0",
45
- "@react-router/node": "0.0.0-experimental-4996fbe2b"
46
+ "@react-router/node": "0.0.0-experimental-ecd35cd60"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@types/babel__core": "^7.20.5",
@@ -66,14 +67,14 @@
66
67
  "strip-ansi": "^6.0.1",
67
68
  "tiny-invariant": "^1.2.0",
68
69
  "vite": "^5.1.0",
69
- "@react-router/serve": "0.0.0-experimental-4996fbe2b",
70
- "react-router": "^0.0.0-experimental-4996fbe2b"
70
+ "react-router": "^0.0.0-experimental-ecd35cd60",
71
+ "@react-router/serve": "0.0.0-experimental-ecd35cd60"
71
72
  },
72
73
  "peerDependencies": {
73
74
  "typescript": "^5.1.0",
74
75
  "vite": "^5.1.0",
75
- "@react-router/serve": "^0.0.0-experimental-4996fbe2b",
76
- "react-router": "^0.0.0-experimental-4996fbe2b"
76
+ "@react-router/serve": "^0.0.0-experimental-ecd35cd60",
77
+ "react-router": "^0.0.0-experimental-ecd35cd60"
77
78
  },
78
79
  "peerDependenciesMeta": {
79
80
  "@react-router/serve": {
@@ -88,6 +89,7 @@
88
89
  },
89
90
  "files": [
90
91
  "dist/",
92
+ "bin.js",
91
93
  "CHANGELOG.md",
92
94
  "LICENSE.md",
93
95
  "README.md"