@react-router/dev 0.0.0-experimental-4996fbe2b → 0.0.0-experimental-49eef6a01

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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -232,11 +232,11 @@ async function resolveEntryFiles({
232
232
  throw new Error(`Could not determine server runtime. Please install @react-router/node, or provide a custom entry.server.tsx/jsx file in your app directory.`);
233
233
  }
234
234
  if (!deps["isbot"]) {
235
- console.log("adding `isbot` to your package.json, you should commit this change");
235
+ console.log("adding `isbot@5` to your package.json, you should commit this change");
236
236
  pkgJson.update({
237
237
  dependencies: {
238
238
  ...pkgJson.content.dependencies,
239
- isbot: "^4"
239
+ isbot: "^5"
240
240
  }
241
241
  });
242
242
  await pkgJson.save();
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export * as cli from "./cli/index";
2
2
  export type { Manifest as AssetsManifest } from "./manifest";
3
3
  export type { BuildManifest, Preset, ServerBundlesFunction, VitePluginConfig, } from "./config";
4
- export { vitePlugin } from "./vite";
4
+ export { vitePlugin, cloudflareDevProxyVitePlugin } from "./vite";
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-49eef6a01
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -14,8 +14,10 @@ Object.defineProperty(exports, '__esModule', { value: true });
14
14
 
15
15
  var index = require('./cli/index.js');
16
16
  var index$1 = require('./vite/index.js');
17
+ var cloudflareDevProxy = require('./vite/cloudflare-dev-proxy.js');
17
18
 
18
19
 
19
20
 
20
21
  exports.cli = index;
21
22
  exports.vitePlugin = index$1.vitePlugin;
23
+ exports.cloudflareDevProxyVitePlugin = cloudflareDevProxy.cloudflareDevProxyVitePlugin;
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-49eef6a01
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-49eef6a01
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-49eef6a01
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -0,0 +1,15 @@
1
+ import { type AppLoadContext } from "react-router";
2
+ import { type Plugin } from "vite";
3
+ import { type GetPlatformProxyOptions, type PlatformProxy } from "wrangler";
4
+ type CfProperties = Record<string, unknown>;
5
+ type LoadContext<Env, Cf extends CfProperties> = {
6
+ cloudflare: Omit<PlatformProxy<Env, Cf>, "dispose">;
7
+ };
8
+ type GetLoadContext<Env, Cf extends CfProperties> = (args: {
9
+ request: Request;
10
+ context: LoadContext<Env, Cf>;
11
+ }) => AppLoadContext | Promise<AppLoadContext>;
12
+ export declare const cloudflareDevProxyVitePlugin: <Env, Cf extends CfProperties>({ getLoadContext, ...options }?: {
13
+ getLoadContext?: GetLoadContext<Env, Cf>;
14
+ } & GetPlatformProxyOptions) => Plugin;
15
+ export {};
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @react-router/dev v0.0.0-experimental-49eef6a01
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 reactRouter = require('react-router');
16
+ var wrangler = require('wrangler');
17
+ var nodeAdapter = require('./node-adapter.js');
18
+
19
+ let serverBuildId = "virtual:react-router/server-build";
20
+ const PLUGIN_NAME = "react-router-cloudflare-vite-dev-proxy";
21
+ const cloudflareDevProxyVitePlugin = ({
22
+ getLoadContext,
23
+ ...options
24
+ } = {}) => {
25
+ return {
26
+ name: PLUGIN_NAME,
27
+ config: () => ({
28
+ ssr: {
29
+ resolve: {
30
+ externalConditions: ["workerd", "worker"]
31
+ }
32
+ }
33
+ }),
34
+ configResolved: viteConfig => {
35
+ let pluginIndex = name => viteConfig.plugins.findIndex(plugin => plugin.name === name);
36
+ let reactRouterPluginIndex = pluginIndex("react-router");
37
+ if (reactRouterPluginIndex >= 0 && reactRouterPluginIndex < pluginIndex(PLUGIN_NAME)) {
38
+ throw new Error(`The "${PLUGIN_NAME}" plugin should be placed before the React Router plugin in your Vite config file`);
39
+ }
40
+ },
41
+ configureServer: async viteDevServer => {
42
+ // Do not include `dispose` in Cloudflare context
43
+ let {
44
+ dispose,
45
+ ...cloudflare
46
+ } = await wrangler.getPlatformProxy(options);
47
+ let context = {
48
+ cloudflare
49
+ };
50
+ return () => {
51
+ if (!viteDevServer.config.server.middlewareMode) {
52
+ viteDevServer.middlewares.use(async (nodeReq, nodeRes, next) => {
53
+ try {
54
+ let build = await viteDevServer.ssrLoadModule(serverBuildId);
55
+ let handler = reactRouter.createRequestHandler(build, "development");
56
+ let req = nodeAdapter.fromNodeRequest(nodeReq);
57
+ let loadContext = getLoadContext ? await getLoadContext({
58
+ request: req,
59
+ context
60
+ }) : context;
61
+ let res = await handler(req, loadContext);
62
+ await nodeAdapter.toNodeRequest(res, nodeRes);
63
+ } catch (error) {
64
+ next(error);
65
+ }
66
+ });
67
+ }
68
+ };
69
+ }
70
+ };
71
+ };
72
+
73
+ exports.cloudflareDevProxyVitePlugin = cloudflareDevProxyVitePlugin;
@@ -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-49eef6a01
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-49eef6a01
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-49eef6a01
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,2 +1,3 @@
1
1
  import type { ReactRouterVitePlugin } from "./plugin";
2
2
  export declare const vitePlugin: ReactRouterVitePlugin;
3
+ export { cloudflareDevProxyVitePlugin } from "./cloudflare-dev-proxy";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-49eef6a01
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -12,6 +12,13 @@
12
12
 
13
13
  Object.defineProperty(exports, '__esModule', { value: true });
14
14
 
15
+ require('react-router');
16
+ require('wrangler');
17
+ require('node:events');
18
+ require('node:stream');
19
+ require('set-cookie-parser');
20
+ require('@react-router/node');
21
+
15
22
  const vitePlugin = (...args) => {
16
23
  let {
17
24
  reactRouterVitePlugin
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-49eef6a01
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-49eef6a01
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"),
@@ -496,7 +510,7 @@ const reactRouterVitePlugin = _config => {
496
510
  // This is only needed within this repo because these packages
497
511
  // are linked to a directory outside of node_modules so Vite
498
512
  // treats them as internal code by default.
499
- "react-router", "react-router-dom", "@react-router/dev", "@react-router/express", "@react-router/node", "@react-router/serve"] : undefined
513
+ "react-router", "react-router-dom", "@react-router/cloudflare", "@react-router/dev", "@react-router/express", "@react-router/node", "@react-router/serve"] : undefined
500
514
  },
501
515
  optimizeDeps: {
502
516
  include: [
@@ -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 = `
@@ -1106,19 +1146,20 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
1106
1146
  }
1107
1147
  await prerenderRoute(handler, path, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit);
1108
1148
  }
1109
- async function prerenderData(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
1110
- let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
1111
- let request = new Request(`http://localhost${normalizedPath}`, requestInit);
1112
- let response = await handler(request);
1113
- let data = await response.text();
1114
- validatePrerenderedResponse(response, data, "Prerender", normalizedPath);
1115
- // Write out the .data file
1116
- let outdir = path__namespace.relative(process.cwd(), clientBuildDirectory);
1117
- let outfile = path__namespace.join(outdir, normalizedPath.split("/").join(path__namespace.sep));
1118
- await fse__namespace.ensureDir(path__namespace.dirname(outfile));
1119
- await fse__namespace.outputFile(outfile, data);
1120
- viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
1121
- }
1149
+ await prerenderManifest(build, clientBuildDirectory, reactRouterConfig, viteConfig);
1150
+ }
1151
+ async function prerenderData(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
1152
+ let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
1153
+ let request = new Request(`http://localhost${normalizedPath}`, requestInit);
1154
+ let response = await handler(request);
1155
+ let data = await response.text();
1156
+ validatePrerenderedResponse(response, data, "Prerender", normalizedPath);
1157
+ // Write out the .data file
1158
+ let outdir = path__namespace.relative(process.cwd(), clientBuildDirectory);
1159
+ let outfile = path__namespace.join(outdir, ...normalizedPath.split("/"));
1160
+ await fse__namespace.ensureDir(path__namespace.dirname(outfile));
1161
+ await fse__namespace.outputFile(outfile, data);
1162
+ viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
1122
1163
  }
1123
1164
  async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
1124
1165
  let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/");
@@ -1136,6 +1177,18 @@ async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reac
1136
1177
  await fse__namespace.outputFile(outfile, html);
1137
1178
  viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
1138
1179
  }
1180
+ async function prerenderManifest(build, clientBuildDirectory, reactRouterConfig, viteConfig) {
1181
+ let normalizedPath = `${reactRouterConfig.basename}/__manifest`.replace(/\/\/+/g, "/");
1182
+ let outdir = path__namespace.relative(process.cwd(), clientBuildDirectory);
1183
+ let outfile = path__namespace.join(outdir, ...normalizedPath.split("/"));
1184
+ await fse__namespace.ensureDir(path__namespace.dirname(outfile));
1185
+ let manifestData = JSON.stringify({
1186
+ notFoundPaths: [],
1187
+ patches: build.assets.routes
1188
+ });
1189
+ await fse__namespace.outputFile(outfile, manifestData);
1190
+ viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
1191
+ }
1139
1192
  function validatePrerenderedResponse(response, html, prefix, path) {
1140
1193
  if (response.status !== 200) {
1141
1194
  throw new Error(`${prefix}: Received a ${response.status} status code from ` + `\`entry.server.tsx\` while prerendering the \`${path}\` ` + `path.\n${html}`);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-4996fbe2b
2
+ * @react-router/dev v0.0.0-experimental-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01
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-49eef6a01",
4
4
  "description": "Dev tools and CLI for React Router",
5
5
  "homepage": "https://reactrouter.com",
6
6
  "bugs": {
@@ -14,8 +14,15 @@
14
14
  "license": "MIT",
15
15
  "main": "dist/index.js",
16
16
  "typings": "dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
17
24
  "bin": {
18
- "react-router": "dist/cli.js"
25
+ "react-router": "bin.js"
19
26
  },
20
27
  "dependencies": {
21
28
  "@babel/core": "^7.21.8",
@@ -28,6 +35,7 @@
28
35
  "@babel/types": "^7.22.5",
29
36
  "@npmcli/package-json": "^4.0.1",
30
37
  "arg": "^5.0.1",
38
+ "babel-dead-code-elimination": "^1.0.6",
31
39
  "chalk": "^4.1.2",
32
40
  "es-module-lexer": "^1.3.1",
33
41
  "exit-hook": "2.2.1",
@@ -42,7 +50,7 @@
42
50
  "react-refresh": "^0.14.0",
43
51
  "semver": "^7.3.7",
44
52
  "set-cookie-parser": "^2.6.0",
45
- "@react-router/node": "0.0.0-experimental-4996fbe2b"
53
+ "@react-router/node": "0.0.0-experimental-49eef6a01"
46
54
  },
47
55
  "devDependencies": {
48
56
  "@types/babel__core": "^7.20.5",
@@ -66,14 +74,16 @@
66
74
  "strip-ansi": "^6.0.1",
67
75
  "tiny-invariant": "^1.2.0",
68
76
  "vite": "^5.1.0",
69
- "@react-router/serve": "0.0.0-experimental-4996fbe2b",
70
- "react-router": "^0.0.0-experimental-4996fbe2b"
77
+ "wrangler": "^3.28.2",
78
+ "@react-router/serve": "0.0.0-experimental-49eef6a01",
79
+ "react-router": "^0.0.0-experimental-49eef6a01"
71
80
  },
72
81
  "peerDependencies": {
73
82
  "typescript": "^5.1.0",
74
83
  "vite": "^5.1.0",
75
- "@react-router/serve": "^0.0.0-experimental-4996fbe2b",
76
- "react-router": "^0.0.0-experimental-4996fbe2b"
84
+ "wrangler": "^3.28.2",
85
+ "@react-router/serve": "^0.0.0-experimental-49eef6a01",
86
+ "react-router": "^0.0.0-experimental-49eef6a01"
77
87
  },
78
88
  "peerDependenciesMeta": {
79
89
  "@react-router/serve": {
@@ -81,6 +91,9 @@
81
91
  },
82
92
  "typescript": {
83
93
  "optional": true
94
+ },
95
+ "wrangler": {
96
+ "optional": true
84
97
  }
85
98
  },
86
99
  "engines": {
@@ -88,6 +101,7 @@
88
101
  },
89
102
  "files": [
90
103
  "dist/",
104
+ "bin.js",
91
105
  "CHANGELOG.md",
92
106
  "LICENSE.md",
93
107
  "README.md"