@react-router/dev 0.0.0-experimental-fbbd4fd81 → 0.0.0-experimental-27337b0d6

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 (38) hide show
  1. package/dist/cli/commands.js +2 -2
  2. package/dist/cli/detectPackageManager.js +1 -1
  3. package/dist/cli/index.js +1 -1
  4. package/dist/cli/run.js +1 -1
  5. package/dist/cli/useJavascript.js +1 -1
  6. package/dist/cli.js +1 -1
  7. package/dist/colors.js +1 -1
  8. package/dist/config/defaults/entry.client.rsc.tsx +90 -0
  9. package/dist/config/defaults/entry.react-server.node.tsx +15 -0
  10. package/dist/config/defaults/entry.react-server.web.tsx +9 -0
  11. package/dist/config/defaults/entry.server.node.rsc.tsx +164 -0
  12. package/dist/config/defaults/entry.server.spa.tsx +63 -10
  13. package/dist/config/findConfig.js +1 -1
  14. package/dist/config/flatRoutes.js +1 -1
  15. package/dist/config/format.js +1 -1
  16. package/dist/config/routes.js +1 -1
  17. package/dist/config.d.ts +15 -1
  18. package/dist/config.js +35 -9
  19. package/dist/index.js +1 -1
  20. package/dist/invariant.js +1 -1
  21. package/dist/runtime.client.d.ts +1 -0
  22. package/dist/runtime.client.js +19 -0
  23. package/dist/vite/babel.js +1 -1
  24. package/dist/vite/build.js +15 -2
  25. package/dist/vite/cloudflare-proxy-plugin.js +1 -1
  26. package/dist/vite/dev.js +1 -1
  27. package/dist/vite/import-vite-esm-sync.js +1 -1
  28. package/dist/vite/index.js +1 -1
  29. package/dist/vite/node-adapter.js +1 -1
  30. package/dist/vite/plugin.d.ts +9 -0
  31. package/dist/vite/plugin.js +347 -40
  32. package/dist/vite/profiler.js +1 -1
  33. package/dist/vite/remove-exports.d.ts +3 -1
  34. package/dist/vite/remove-exports.js +18 -2
  35. package/dist/vite/resolve-file-url.js +1 -1
  36. package/dist/vite/styles.js +1 -1
  37. package/dist/vite/vmod.js +1 -1
  38. package/package.json +13 -7
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -128,7 +128,7 @@ async function generateEntry(entry, reactRouterRoot, flags = {}) {
128
128
  }
129
129
  let defaultsDirectory = path__namespace.resolve(__dirname, "..", "config", "defaults");
130
130
  let defaultEntryClient = path__namespace.resolve(defaultsDirectory, "entry.client.tsx");
131
- let defaultEntryServer = path__namespace.resolve(defaultsDirectory, (ctx === null || ctx === void 0 ? void 0 : ctx.reactRouterConfig.ssr) === false && (ctx === null || ctx === void 0 ? void 0 : ctx.reactRouterConfig.future.unstable_singleFetch) !== true ? `entry.server.spa.tsx` : `entry.server.${serverRuntime}.tsx`);
131
+ let defaultEntryServer = path__namespace.resolve(defaultsDirectory, (ctx === null || ctx === void 0 ? void 0 : ctx.reactRouterConfig.ssr) === false ? `entry.server.spa.tsx` : `entry.server.${serverRuntime}.tsx`);
132
132
  let isServerEntry = entry === "entry.server";
133
133
  let contents = isServerEntry ? await createServerEntry(rootDirectory, appDirectory, defaultEntryServer) : await createClientEntry(rootDirectory, appDirectory, defaultEntryClient);
134
134
  let useTypeScript = flags.typescript ?? true;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
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-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
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-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
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-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * @react-router/dev v0.0.0-experimental-fbbd4fd81
3
+ * @react-router/dev v0.0.0-experimental-27337b0d6
4
4
  *
5
5
  * Copyright (c) Remix Software Inc.
6
6
  *
