vite-plugin-react-server 1.1.4 → 1.1.6
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/dist/package.json +1 -1
- package/dist/plugin/config/autoDiscover/resolveBuildPages.d.ts +1 -1
- package/dist/plugin/config/autoDiscover/resolveBuildPages.d.ts.map +1 -1
- package/dist/plugin/config/autoDiscover/resolveBuildPages.js.map +1 -1
- package/dist/plugin/config/defaults.d.ts +1 -1
- package/dist/plugin/config/defaults.d.ts.map +1 -1
- package/dist/plugin/config/resolveUrlOption.d.ts +2 -2
- package/dist/plugin/config/resolveUrlOption.d.ts.map +1 -1
- package/dist/plugin/config/resolveUrlOption.js +4 -1
- package/dist/plugin/config/resolveUrlOption.js.map +1 -1
- package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
- package/dist/plugin/config/resolveUserConfig.js +10 -0
- package/dist/plugin/config/resolveUserConfig.js.map +1 -1
- package/dist/plugin/helpers/createRscStream.js +2 -1
- package/dist/plugin/helpers/createRscStream.js.map +1 -1
- package/dist/plugin/helpers/requestToRoute.d.ts +5 -0
- package/dist/plugin/helpers/requestToRoute.d.ts.map +1 -0
- package/dist/plugin/helpers/requestToRoute.js +24 -0
- package/dist/plugin/helpers/requestToRoute.js.map +1 -0
- package/dist/plugin/html.d.ts +1 -1
- package/dist/plugin/html.d.ts.map +1 -1
- package/dist/plugin/html.js +3 -2
- package/dist/plugin/html.js.map +1 -1
- package/dist/plugin/react-client/plugin.d.ts.map +1 -1
- package/dist/plugin/react-client/plugin.js.map +1 -1
- package/dist/plugin/react-client/server.d.ts +1 -1
- package/dist/plugin/react-client/server.d.ts.map +1 -1
- package/dist/plugin/react-client/server.js +51 -39
- package/dist/plugin/react-client/server.js.map +1 -1
- package/dist/plugin/react-server/server.d.ts +1 -1
- package/dist/plugin/react-server/server.d.ts.map +1 -1
- package/dist/plugin/react-server/server.js +36 -22
- package/dist/plugin/react-server/server.js.map +1 -1
- package/dist/plugin/react-static/plugin.d.ts.map +1 -1
- package/dist/plugin/react-static/plugin.js +24 -10
- package/dist/plugin/react-static/plugin.js.map +1 -1
- package/dist/plugin/react-static/renderPage.d.ts.map +1 -1
- package/dist/plugin/react-static/renderPage.js.map +1 -1
- package/dist/plugin/transformer/plugin.client.d.ts.map +1 -1
- package/dist/plugin/transformer/plugin.client.js +13 -3
- package/dist/plugin/transformer/plugin.client.js.map +1 -1
- package/dist/plugin/transformer/plugin.server.d.ts.map +1 -1
- package/dist/plugin/transformer/plugin.server.js +13 -3
- package/dist/plugin/transformer/plugin.server.js.map +1 -1
- package/dist/plugin/worker/createWorker.d.ts +1 -0
- package/dist/plugin/worker/createWorker.d.ts.map +1 -1
- package/dist/plugin/worker/createWorker.js +9 -16
- package/dist/plugin/worker/createWorker.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/plugin/config/autoDiscover/resolveBuildPages.ts +1 -1
- package/plugin/config/resolveUrlOption.ts +19 -10
- package/plugin/config/resolveUserConfig.ts +18 -0
- package/plugin/helpers/createRscStream.tsx +2 -2
- package/plugin/helpers/requestToRoute.ts +23 -0
- package/plugin/html.tsx +2 -0
- package/plugin/react-client/plugin.ts +1 -0
- package/plugin/react-client/server.ts +62 -40
- package/plugin/react-server/server.ts +50 -25
- package/plugin/react-static/plugin.ts +30 -13
- package/plugin/react-static/renderPage.ts +0 -1
- package/plugin/transformer/plugin.client.ts +13 -3
- package/plugin/transformer/plugin.server.ts +14 -4
- package/plugin/worker/createWorker.ts +19 -21
|
@@ -1,29 +1,38 @@
|
|
|
1
|
-
import type { ResolvedUserOptions } from
|
|
1
|
+
import type { ResolvedUserOptions } from "../types.js";
|
|
2
2
|
|
|
3
3
|
type ResolvePageAndPropsOptionsSuccess<T extends "Page" | "props"> = {
|
|
4
4
|
[optionName in T]: string;
|
|
5
|
-
} & {type: "success"; error?:never}
|
|
5
|
+
} & { type: "success"; error?: never };
|
|
6
6
|
|
|
7
7
|
type ResolvePageAndPropsOptionsError<T extends "Page" | "props"> = {
|
|
8
8
|
[optionName in T]?: never;
|
|
9
|
-
} & { type: "error"; error: Error }
|
|
9
|
+
} & { type: "error"; error: Error };
|
|
10
10
|
|
|
11
11
|
export async function resolveUrlOption<T extends "Page" | "props">(
|
|
12
|
-
options: Pick<ResolvedUserOptions, T>,
|
|
12
|
+
options: Pick<ResolvedUserOptions, T | "moduleBasePath">,
|
|
13
13
|
optionName: T,
|
|
14
14
|
url: string
|
|
15
|
-
): Promise<
|
|
15
|
+
): Promise<
|
|
16
|
+
ResolvePageAndPropsOptionsSuccess<T> | ResolvePageAndPropsOptionsError<T>
|
|
17
|
+
> {
|
|
16
18
|
try {
|
|
17
19
|
switch (typeof options[optionName]) {
|
|
18
20
|
case "function":
|
|
19
|
-
const result = options[optionName](
|
|
20
|
-
|
|
21
|
+
const result = options[optionName](
|
|
22
|
+
// quick normalization to make it easier to work with dynamic moduleBasePaths (so that you don't have to change the Page/props function)
|
|
23
|
+
options.moduleBasePath !== "" &&
|
|
24
|
+
options.moduleBasePath !== "/" &&
|
|
25
|
+
url.startsWith(options.moduleBasePath)
|
|
26
|
+
? url.slice(options.moduleBasePath.length)
|
|
27
|
+
: url
|
|
28
|
+
);
|
|
29
|
+
if (typeof result === "string") {
|
|
21
30
|
return { type: "success", [optionName]: result };
|
|
22
31
|
}
|
|
23
|
-
if(result instanceof Promise) {
|
|
32
|
+
if (result instanceof Promise) {
|
|
24
33
|
try {
|
|
25
34
|
const promiseResult = await result;
|
|
26
|
-
if(typeof promiseResult === "string") {
|
|
35
|
+
if (typeof promiseResult === "string") {
|
|
27
36
|
return { type: "success", [optionName]: promiseResult };
|
|
28
37
|
}
|
|
29
38
|
} catch (error) {
|
|
@@ -40,4 +49,4 @@ export async function resolveUrlOption<T extends "Page" | "props">(
|
|
|
40
49
|
} catch (error) {
|
|
41
50
|
return { type: "error", error: error as Error };
|
|
42
51
|
}
|
|
43
|
-
}
|
|
52
|
+
}
|
|
@@ -101,6 +101,7 @@ export function resolveUserConfig({
|
|
|
101
101
|
...config,
|
|
102
102
|
root: root,
|
|
103
103
|
mode: mode,
|
|
104
|
+
base: userOptions.moduleBasePath,
|
|
104
105
|
resolve: {
|
|
105
106
|
...config.resolve,
|
|
106
107
|
external: config.resolve?.external ?? [
|
|
@@ -160,15 +161,32 @@ export function resolveUserConfig({
|
|
|
160
161
|
...config,
|
|
161
162
|
root: root,
|
|
162
163
|
mode: mode,
|
|
164
|
+
base: userOptions.moduleBasePath,
|
|
163
165
|
resolve: {
|
|
164
166
|
...config.resolve,
|
|
165
167
|
externalConditions: config.resolve?.externalConditions ?? [
|
|
166
168
|
"react-server",
|
|
167
169
|
],
|
|
168
170
|
},
|
|
171
|
+
define: {
|
|
172
|
+
...config.define,
|
|
173
|
+
"process.env.VITE_SSR": `"1"`,
|
|
174
|
+
"process.env.VITE_DEV": `"${mode === "development" ? "1" : "0"}"`,
|
|
175
|
+
"process.env.VITE_PROD": `"${mode === "production" ? "1" : "0"}"`,
|
|
176
|
+
"process.env.VITE_MODE": `"${mode}"`,
|
|
177
|
+
"process.env.VITE_BASE": `"${
|
|
178
|
+
userOptions.moduleBasePath === "" ||
|
|
179
|
+
userOptions.moduleBasePath === "/"
|
|
180
|
+
? "/"
|
|
181
|
+
: !userOptions.moduleBasePath.endsWith("/")
|
|
182
|
+
? userOptions.moduleBasePath + "/"
|
|
183
|
+
: userOptions.moduleBasePath
|
|
184
|
+
}"`,
|
|
185
|
+
},
|
|
169
186
|
ssr: {
|
|
170
187
|
...config.ssr,
|
|
171
188
|
target: config.ssr?.target ?? "node",
|
|
189
|
+
|
|
172
190
|
resolve: {
|
|
173
191
|
...config.ssr?.resolve,
|
|
174
192
|
externalConditions: config.ssr?.resolve?.externalConditions ?? [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { React, ReactDOMServer } from "../vendor.server.js";
|
|
2
2
|
import type { CreateHandlerOptions, StreamMetrics } from "../types.js";
|
|
3
|
-
|
|
3
|
+
import { join } from "node:path";
|
|
4
4
|
export function createRscStream<
|
|
5
5
|
T,
|
|
6
6
|
C extends React.ComponentType<T>,
|
|
@@ -45,7 +45,7 @@ export function createRscStream<
|
|
|
45
45
|
const startTime = performance.now()
|
|
46
46
|
const htmlIsFragment = Html == React.Fragment;
|
|
47
47
|
const url =
|
|
48
|
-
moduleBaseURL !== "" ? new URL(route, moduleBaseURL).toString() : route;
|
|
48
|
+
moduleBaseURL !== "" ? new URL(join(route, moduleBasePath), moduleBaseURL).toString() : route;
|
|
49
49
|
let errorCount = 0;
|
|
50
50
|
let streamError: Error | null = null;
|
|
51
51
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CreateHandlerOptions } from "../types.js";
|
|
2
|
+
|
|
3
|
+
export function requestToRoute(
|
|
4
|
+
req: {url?: string},
|
|
5
|
+
handlerOptions: Pick<CreateHandlerOptions, "moduleBasePath" | "build">
|
|
6
|
+
) {
|
|
7
|
+
let route = req.url?.replace("/" + handlerOptions.build.rscOutputPath, "");
|
|
8
|
+
if (typeof route !== "string") {
|
|
9
|
+
return route;
|
|
10
|
+
}
|
|
11
|
+
if (
|
|
12
|
+
route.startsWith(handlerOptions.moduleBasePath)
|
|
13
|
+
) {
|
|
14
|
+
route = route.slice(handlerOptions.moduleBasePath.length);
|
|
15
|
+
}
|
|
16
|
+
if (!route || route === "") {
|
|
17
|
+
route = "/";
|
|
18
|
+
}
|
|
19
|
+
if (!route.startsWith("/")) {
|
|
20
|
+
route = "/" + route;
|
|
21
|
+
}
|
|
22
|
+
return route;
|
|
23
|
+
}
|
package/plugin/html.tsx
CHANGED
|
@@ -6,9 +6,11 @@ export const Html = ({
|
|
|
6
6
|
CssCollector,
|
|
7
7
|
cssFiles,
|
|
8
8
|
globalCss,
|
|
9
|
+
moduleBasePath,
|
|
9
10
|
}: React.PropsWithChildren<HtmlProps>) => (
|
|
10
11
|
<html>
|
|
11
12
|
<head>
|
|
13
|
+
{moduleBasePath !== "" && <base href={moduleBasePath} />}
|
|
12
14
|
<CssCollectorElements cssFiles={globalCss} />
|
|
13
15
|
</head>
|
|
14
16
|
<body>
|
|
@@ -8,7 +8,6 @@ import type {
|
|
|
8
8
|
RscWorkerOutputMessage,
|
|
9
9
|
RscRenderMessage,
|
|
10
10
|
} from "../worker/types.js";
|
|
11
|
-
import { join } from "node:path";
|
|
12
11
|
import type { Worker as NodeWorker } from "node:worker_threads";
|
|
13
12
|
import { MessageChannel } from "node:worker_threads";
|
|
14
13
|
import {
|
|
@@ -17,6 +16,7 @@ import {
|
|
|
17
16
|
} from "../helpers/serializeUserOptions.js";
|
|
18
17
|
import { createWorker } from "../worker/createWorker.js";
|
|
19
18
|
import { getRouteFiles } from "../helpers/getRouteFiles.js";
|
|
19
|
+
import { requestToRoute } from "../helpers/requestToRoute.js";
|
|
20
20
|
|
|
21
21
|
let currentWorker: NodeWorker | null = null;
|
|
22
22
|
let isRestarting = false;
|
|
@@ -169,7 +169,7 @@ export function handleWorkerRscStream(
|
|
|
169
169
|
export async function configureWorkerRequestHandler({
|
|
170
170
|
server,
|
|
171
171
|
autoDiscoveredFiles,
|
|
172
|
-
userOptions,
|
|
172
|
+
userOptions: _userOptions,
|
|
173
173
|
hmrChannel,
|
|
174
174
|
}: {
|
|
175
175
|
server: ViteDevServer;
|
|
@@ -177,15 +177,30 @@ export async function configureWorkerRequestHandler({
|
|
|
177
177
|
userOptions: ResolvedUserOptions;
|
|
178
178
|
hmrChannel: MessageChannel;
|
|
179
179
|
}) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
180
|
+
let {
|
|
181
|
+
// remove these
|
|
182
|
+
moduleBaseURL: _moduleBaseURL,
|
|
183
|
+
projectRoot: _projectRoot,
|
|
184
|
+
...handlerUserOptions
|
|
185
|
+
} = _userOptions;
|
|
186
|
+
const handlerOptions = Object.assign({}, handlerUserOptions, {
|
|
187
|
+
moduleBaseURL:
|
|
188
|
+
typeof server.config.server.host === "string"
|
|
189
|
+
? `${server.config.server.https ? "https" : "http"}://${
|
|
190
|
+
server.config.server.host
|
|
191
|
+
}:${server.config.server.port}`
|
|
192
|
+
: "",
|
|
193
|
+
moduleBasePath:
|
|
194
|
+
server.config.base === "/"
|
|
195
|
+
? ""
|
|
196
|
+
: server.config.base.endsWith("/")
|
|
197
|
+
? server.config.base.slice(0, -1)
|
|
198
|
+
: server.config.base,
|
|
199
|
+
projectRoot: server.config.root,
|
|
200
|
+
});
|
|
186
201
|
|
|
187
202
|
// Start the worker
|
|
188
|
-
await restartWorker(server, autoDiscoveredFiles,
|
|
203
|
+
await restartWorker(server, autoDiscoveredFiles, handlerOptions, hmrChannel);
|
|
189
204
|
|
|
190
205
|
// Create the request handler
|
|
191
206
|
const handler: RequestHandler = async (req, res, next) => {
|
|
@@ -197,18 +212,24 @@ export async function configureWorkerRequestHandler({
|
|
|
197
212
|
}
|
|
198
213
|
|
|
199
214
|
// Get the route from the request
|
|
200
|
-
let route = req
|
|
201
|
-
|
|
215
|
+
let route = requestToRoute(req, {
|
|
216
|
+
moduleBasePath: handlerOptions.moduleBasePath,
|
|
217
|
+
build: handlerOptions.build
|
|
218
|
+
});
|
|
219
|
+
if (!route) {
|
|
220
|
+
return next();
|
|
221
|
+
}
|
|
202
222
|
// in the case of the no build.pages and a async Page and or props userOption, we need to await those
|
|
203
223
|
// if they are already autoDiscovered then the promise will resolve immediately
|
|
204
224
|
const routeFiles = await getRouteFiles(
|
|
205
225
|
route,
|
|
206
226
|
autoDiscoveredFiles,
|
|
207
|
-
|
|
227
|
+
handlerOptions
|
|
208
228
|
);
|
|
209
229
|
if (routeFiles.type === "error") {
|
|
210
|
-
server.config.logger.error(
|
|
230
|
+
server.config.logger.error(routeFiles.error.message, {
|
|
211
231
|
error: routeFiles.error,
|
|
232
|
+
timestamp: true,
|
|
212
233
|
});
|
|
213
234
|
return next();
|
|
214
235
|
}
|
|
@@ -218,12 +239,8 @@ export async function configureWorkerRequestHandler({
|
|
|
218
239
|
res.setHeader("Content-Type", "text/x-component; charset=utf-8");
|
|
219
240
|
res.setHeader("Transfer-Encoding", "chunked");
|
|
220
241
|
res.setHeader("Connection", "keep-alive");
|
|
221
|
-
let timeout = setTimeout(() => {
|
|
222
|
-
server.config.logger.error("[react-client] RSC render timeout");
|
|
223
|
-
res.end();
|
|
224
|
-
}, 5000);
|
|
225
242
|
const serializedUserOptions = serializedOptions(
|
|
226
|
-
|
|
243
|
+
handlerOptions,
|
|
227
244
|
autoDiscoveredFiles
|
|
228
245
|
);
|
|
229
246
|
const stream = handleWorkerRscStream(currentWorker, {
|
|
@@ -234,37 +251,42 @@ export async function configureWorkerRequestHandler({
|
|
|
234
251
|
propsPath: props,
|
|
235
252
|
// override these at all times to ensure the settings will work for the dev server
|
|
236
253
|
projectRoot: server.config.root,
|
|
237
|
-
moduleRootPath: join(server.config.root, userOptions.moduleBase),
|
|
238
|
-
moduleBaseURL: "",
|
|
239
|
-
moduleBasePath: "",
|
|
240
254
|
build: serializedUserOptions.build,
|
|
241
255
|
manifest: autoDiscoveredFiles.staticManifest,
|
|
242
256
|
cssFiles: new Map(),
|
|
243
257
|
globalCss: new Map(),
|
|
244
258
|
});
|
|
259
|
+
const writeStream = new WritableStream({
|
|
260
|
+
write(chunk) {
|
|
261
|
+
res.write(chunk);
|
|
262
|
+
},
|
|
245
263
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
264
|
+
close() {
|
|
265
|
+
clearTimeout(timeout);
|
|
266
|
+
res.end();
|
|
267
|
+
},
|
|
268
|
+
abort() {
|
|
269
|
+
clearTimeout(timeout);
|
|
270
|
+
// Restart worker on error
|
|
271
|
+
restartWorker(
|
|
272
|
+
server,
|
|
273
|
+
autoDiscoveredFiles,
|
|
274
|
+
handlerOptions,
|
|
275
|
+
hmrChannel
|
|
276
|
+
);
|
|
277
|
+
res.end();
|
|
278
|
+
},
|
|
279
|
+
})
|
|
280
|
+
let timeout = setTimeout(() => {
|
|
281
|
+
server.config.logger.error("[react-client] RSC render timeout");
|
|
282
|
+
res.end();
|
|
283
|
+
}, 5000);
|
|
252
284
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
res.end();
|
|
256
|
-
},
|
|
257
|
-
abort() {
|
|
258
|
-
clearTimeout(timeout);
|
|
259
|
-
// Restart worker on error
|
|
260
|
-
restartWorker(server, autoDiscoveredFiles, userOptions, hmrChannel);
|
|
261
|
-
res.end();
|
|
262
|
-
},
|
|
263
|
-
})
|
|
264
|
-
);
|
|
285
|
+
// Pipe the stream to the response
|
|
286
|
+
stream.pipeTo(writeStream);
|
|
265
287
|
} catch (error) {
|
|
266
288
|
if (error instanceof Error) {
|
|
267
|
-
server.config.logger.error(
|
|
289
|
+
server.config.logger.error(error.message, {
|
|
268
290
|
error,
|
|
269
291
|
});
|
|
270
292
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Manifest, ViteDevServer } from "vite";
|
|
2
2
|
import type { ServerResponse } from "http";
|
|
3
3
|
import type { AutoDiscoveredFiles, ResolvedUserOptions } from "../types.js";
|
|
4
4
|
import { createEventHandler } from "../helpers/createEventHandler.js";
|
|
@@ -10,7 +10,7 @@ import React from "react";
|
|
|
10
10
|
export async function configureReactServer({
|
|
11
11
|
server,
|
|
12
12
|
autoDiscoveredFiles,
|
|
13
|
-
userOptions,
|
|
13
|
+
userOptions: _userOptions,
|
|
14
14
|
serverManifest,
|
|
15
15
|
}: {
|
|
16
16
|
server: ViteDevServer;
|
|
@@ -20,6 +20,31 @@ export async function configureReactServer({
|
|
|
20
20
|
}) {
|
|
21
21
|
const activeStreams = new Set<ServerResponse>();
|
|
22
22
|
|
|
23
|
+
const {
|
|
24
|
+
Html: _UserHtmlComponent,
|
|
25
|
+
onEvent,
|
|
26
|
+
// remove these
|
|
27
|
+
moduleBaseURL: _moduleBaseURL,
|
|
28
|
+
moduleBasePath: _moduleBasePath,
|
|
29
|
+
projectRoot: _projectRoot,
|
|
30
|
+
...handlerUserOptions
|
|
31
|
+
} = _userOptions;
|
|
32
|
+
|
|
33
|
+
const handlerOptions = Object.assign({}, handlerUserOptions, {
|
|
34
|
+
moduleBaseURL:
|
|
35
|
+
typeof server.config.server.host === "string"
|
|
36
|
+
? `${server.config.server.https ? "https" : "http"}://${
|
|
37
|
+
server.config.server.host
|
|
38
|
+
}:${server.config.server.port}`
|
|
39
|
+
: "",
|
|
40
|
+
moduleBasePath:
|
|
41
|
+
server.config.base === "/"
|
|
42
|
+
? ""
|
|
43
|
+
: server.config.base.endsWith("/")
|
|
44
|
+
? server.config.base.slice(0, -1)
|
|
45
|
+
: server.config.base,
|
|
46
|
+
projectRoot: server.config.root,
|
|
47
|
+
});
|
|
23
48
|
// Handle Vite server restarts
|
|
24
49
|
server.ws.on("restart", (path) => {
|
|
25
50
|
console.log(
|
|
@@ -41,10 +66,21 @@ export async function configureReactServer({
|
|
|
41
66
|
server.middlewares.use(async (req, res, next) => {
|
|
42
67
|
try {
|
|
43
68
|
if (req.headers.accept !== "text/x-component") return next();
|
|
44
|
-
let route = req.url?.replace(
|
|
69
|
+
let route = req.url?.replace("/" + handlerOptions.build.rscOutputPath, "");
|
|
70
|
+
if(!route?.startsWith(handlerOptions.moduleBasePath)) {
|
|
71
|
+
next();
|
|
72
|
+
} else {
|
|
73
|
+
route = route.slice(handlerOptions.moduleBasePath.length);
|
|
74
|
+
}
|
|
75
|
+
if(typeof route !== "string" ) {
|
|
76
|
+
throw new Error("req.url is not a string");
|
|
77
|
+
}
|
|
45
78
|
if (!route || route === "") {
|
|
46
79
|
route = "/";
|
|
47
80
|
}
|
|
81
|
+
if(!route.startsWith("/")) {
|
|
82
|
+
route = "/" + route;
|
|
83
|
+
}
|
|
48
84
|
if (!autoDiscoveredFiles.urlMap.has(route)) {
|
|
49
85
|
return next();
|
|
50
86
|
}
|
|
@@ -52,27 +88,19 @@ export async function configureReactServer({
|
|
|
52
88
|
const pagePath = routeFiles.page;
|
|
53
89
|
const propsPath = routeFiles.props;
|
|
54
90
|
|
|
55
|
-
const {
|
|
56
|
-
Html: _UserHtmlComponent,
|
|
57
|
-
onEvent,
|
|
58
|
-
// remove these
|
|
59
|
-
moduleBaseURL,
|
|
60
|
-
...handlerUserOptions
|
|
61
|
-
} = userOptions;
|
|
62
91
|
// Create a unified event handler
|
|
63
92
|
await server.warmupRequest(pagePath);
|
|
64
93
|
const eventHandler = createEventHandler(onEvent);
|
|
65
|
-
const moduleBasePathForDevServer = "/" + userOptions.moduleBase;
|
|
66
94
|
const cssFilesResult = await collectViteModuleGraphCss({
|
|
67
95
|
moduleGraph: server.moduleGraph,
|
|
68
96
|
pagePath,
|
|
69
|
-
loader: (i)=>server.ssrLoadModule(i, {fixStacktrace: true}),
|
|
70
|
-
// explicitly set
|
|
71
|
-
moduleBaseURL:
|
|
72
|
-
moduleBasePath:
|
|
73
|
-
moduleRootPath:
|
|
74
|
-
projectRoot:
|
|
75
|
-
css:
|
|
97
|
+
loader: (i) => server.ssrLoadModule(i, { fixStacktrace: true }),
|
|
98
|
+
// explicitly set for development server
|
|
99
|
+
moduleBaseURL: handlerOptions.moduleBaseURL,
|
|
100
|
+
moduleBasePath: handlerOptions.moduleBasePath,
|
|
101
|
+
moduleRootPath: handlerOptions.moduleRootPath,
|
|
102
|
+
projectRoot: handlerOptions.projectRoot,
|
|
103
|
+
css: handlerOptions.css,
|
|
76
104
|
parentUrl: pagePath,
|
|
77
105
|
});
|
|
78
106
|
if (cssFilesResult.type === "skip") {
|
|
@@ -86,8 +114,8 @@ export async function configureReactServer({
|
|
|
86
114
|
propsPath,
|
|
87
115
|
route,
|
|
88
116
|
loader: server.ssrLoadModule,
|
|
89
|
-
pageExportName:
|
|
90
|
-
propsExportName:
|
|
117
|
+
pageExportName: handlerOptions.pageExportName ?? "default",
|
|
118
|
+
propsExportName: handlerOptions.propsExportName ?? "default",
|
|
91
119
|
});
|
|
92
120
|
if (pageAndPropsResult.type === "error") {
|
|
93
121
|
throw pageAndPropsResult.error;
|
|
@@ -96,9 +124,9 @@ export async function configureReactServer({
|
|
|
96
124
|
return next();
|
|
97
125
|
}
|
|
98
126
|
const { PageComponent, pageProps } = pageAndPropsResult;
|
|
99
|
-
// Create the headless RSC stream directly
|
|
127
|
+
// Create the headless RSC stream directly;
|
|
100
128
|
const rscResult = await createHandler({
|
|
101
|
-
...
|
|
129
|
+
...handlerOptions,
|
|
102
130
|
PageComponent: PageComponent,
|
|
103
131
|
pageProps: pageProps,
|
|
104
132
|
logger: server.config.logger,
|
|
@@ -111,9 +139,6 @@ export async function configureReactServer({
|
|
|
111
139
|
pagePath,
|
|
112
140
|
propsPath,
|
|
113
141
|
cssFiles: cssFilesResult.cssFiles ?? new Map(),
|
|
114
|
-
// explicitly set to empty string, because we let vite handle the resolving during development
|
|
115
|
-
moduleBaseURL: "",
|
|
116
|
-
moduleBasePath: "",
|
|
117
142
|
globalCss: new Map(),
|
|
118
143
|
});
|
|
119
144
|
if (rscResult.type === "success") {
|
|
@@ -138,6 +138,7 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
138
138
|
timing.renderStart = Date.now();
|
|
139
139
|
},
|
|
140
140
|
|
|
141
|
+
|
|
141
142
|
async writeBundle(options, bundle) {
|
|
142
143
|
try {
|
|
143
144
|
const bundleManifest = getBundleManifest<false>({
|
|
@@ -158,7 +159,10 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
158
159
|
|
|
159
160
|
const clientManifestResult = await tryManifest({
|
|
160
161
|
root: userOptions.projectRoot,
|
|
161
|
-
outDir: join(
|
|
162
|
+
outDir: join(
|
|
163
|
+
userOptions.build.outDir,
|
|
164
|
+
userOptions.build.client
|
|
165
|
+
),
|
|
162
166
|
ssrManifest: false,
|
|
163
167
|
});
|
|
164
168
|
if (clientManifestResult.type === "error") {
|
|
@@ -268,7 +272,16 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
268
272
|
const pipeableStreamOptions = {
|
|
269
273
|
...userOptions.pipeableStreamOptions,
|
|
270
274
|
bootstrapModules: [
|
|
271
|
-
...(indexHtml
|
|
275
|
+
...(indexHtml
|
|
276
|
+
? [
|
|
277
|
+
userOptions.moduleBaseURL !== ""
|
|
278
|
+
? new URL(
|
|
279
|
+
join(userOptions.moduleBasePath, indexHtml),
|
|
280
|
+
userOptions.moduleBaseURL
|
|
281
|
+
).href
|
|
282
|
+
: join(userOptions.moduleBasePath, indexHtml),
|
|
283
|
+
]
|
|
284
|
+
: []),
|
|
272
285
|
...(userOptions.pipeableStreamOptions?.bootstrapModules ?? []),
|
|
273
286
|
],
|
|
274
287
|
};
|
|
@@ -279,34 +292,37 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
279
292
|
);
|
|
280
293
|
// Create worker
|
|
281
294
|
if (!worker) {
|
|
295
|
+
const viteEnvPrefix = typeof resolvedConfig.envPrefix === 'string' ? resolvedConfig.envPrefix : Array.isArray(resolvedConfig.envPrefix) ? resolvedConfig.envPrefix[0] : 'VITE_'
|
|
282
296
|
const workerResult = await createWorker({
|
|
283
297
|
projectRoot: userOptions.projectRoot,
|
|
284
298
|
workerPath: userOptions.htmlWorkerPath,
|
|
285
299
|
currentCondition: "react-server",
|
|
286
300
|
reverseCondition: "react-client",
|
|
301
|
+
envPrefix: viteEnvPrefix,
|
|
287
302
|
workerData: {
|
|
288
303
|
resolvedConfig: serializeResolvedConfig(resolvedConfig),
|
|
289
304
|
userOptions: {
|
|
290
305
|
...serializedUserOptions,
|
|
291
|
-
moduleBasePath: '',
|
|
292
306
|
},
|
|
293
307
|
},
|
|
294
308
|
});
|
|
295
309
|
if (workerResult.type === "error") {
|
|
296
310
|
throw workerResult.error;
|
|
297
311
|
} else if (workerResult.type === "skip") {
|
|
298
|
-
this.environment.logger.info(
|
|
312
|
+
this.environment.logger.info(
|
|
313
|
+
"Worker not created, skipping static build"
|
|
314
|
+
);
|
|
299
315
|
return;
|
|
300
316
|
} else {
|
|
301
317
|
worker = workerResult.worker;
|
|
302
318
|
}
|
|
303
319
|
}
|
|
304
320
|
// Render pages
|
|
305
|
-
const { onEvent, ...
|
|
321
|
+
const { onEvent, ...handlerOptions } = userOptions;
|
|
306
322
|
const renderPagesGenerator = renderPages(
|
|
307
323
|
autoDiscoveredFiles!,
|
|
308
324
|
{
|
|
309
|
-
...
|
|
325
|
+
...handlerOptions,
|
|
310
326
|
loader: buildLoader,
|
|
311
327
|
worker: worker,
|
|
312
328
|
logger: createLogger(),
|
|
@@ -321,7 +337,6 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
321
337
|
},
|
|
322
338
|
pipeableStreamOptions: pipeableStreamOptions,
|
|
323
339
|
manifest: serverManifest ?? {},
|
|
324
|
-
moduleBasePath: '',
|
|
325
340
|
build: {
|
|
326
341
|
htmlOutputPath: userOptions.build.htmlOutputPath,
|
|
327
342
|
rscOutputPath: userOptions.build.rscOutputPath,
|
|
@@ -333,7 +348,7 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
333
348
|
},
|
|
334
349
|
globalCss: globalCss,
|
|
335
350
|
},
|
|
336
|
-
cssFilesByPage
|
|
351
|
+
cssFilesByPage
|
|
337
352
|
);
|
|
338
353
|
|
|
339
354
|
// Process render results
|
|
@@ -348,11 +363,13 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
348
363
|
if (!finalResult) {
|
|
349
364
|
throw new Error("No render result produced");
|
|
350
365
|
}
|
|
351
|
-
finalResult.streamMetrics.duration = Math.round(
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
366
|
+
finalResult.streamMetrics.duration = Math.round(
|
|
367
|
+
performance.now() - finalResult.streamMetrics.startTime
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
this.environment.logger.info(
|
|
371
|
+
`Rendered ${finalResult.completedRoutes.size} unique routes in ${finalResult.streamMetrics.duration}ms`
|
|
372
|
+
);
|
|
356
373
|
|
|
357
374
|
// Update timing
|
|
358
375
|
timing.render = Date.now() - (timing.renderStart ?? timing.start);
|
|
@@ -44,7 +44,6 @@ export async function* renderPage(
|
|
|
44
44
|
} satisfies CreateHandlerOptions;
|
|
45
45
|
// Create streams with CSS files
|
|
46
46
|
const [rscFull, rscHeadless] = await renderStreams(newHandlerOptions);
|
|
47
|
-
|
|
48
47
|
// Handle stream creation errors
|
|
49
48
|
if (rscFull.type !== "success") {
|
|
50
49
|
yield {
|
|
@@ -37,6 +37,15 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
|
|
|
37
37
|
if (resolvedOptionsResult.type === "error") throw resolvedOptionsResult.error;
|
|
38
38
|
userOptions = resolvedOptionsResult.userOptions;
|
|
39
39
|
let staticManifest: Manifest;
|
|
40
|
+
const getID = (id: string) => {
|
|
41
|
+
if(userOptions.moduleBasePath !== '' && !id.startsWith(userOptions.moduleBasePath)) {
|
|
42
|
+
id = join(userOptions.moduleBasePath, id);
|
|
43
|
+
}
|
|
44
|
+
if(!id.startsWith('/')) {
|
|
45
|
+
id = '/' + id;
|
|
46
|
+
}
|
|
47
|
+
return id;
|
|
48
|
+
}
|
|
40
49
|
return {
|
|
41
50
|
name: "vite:react-server-action-transform",
|
|
42
51
|
enforce: "pre",
|
|
@@ -73,13 +82,14 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
|
|
|
73
82
|
}
|
|
74
83
|
if (isServer && isBuild) {
|
|
75
84
|
const [key] = userOptions.normalizer(id);
|
|
76
|
-
id =
|
|
85
|
+
id = key + ".js";
|
|
77
86
|
}
|
|
78
|
-
const
|
|
87
|
+
const finalID = getID(id);
|
|
88
|
+
const transformed = await transformModuleIfNeeded(code, finalID, null);
|
|
79
89
|
if (!transformed) return null;
|
|
80
90
|
return {
|
|
81
91
|
code: transformed,
|
|
82
|
-
id:
|
|
92
|
+
id: finalID,
|
|
83
93
|
map: null,
|
|
84
94
|
};
|
|
85
95
|
},
|
|
@@ -38,6 +38,15 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
|
|
|
38
38
|
|
|
39
39
|
let staticManifest: Manifest;
|
|
40
40
|
|
|
41
|
+
const getID = (id: string) => {
|
|
42
|
+
if(userOptions.moduleBasePath !== '' && !id.startsWith(userOptions.moduleBasePath)) {
|
|
43
|
+
id = join(userOptions.moduleBasePath, id);
|
|
44
|
+
}
|
|
45
|
+
if(!id.startsWith('/')) {
|
|
46
|
+
id = '/' + id;
|
|
47
|
+
}
|
|
48
|
+
return id;
|
|
49
|
+
}
|
|
41
50
|
return {
|
|
42
51
|
name: "vite:react-server-transform",
|
|
43
52
|
enforce: "pre", // Run before Vite's transforms
|
|
@@ -59,12 +68,12 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
|
|
|
59
68
|
if (!ssr) return null;
|
|
60
69
|
if (!userOptions.autoDiscover.modulePattern(id)) return null;
|
|
61
70
|
if (!code.match('"use client"')) return null;
|
|
62
|
-
|
|
71
|
+
|
|
63
72
|
if (isBuild) {
|
|
64
73
|
const [key, value] = userOptions.normalizer(id);
|
|
65
74
|
if (staticManifest) {
|
|
66
75
|
if (value in staticManifest) {
|
|
67
|
-
id =
|
|
76
|
+
id = staticManifest[value].file
|
|
68
77
|
} else {
|
|
69
78
|
const hash = this.emitFile({
|
|
70
79
|
id,
|
|
@@ -75,15 +84,16 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
|
|
|
75
84
|
// get fileName from hash
|
|
76
85
|
|
|
77
86
|
const fileName = this.getFileName(hash);
|
|
78
|
-
id =
|
|
87
|
+
id = fileName;
|
|
79
88
|
}
|
|
80
89
|
} else {
|
|
81
90
|
throw new Error(`Client manifest not found.`);
|
|
82
91
|
}
|
|
83
92
|
}
|
|
93
|
+
const finalID = getID(id);
|
|
84
94
|
const transformed = await transformModuleIfNeeded(
|
|
85
95
|
code,
|
|
86
|
-
|
|
96
|
+
finalID,
|
|
87
97
|
// Pass null for nextLoad since we don't need module loading in the plugin
|
|
88
98
|
null
|
|
89
99
|
);
|