package/dist/colors.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -0,0 +1,90 @@
1
+ import { HydratedRouter } from "react-router";
2
+ import { startTransition, StrictMode } from "react";
3
+ import { hydrateRoot } from "react-dom/client";
4
+ // @ts-expect-error - no types
5
+ import ReactServerDOM from "react-server-dom-diy/client";
6
+
7
+ if (import.meta.env.PROD) {
8
+ window.__diy_client_manifest__ = {
9
+ _cache: new Map(),
10
+ resolveClientReference([id, exportName]) {
11
+ return {
12
+ preloadModule() {
13
+ if (window.__diy_client_manifest__._cache.has(id)) {
14
+ return window.__diy_client_manifest__._cache.get(id);
15
+ }
16
+ const promise = import("virtual:react-router/client-references")
17
+ .then(({ default: mods }) => mods[id]())
18
+ .then((mod) => {
19
+ promise.status = "fulfilled";
20
+ promise.value = mod;
21
+ })
22
+ .catch((res) => {
23
+ promise.status = "rejected";
24
+ promise.reason = res;
25
+ throw res;
26
+ });
27
+ promise.status = "pending";
28
+ window.__diy_client_manifest__._cache.set(id, promise);
29
+ return promise;
30
+ },
31
+ requireModule() {
32
+ const cached = window.__diy_client_manifest__._cache.get(id);
33
+ if (!cached) throw new Error(`Module ${id} not found`);
34
+ if (cached.reason) throw cached.reason;
35
+ return cached.value[exportName];
36
+ },
37
+ };
38
+ },
39
+ };
40
+ } else {
41
+ window.__diy_client_manifest__ = {
42
+ _cache: new Map(),
43
+ resolveClientReference([id, exportName]) {
44
+ return {
45
+ preloadModule() {
46
+ if (window.__diy_client_manifest__._cache.has(id)) {
47
+ return window.__diy_client_manifest__._cache.get(id);
48
+ }
49
+ const promise = import(id)
50
+ .then((mod) => {
51
+ promise.status = "fulfilled";
52
+ promise.value = mod;
53
+ })
54
+ .catch((res) => {
55
+ promise.status = "rejected";
56
+ promise.reason = res;
57
+ throw res;
58
+ });
59
+ promise.status = "pending";
60
+ window.__diy_client_manifest__._cache.set(id, promise);
61
+ return promise;
62
+ },
63
+ requireModule() {
64
+ const cached = window.__diy_client_manifest__._cache.get(id);
65
+ if (!cached) throw new Error(`Module ${id} not found`);
66
+ if (cached.reason) throw cached.reason;
67
+ return cached.value[exportName];
68
+ },
69
+ };
70
+ },
71
+ };
72
+ }
73
+
74
+ window.createFromReadableStream = function createFromReadableStream(
75
+ body: ReadableStream<Uint8Array>
76
+ ) {
77
+ return ReactServerDOM.createFromReadableStream(
78
+ body,
79
+ window.__diy_client_manifest__
80
+ );
81
+ };
82
+
83
+ startTransition(() => {
84
+ hydrateRoot(
85
+ document,
86
+ <StrictMode>
87
+ <HydratedRouter />
88
+ </StrictMode>
89
+ );
90
+ });
@@ -0,0 +1,15 @@
1
+ import * as stream from "node:stream";
2
+
3
+ import { createReadableStreamFromReadable } from "@react-router/node";
4
+ // @ts-expect-error - no types
5
+ import ReactServerDOM from "react-server-dom-diy/server";
6
+
7
+ export function renderToReadableStream(data: unknown) {
8
+ const passthrough = new stream.PassThrough();
9
+ const { pipe } = ReactServerDOM.renderToPipeableStream(
10
+ data,
11
+ global.__diy_server_manifest__
12
+ );
13
+ pipe(passthrough);
14
+ return createReadableStreamFromReadable(passthrough);
15
+ }
@@ -0,0 +1,9 @@
1
+ // @ts-expect-error - no types
2
+ import ReactServerDOM from "react-server-dom-diy/server";
3
+
4
+ export function renderToReadableStream(data: unknown) {
5
+ return ReactServerDOM.renderToReadableStream(
6
+ data,
7
+ global.__diy_server_manifest__
8
+ );
9
+ }
@@ -0,0 +1,164 @@
1
+ import { PassThrough, Readable } from "node:stream";
2
+
3
+ import type { AppLoadContext, EntryContext } from "@react-router/node";
4
+ import { createReadableStreamFromReadable } from "@react-router/node";
5
+ import { RemixServer } from "react-router";
6
+ import * as isbotModule from "isbot";
7
+ import { renderToPipeableStream } from "react-dom/server";
8
+ // @ts-expect-error - no types
9
+ import ReactServerDOM from "react-server-dom-diy/client";
10
+
11
+ const ABORT_DELAY = 5_000;
12
+
13
+ export function createFromReadableStream(body: ReadableStream<Uint8Array>) {
14
+ return ReactServerDOM.createFromNodeStream(
15
+ Readable.fromWeb(body as any),
16
+ global.__diy_client_manifest__
17
+ );
18
+ }
19
+
20
+ export default function handleRequest(
21
+ request: Request,
22
+ responseStatusCode: number,
23
+ responseHeaders: Headers,
24
+ remixContext: EntryContext,
25
+ loadContext: AppLoadContext
26
+ ) {
27
+ let prohibitOutOfOrderStreaming =
28
+ isBotRequest(request.headers.get("user-agent")) || remixContext.isSpaMode;
29
+
30
+ return prohibitOutOfOrderStreaming
31
+ ? handleBotRequest(
32
+ request,
33
+ responseStatusCode,
34
+ responseHeaders,
35
+ remixContext
36
+ )
37
+ : handleBrowserRequest(
38
+ request,
39
+ responseStatusCode,
40
+ responseHeaders,
41
+ remixContext
42
+ );
43
+ }
44
+
45
+ // We have some Remix apps in the wild already running with isbot@3 so we need
46
+ // to maintain backwards compatibility even though we want new apps to use
47
+ // isbot@4. That way, we can ship this as a minor Semver update to @react-router/dev.
48
+ function isBotRequest(userAgent: string | null) {
49
+ if (!userAgent) {
50
+ return false;
51
+ }
52
+
53
+ // isbot >= 3.8.0, >4
54
+ if ("isbot" in isbotModule && typeof isbotModule.isbot === "function") {
55
+ return isbotModule.isbot(userAgent);
56
+ }
57
+
58
+ // isbot < 3.8.0
59
+ if ("default" in isbotModule && typeof isbotModule.default === "function") {
60
+ return isbotModule.default(userAgent);
61
+ }
62
+
63
+ return false;
64
+ }
65
+
66
+ function handleBotRequest(
67
+ request: Request,
68
+ responseStatusCode: number,
69
+ responseHeaders: Headers,
70
+ remixContext: EntryContext
71
+ ) {
72
+ return new Promise((resolve, reject) => {
73
+ let shellRendered = false;
74
+ const { pipe, abort } = renderToPipeableStream(
75
+ <RemixServer
76
+ context={remixContext}
77
+ url={request.url}
78
+ abortDelay={ABORT_DELAY}
79
+ />,
80
+ {
81
+ onAllReady() {
82
+ shellRendered = true;
83
+ const body = new PassThrough();
84
+ const stream = createReadableStreamFromReadable(body);
85
+
86
+ responseHeaders.set("Content-Type", "text/html");
87
+
88
+ resolve(
89
+ new Response(stream, {
90
+ headers: responseHeaders,
91
+ status: responseStatusCode,
92
+ })
93
+ );
94
+
95
+ pipe(body);
96
+ },
97
+ onShellError(error: unknown) {
98
+ reject(error);
99
+ },
100
+ onError(error: unknown) {
101
+ responseStatusCode = 500;
102
+ // Log streaming rendering errors from inside the shell. Don't log
103
+ // errors encountered during initial shell rendering since they'll
104
+ // reject and get logged in handleDocumentRequest.
105
+ if (shellRendered) {
106
+ console.error(error);
107
+ }
108
+ },
109
+ }
110
+ );
111
+
112
+ setTimeout(abort, ABORT_DELAY);
113
+ });
114
+ }
115
+
116
+ function handleBrowserRequest(
117
+ request: Request,
118
+ responseStatusCode: number,
119
+ responseHeaders: Headers,
120
+ remixContext: EntryContext
121
+ ) {
122
+ return new Promise((resolve, reject) => {
123
+ let shellRendered = false;
124
+ const { pipe, abort } = renderToPipeableStream(
125
+ <RemixServer
126
+ context={remixContext}
127
+ url={request.url}
128
+ abortDelay={ABORT_DELAY}
129
+ />,
130
+ {
131
+ onShellReady() {
132
+ shellRendered = true;
133
+ const body = new PassThrough();
134
+ const stream = createReadableStreamFromReadable(body);
135
+
136
+ responseHeaders.set("Content-Type", "text/html");
137
+
138
+ resolve(
139
+ new Response(stream, {
140
+ headers: responseHeaders,
141
+ status: responseStatusCode,
142
+ })
143
+ );
144
+
145
+ pipe(body);
146
+ },
147
+ onShellError(error: unknown) {
148
+ reject(error);
149
+ },
150
+ onError(error: unknown) {
151
+ responseStatusCode = 500;
152
+ // Log streaming rendering errors from inside the shell. Don't log
153
+ // errors encountered during initial shell rendering since they'll
154
+ // reject and get logged in handleDocumentRequest.
155
+ if (shellRendered) {
156
+ console.error(error);
157
+ }
158
+ },
159
+ }
160
+ );
161
+
162
+ setTimeout(abort, ABORT_DELAY);
163
+ });
164
+ }
@@ -1,20 +1,73 @@
1
- import type { EntryContext } from "@react-router/node";
1
+ import { PassThrough } from "node:stream";
2
+
3
+ import type { AppLoadContext, EntryContext } from "@react-router/node";
4
+ import { createReadableStreamFromReadable } from "@react-router/node";
2
5
  import { RemixServer } from "react-router";
3
- import * as React from "react";
4
- import { renderToString } from "react-dom/server";
6
+ import { renderToPipeableStream } from "react-dom/server";
7
+
8
+ const ABORT_DELAY = 5_000;
5
9
 
6
10
  export default function handleRequest(
7
11
  request: Request,
8
12
  responseStatusCode: number,
9
13
  responseHeaders: Headers,
10
- remixContext: EntryContext
14
+ remixContext: EntryContext,
15
+ loadContext: AppLoadContext
11
16
  ) {
12
- let html = renderToString(
13
- <RemixServer context={remixContext} url={request.url} />
17
+ return handleBotRequest(
18
+ request,
19
+ responseStatusCode,
20
+ responseHeaders,
21
+ remixContext
14
22
  );
15
- html = "<!DOCTYPE html>\n" + html;
16
- return new Response(html, {
17
- headers: { "Content-Type": "text/html" },
18
- status: responseStatusCode,
23
+ }
24
+
25
+ function handleBotRequest(
26
+ request: Request,
27
+ responseStatusCode: number,
28
+ responseHeaders: Headers,
29
+ remixContext: EntryContext
30
+ ) {
31
+ return new Promise((resolve, reject) => {
32
+ let shellRendered = false;
33
+ const { pipe, abort } = renderToPipeableStream(
34
+ <RemixServer
35
+ context={remixContext}
36
+ url={request.url}
37
+ abortDelay={ABORT_DELAY}
38
+ />,
39
+ {
40
+ onAllReady() {
41
+ shellRendered = true;
42
+ const body = new PassThrough();
43
+ const stream = createReadableStreamFromReadable(body);
44
+
45
+ responseHeaders.set("Content-Type", "text/html");
46
+
47
+ resolve(
48
+ new Response(stream, {
49
+ headers: responseHeaders,
50
+ status: responseStatusCode,
51
+ })
52
+ );
53
+
54
+ pipe(body);
55
+ },
56
+ onShellError(error: unknown) {
57
+ reject(error);
58
+ },
59
+ onError(error: unknown) {
60
+ responseStatusCode = 500;
61
+ // Log streaming rendering errors from inside the shell. Don't log
62
+ // errors encountered during initial shell rendering since they'll
63
+ // reject and get logged in handleDocumentRequest.
64
+ if (shellRendered) {
65
+ console.error(error);
66
+ }
67
+ },
68
+ }
69
+ );
70
+
71
+ setTimeout(abort, ABORT_DELAY);
19
72
  });
20
73
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
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-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
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-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
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-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/config.d.ts CHANGED
@@ -39,7 +39,7 @@ interface FutureConfig {
39
39
  v3_fetcherPersist: boolean;
40
40
  v3_relativeSplatPath: boolean;
41
41
  v3_throwAbortReason: boolean;
42
- unstable_singleFetch: boolean;
42
+ unstable_serverComponents: boolean;
43
43
  }
44
44
  export type BuildManifest = DefaultBuildManifest | ServerBundlesBuildManifest;
45
45
  type BuildEndHook = (args: {
@@ -93,6 +93,11 @@ export type VitePluginConfig = {
93
93
  * Defaults to `false`.
94
94
  */
95
95
  manifest?: boolean;
96
+ /**
97
+ * An array of URLs to prerender to HTML files at build time. Can also be a
98
+ * function returning an array to dynamically generate URLs.
99
+ */
100
+ prerender?: Array<string> | (() => Array<string> | Promise<Array<string>>);
96
101
  /**
97
102
  * An array of React Router plugin config presets to ease integration with
98
103
  * other platforms and tools.
@@ -144,6 +149,10 @@ export type ResolvedVitePluginConfig = Readonly<{
144
149
  * Defaults to `false`.
145
150
  */
146
151
  manifest: boolean;
152
+ /**
153
+ * An array of URLs to prerender to HTML files at build time.
154
+ */
155
+ prerender: Array<string> | null;
147
156
  /**
148
157
  * Derived from Vite's `base` config
149
158
  * */
@@ -207,6 +216,10 @@ export declare function resolveReactRouterConfig({ rootDirectory, reactRouterUse
207
216
  * Defaults to `false`.
208
217
  */
209
218
  manifest: boolean;
219
+ /**
220
+ * An array of URLs to prerender to HTML files at build time.
221
+ */
222
+ prerender: string[] | null;
210
223
  /**
211
224
  * Derived from Vite's `base` config
212
225
  * */
@@ -244,6 +257,7 @@ export declare function resolveEntryFiles({ rootDirectory, reactRouterConfig, }:
244
257
  reactRouterConfig: ResolvedVitePluginConfig;
245
258
  }): Promise<{
246
259
  entryClientFilePath: string;
260
+ entryReactServerFilePath: string | undefined;
247
261
  entryServerFilePath: string;
248
262
  }>;
249
263
  export {};
package/dist/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -124,6 +124,7 @@ async function resolveReactRouterConfig({
124
124
  ignoredRouteFiles,
125
125
  manifest,
126
126
  routes: userRoutesFunction,
127
+ prerender: prerenderConfig,
127
128
  serverBuildFile,
128
129
  serverBundles,
129
130
  serverModuleFormat,
@@ -133,12 +134,21 @@ async function resolveReactRouterConfig({
133
134
  // Default values should be completely overridden by user/preset config, not merged
134
135
  ...mergeReactRouterConfig(...presets, reactRouterUserConfig)
135
136
  };
136
- let isSpaMode = !ssr;
137
137
  // Log warning for incompatible vite config flags
138
- if (isSpaMode && serverBundles) {
138
+ if (!ssr && serverBundles) {
139
139
  console.warn(colors__default["default"].yellow(colors__default["default"].bold("⚠️ SPA Mode: ") + "the `serverBundles` config is invalid with " + "`ssr:false` and will be ignored`"));
140
140
  serverBundles = undefined;
141
141
  }
142
+ let prerender = null;
143
+ if (prerenderConfig) {
144
+ if (Array.isArray(prerenderConfig)) {
145
+ prerender = prerenderConfig;
146
+ } else if (typeof prerenderConfig === "function") {
147
+ prerender = await prerenderConfig();
148
+ } else {
149
+ throw new Error("The `prerender` config must be an array of string paths, or a function " + "returning an array of string paths");
150
+ }
151
+ }
142
152
  let appDirectory = path__default["default"].resolve(rootDirectory, userAppDirectory || "app");
143
153
  let buildDirectory = path__default["default"].resolve(rootDirectory, userBuildDirectory);
144
154
  let publicPath = viteUserConfig.base ?? "/";
@@ -178,7 +188,7 @@ async function resolveReactRouterConfig({
178
188
  v3_fetcherPersist: (userFuture === null || userFuture === void 0 ? void 0 : userFuture.v3_fetcherPersist) === true,
179
189
  v3_relativeSplatPath: (userFuture === null || userFuture === void 0 ? void 0 : userFuture.v3_relativeSplatPath) === true,
180
190
  v3_throwAbortReason: (userFuture === null || userFuture === void 0 ? void 0 : userFuture.v3_throwAbortReason) === true,
181
- unstable_singleFetch: (userFuture === null || userFuture === void 0 ? void 0 : userFuture.unstable_singleFetch) === true
191
+ unstable_serverComponents: (userFuture === null || userFuture === void 0 ? void 0 : userFuture.unstable_serverComponents) === true
182
192
  };
183
193
  let reactRouterConfig = deepFreeze({
184
194
  appDirectory,
@@ -187,6 +197,7 @@ async function resolveReactRouterConfig({
187
197
  buildEnd,
188
198
  future,
189
199
  manifest,
200
+ prerender,
190
201
  publicPath,
191
202
  routes: routes$1,
192
203
  serverBuildFile,
@@ -210,15 +221,17 @@ async function resolveEntryFiles({
210
221
  appDirectory,
211
222
  future
212
223
  } = reactRouterConfig;
213
- let isSpaMode = !reactRouterConfig.ssr;
214
224
  let defaultsDirectory = path__default["default"].resolve(__dirname, "config", "defaults");
215
225
  let userEntryClientFile = findEntry(appDirectory, "entry.client");
216
226
  let userEntryServerFile = findEntry(appDirectory, "entry.server");
227
+ let userEntryReactServerFile = findEntry(appDirectory, "entry.react-server");
217
228
  let entryServerFile;
218
- let entryClientFile = userEntryClientFile || "entry.client.tsx";
229
+ let entryReactServerFile;
230
+ let entryClientFile = userEntryClientFile || future.unstable_serverComponents ? "entry.client.rsc.tsx" : "entry.client.tsx";
219
231
  let pkgJson = await PackageJson__default["default"].load(rootDirectory);
220
232
  let deps = pkgJson.content.dependencies ?? {};
221
- if (isSpaMode && (future === null || future === void 0 ? void 0 : future.unstable_singleFetch) != true) {
233
+ let serverRuntime = deps["@react-router/deno"] ? "deno" : deps["@react-router/cloudflare"] ? "cloudflare" : deps["@react-router/node"] ? "node" : undefined;
234
+ if (!reactRouterConfig.ssr) {
222
235
  // This is a super-simple default since we don't need streaming in SPA Mode.
223
236
  // We can include this in a remix-spa template, but right now `npx remix reveal`
224
237
  // will still expose the streaming template since that command doesn't have
@@ -231,7 +244,6 @@ async function resolveEntryFiles({
231
244
  } else if (userEntryServerFile) {
232
245
  entryServerFile = userEntryServerFile;
233
246
  } else {
234
- let serverRuntime = deps["@react-router/deno"] ? "deno" : deps["@react-router/cloudflare"] ? "cloudflare" : deps["@react-router/node"] ? "node" : undefined;
235
247
  if (!serverRuntime) {
236
248
  let serverRuntimes = ["@react-router/deno", "@react-router/cloudflare", "@react-router/node"];
237
249
  let formattedList = disjunctionListFormat.format(serverRuntimes);
@@ -252,12 +264,26 @@ async function resolveEntryFiles({
252
264
  stdio: "inherit"
253
265
  });
254
266
  }
255
- entryServerFile = `entry.server.${serverRuntime}.tsx`;
267
+ entryServerFile = reactRouterConfig.future.unstable_serverComponents ? `entry.server.${serverRuntime}.rsc.tsx` : `entry.server.${serverRuntime}.tsx`;
268
+ }
269
+ if (future.unstable_serverComponents) {
270
+ if (userEntryReactServerFile) {
271
+ entryReactServerFile = userEntryReactServerFile;
272
+ } else {
273
+ if (!serverRuntime) {
274
+ let serverRuntimes = ["@react-router/deno", "@react-router/cloudflare", "@react-router/node"];
275
+ let formattedList = disjunctionListFormat.format(serverRuntimes);
276
+ throw new Error(`Could not determine server runtime. Please install one of the following: ${formattedList}`);
277
+ }
278
+ entryReactServerFile = `entry.react-server.${serverRuntime === "node" ? serverRuntime : "web"}.tsx`;
279
+ }
256
280
  }
257
281
  let entryClientFilePath = userEntryClientFile ? path__default["default"].resolve(reactRouterConfig.appDirectory, userEntryClientFile) : path__default["default"].resolve(defaultsDirectory, entryClientFile);
258
282
  let entryServerFilePath = userEntryServerFile ? path__default["default"].resolve(reactRouterConfig.appDirectory, userEntryServerFile) : path__default["default"].resolve(defaultsDirectory, entryServerFile);
283
+ let entryReactServerFilePath = userEntryReactServerFile ? path__default["default"].resolve(reactRouterConfig.appDirectory, userEntryReactServerFile) : entryReactServerFile ? path__default["default"].resolve(defaultsDirectory, entryReactServerFile) : undefined;
259
284
  return {
260
285
  entryClientFilePath,
286
+ entryReactServerFilePath,
261
287
  entryServerFilePath
262
288
  };
263
289
  }
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
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-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -0,0 +1 @@
1
+ export declare function createServerReference(_: unknown, mod: string, name: string): void;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
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
+ function createServerReference(_, mod, name) {
16
+ throw new Error("Server references are not yet implemented.");
17
+ }
18
+
19
+ exports.createServerReference = createServerReference;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-fbbd4fd81
2
+ * @react-router/dev v0.0.0-experimental-27337b0d6
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *