vite-plugin-react-server 1.1.8 → 1.1.10
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/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/plugin/config/defaults.d.ts +2 -1
- package/dist/plugin/config/defaults.d.ts.map +1 -1
- package/dist/plugin/config/defaults.js +3 -1
- package/dist/plugin/config/defaults.js.map +1 -1
- package/dist/plugin/config/resolveDevServerConfig.d.ts +2 -0
- package/dist/plugin/config/resolveDevServerConfig.d.ts.map +1 -0
- package/dist/plugin/config/resolveDevServerConfig.js +1 -0
- package/dist/plugin/config/resolveEnv.d.ts +3 -0
- package/dist/plugin/config/resolveEnv.d.ts.map +1 -0
- package/dist/plugin/config/resolveEnv.js +21 -0
- package/dist/plugin/config/resolveEnv.js.map +1 -0
- package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
- package/dist/plugin/config/resolveOptions.js +25 -9
- package/dist/plugin/config/resolveOptions.js.map +1 -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 +45 -52
- package/dist/plugin/config/resolveUserConfig.js.map +1 -1
- package/dist/plugin/helpers/collectManifestCss.js.map +1 -1
- package/dist/plugin/helpers/createCssProps.d.ts.map +1 -1
- package/dist/plugin/helpers/createCssProps.js +10 -2
- package/dist/plugin/helpers/createCssProps.js.map +1 -1
- package/dist/plugin/helpers/getRouteFiles.js +18 -35
- package/dist/plugin/helpers/inputNormalizer.d.ts +2 -1
- package/dist/plugin/helpers/inputNormalizer.d.ts.map +1 -1
- package/dist/plugin/helpers/inputNormalizer.js +34 -9
- package/dist/plugin/helpers/inputNormalizer.js.map +1 -1
- package/dist/plugin/helpers/requestInfo.d.ts +16 -0
- package/dist/plugin/helpers/requestInfo.d.ts.map +1 -0
- package/dist/plugin/helpers/requestInfo.js +66 -0
- package/dist/plugin/helpers/requestInfo.js.map +1 -0
- package/dist/plugin/helpers/requestToRoute.js +14 -22
- package/dist/plugin/helpers/serializeUserOptions.js.map +1 -1
- package/dist/plugin/loader/css-loader.development.d.ts.map +1 -1
- package/dist/plugin/loader/css-loader.development.js +1 -7
- package/dist/plugin/loader/css-loader.development.js.map +1 -1
- package/dist/plugin/loader/css-loader.production.js.map +1 -1
- package/dist/plugin/loader/react-loader.d.ts.map +1 -1
- package/dist/plugin/loader/react-loader.js +1 -8
- package/dist/plugin/loader/react-loader.js.map +1 -1
- package/dist/plugin/metrics/formatMetrics.d.ts +6 -1
- package/dist/plugin/metrics/formatMetrics.d.ts.map +1 -1
- package/dist/plugin/metrics/formatMetrics.js +21 -3
- package/dist/plugin/metrics/formatMetrics.js.map +1 -1
- package/dist/plugin/metrics.js +1 -1
- package/dist/plugin/plugin.client.js.map +1 -1
- package/dist/plugin/plugin.server.js.map +1 -1
- package/dist/plugin/preserver/plugin.js.map +1 -1
- package/dist/plugin/react-client/createMessageHandlers.d.ts +10 -0
- package/dist/plugin/react-client/createMessageHandlers.d.ts.map +1 -0
- package/dist/plugin/react-client/createMessageHandlers.js +36 -0
- package/dist/plugin/react-client/createMessageHandlers.js.map +1 -0
- package/dist/plugin/react-client/createWorkerStream.d.ts +3 -3
- package/dist/plugin/react-client/createWorkerStream.d.ts.map +1 -1
- package/dist/plugin/react-client/createWorkerStream.js +60 -69
- package/dist/plugin/react-client/createWorkerStream.js.map +1 -1
- package/dist/plugin/react-client/plugin.d.ts.map +1 -1
- package/dist/plugin/react-client/plugin.js +1 -3
- package/dist/plugin/react-client/plugin.js.map +1 -1
- package/dist/plugin/react-client/restartWorker.js +2 -2
- package/dist/plugin/react-client/restartWorker.js.map +1 -1
- package/dist/plugin/react-client/server.d.ts.map +1 -1
- package/dist/plugin/react-client/server.js +29 -40
- package/dist/plugin/react-client/server.js.map +1 -1
- package/dist/plugin/react-server/server.d.ts.map +1 -1
- package/dist/plugin/react-server/server.js +17 -19
- package/dist/plugin/react-server/server.js.map +1 -1
- package/dist/plugin/react-static/collectHtmlWorkerContent.js.map +1 -1
- package/dist/plugin/react-static/collectRscContent.js.map +1 -1
- package/dist/plugin/react-static/configurePreviewServer.d.ts.map +1 -1
- package/dist/plugin/react-static/configurePreviewServer.js +58 -54
- package/dist/plugin/react-static/configurePreviewServer.js.map +1 -1
- package/dist/plugin/react-static/fileWriter.js.map +1 -1
- package/dist/plugin/react-static/plugin.d.ts.map +1 -1
- package/dist/plugin/react-static/plugin.js +12 -6
- package/dist/plugin/react-static/plugin.js.map +1 -1
- package/dist/plugin/react-static/renderPages.js.map +1 -1
- package/dist/plugin/transformer/plugin.client.d.ts.map +1 -1
- package/dist/plugin/transformer/plugin.client.js +3 -12
- package/dist/plugin/transformer/plugin.client.js.map +1 -1
- package/dist/plugin/transformer/plugin.js.map +1 -1
- package/dist/plugin/transformer/plugin.server.d.ts.map +1 -1
- package/dist/plugin/transformer/plugin.server.js +17 -24
- package/dist/plugin/transformer/plugin.server.js.map +1 -1
- package/dist/plugin/types.d.ts +4 -1
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/plugin/utils/callServer.d.ts.map +1 -1
- package/dist/plugin/utils/callServer.js +2 -2
- package/dist/plugin/utils/callServer.js.map +1 -1
- package/dist/plugin/utils/createReactFetcher.d.ts +1 -1
- package/dist/plugin/utils/createReactFetcher.d.ts.map +1 -1
- package/dist/plugin/utils/createReactFetcher.js +6 -8
- package/dist/plugin/utils/createReactFetcher.js.map +1 -1
- package/dist/plugin/utils/env.d.ts +2 -0
- package/dist/plugin/utils/env.d.ts.map +1 -0
- package/dist/plugin/utils/env.js +9 -0
- package/dist/plugin/utils/env.js.map +1 -0
- package/dist/plugin/utils/index.d.ts +1 -0
- package/dist/plugin/utils/index.d.ts.map +1 -1
- package/dist/plugin/utils/index.js +1 -0
- package/dist/plugin/utils/pageURL.d.ts +4 -1
- package/dist/plugin/utils/pageURL.d.ts.map +1 -1
- package/dist/plugin/utils/pageURL.js +23 -11
- package/dist/plugin/utils/pageURL.js.map +1 -1
- package/dist/plugin/utils.js +1 -0
- package/dist/plugin/utils.js.map +1 -1
- package/dist/plugin/worker/createWorker.d.ts.map +1 -1
- package/dist/plugin/worker/createWorker.js +4 -3
- package/dist/plugin/worker/createWorker.js.map +1 -1
- package/dist/plugin/worker/html/createHtmlWorkerRenderState.d.ts.map +1 -1
- package/dist/plugin/worker/html/createHtmlWorkerRenderState.js +3 -0
- package/dist/plugin/worker/html/createHtmlWorkerRenderState.js.map +1 -1
- package/dist/plugin/worker/rsc/handleRender.d.ts +2 -7
- package/dist/plugin/worker/rsc/handleRender.d.ts.map +1 -1
- package/dist/plugin/worker/rsc/handleRender.js.map +1 -1
- package/dist/plugin/worker/rsc/messageHandler.d.ts.map +1 -1
- package/dist/plugin/worker/rsc/messageHandler.js +1 -1
- package/dist/plugin/worker/rsc/messageHandler.js.map +1 -1
- package/dist/plugin/worker/rsc/rsc-worker.development.js.map +1 -1
- package/dist/plugin/worker/rsc/state.d.ts.map +1 -1
- package/dist/plugin/worker/rsc/state.js.map +1 -1
- package/dist/plugin/worker/types.d.ts +6 -0
- package/dist/plugin/worker/types.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/plugin/config/defaults.tsx +2 -1
- package/plugin/config/resolveDevServerConfig.tsx +0 -0
- package/plugin/config/resolveEnv.ts +37 -0
- package/plugin/config/resolveOptions.ts +49 -24
- package/plugin/config/resolveUserConfig.ts +73 -70
- package/plugin/helpers/createCssProps.tsx +14 -6
- package/plugin/helpers/inputNormalizer.ts +66 -17
- package/plugin/helpers/requestInfo.ts +81 -0
- package/plugin/loader/css-loader.development.ts +2 -8
- package/plugin/loader/react-loader.ts +1 -10
- package/plugin/metrics/formatMetrics.ts +29 -4
- package/plugin/preserver/plugin.ts +1 -0
- package/plugin/react-client/createMessageHandlers.ts +37 -0
- package/plugin/react-client/createWorkerStream.ts +76 -83
- package/plugin/react-client/plugin.ts +1 -4
- package/plugin/react-client/restartWorker.ts +2 -2
- package/plugin/react-client/server.ts +36 -62
- package/plugin/react-server/server.ts +17 -30
- package/plugin/react-static/configurePreviewServer.ts +75 -62
- package/plugin/react-static/plugin.ts +17 -11
- package/plugin/transformer/plugin.client.ts +4 -12
- package/plugin/transformer/plugin.server.ts +18 -25
- package/plugin/types.ts +12 -9
- package/plugin/utils/callServer.ts +20 -19
- package/plugin/utils/createReactFetcher.ts +6 -8
- package/plugin/utils/env.ts +1 -0
- package/plugin/utils/index.ts +2 -1
- package/plugin/utils/pageURL.ts +29 -24
- package/plugin/worker/createWorker.ts +4 -9
- package/plugin/worker/html/createHtmlWorkerRenderState.tsx +3 -0
- package/plugin/worker/rsc/handleRender.ts +2 -7
- package/plugin/worker/rsc/messageHandler.tsx +4 -7
- package/plugin/worker/rsc/rsc-worker.development.ts +1 -1
- package/plugin/worker/types.ts +7 -0
- package/dist/plugin/helpers/getRouteFiles.js.map +0 -1
- package/dist/plugin/helpers/requestToRoute.js.map +0 -1
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { Logger } from "vite";
|
|
2
|
-
import type {
|
|
3
|
-
import type { StreamMetrics } from "
|
|
4
|
-
import { Worker } from "node:worker_threads";
|
|
2
|
+
import type { RscWorkerOutputMessage, RscRenderMessage } from "../worker/types.js";
|
|
3
|
+
import type { StreamMetrics } from "../types.js";
|
|
4
|
+
import type { Worker as NodeWorker } from "node:worker_threads";
|
|
5
|
+
import type { StreamHandlers } from "../worker/types.js";
|
|
6
|
+
import { createMessageHandler } from "./createMessageHandlers.js";
|
|
7
|
+
|
|
5
8
|
/**
|
|
6
9
|
* Creates an async generator that yields RSC chunks from the worker.
|
|
7
10
|
* Handles both module requests and RSC streaming.
|
|
@@ -13,95 +16,85 @@ import { Worker } from "node:worker_threads";
|
|
|
13
16
|
* @returns An async generator that yields RSC chunks
|
|
14
17
|
*/
|
|
15
18
|
export async function* createWorkerStream(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
19
|
+
worker: NodeWorker,
|
|
20
|
+
message: Omit<RscRenderMessage, "type" | "id">,
|
|
21
|
+
logger: Logger,
|
|
22
|
+
onMetrics?: (metrics: StreamMetrics) => void
|
|
23
|
+
): AsyncGenerator<Uint8Array> {
|
|
24
|
+
let messageHandler: ((message: RscWorkerOutputMessage | undefined) => void) | null = null;
|
|
25
|
+
let currentResolve: ((chunk: Uint8Array) => void) | null = null;
|
|
26
|
+
const handlers: StreamHandlers = {
|
|
27
|
+
onError: (error: any, errorInfo?: any) => {
|
|
28
|
+
logger.error(error.message + error.stack, {
|
|
29
|
+
error,
|
|
30
|
+
});
|
|
31
|
+
if (errorInfo) {
|
|
32
|
+
logger.error(errorInfo.componentStack);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
onData: (chunk: Uint8Array) => {
|
|
36
|
+
currentResolve?.(chunk);
|
|
37
|
+
},
|
|
38
|
+
onEnd: () => {
|
|
39
|
+
currentResolve?.(new Uint8Array());
|
|
40
|
+
if (messageHandler) {
|
|
41
|
+
worker.removeListener("message", messageHandler);
|
|
42
|
+
messageHandler = null;
|
|
36
43
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
},
|
|
45
|
+
onMetrics: (metrics: StreamMetrics) => {
|
|
46
|
+
onMetrics?.(metrics);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
// Remove any existing message handler before starting
|
|
52
|
+
if (messageHandler) {
|
|
53
|
+
worker.removeListener("message", messageHandler);
|
|
54
|
+
messageHandler = null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
worker.postMessage({
|
|
58
|
+
...message,
|
|
59
|
+
type: "RSC_RENDER",
|
|
60
|
+
id: Math.random().toString(36).slice(2),
|
|
61
|
+
});
|
|
62
|
+
|
|
43
63
|
yield await new Promise<Uint8Array>((resolve) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
break;
|
|
49
|
-
case "RSC_END":
|
|
50
|
-
resolve(new Uint8Array());
|
|
51
|
-
break;
|
|
52
|
-
case "ERROR":
|
|
53
|
-
const errorResponse = onError(message.error);
|
|
54
|
-
resolve(errorResponse);
|
|
55
|
-
break;
|
|
56
|
-
default:
|
|
57
|
-
logger.warn(`Unknown initial message type: ${message.type}`);
|
|
58
|
-
resolve(new Uint8Array());
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
cleanup = () => {
|
|
64
|
-
worker.off("message", messageHandler);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
worker.on("message", messageHandler);
|
|
68
|
-
|
|
69
|
-
// Send the render message to start the RSC stream
|
|
70
|
-
worker.postMessage({
|
|
71
|
-
type: "RSC_RENDER",
|
|
72
|
-
id: message.route,
|
|
73
|
-
...message,
|
|
64
|
+
currentResolve = resolve;
|
|
65
|
+
messageHandler = createMessageHandler({
|
|
66
|
+
handlers,
|
|
67
|
+
logger,
|
|
74
68
|
});
|
|
69
|
+
worker.on("message", messageHandler);
|
|
75
70
|
});
|
|
76
|
-
|
|
77
|
-
// Subsequent yields: handle RSC chunks until stream ends
|
|
71
|
+
|
|
78
72
|
while (true) {
|
|
79
73
|
const chunk = await new Promise<Uint8Array>((resolve) => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
onMetrics?.(message.metrics);
|
|
91
|
-
break;
|
|
92
|
-
case "ERROR":
|
|
93
|
-
cleanup();
|
|
94
|
-
const errorResponse = onError(message.error);
|
|
95
|
-
resolve(errorResponse);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
worker.once("message", messageHandler);
|
|
74
|
+
currentResolve = resolve;
|
|
75
|
+
// Create new message handler for each iteration
|
|
76
|
+
if (messageHandler) {
|
|
77
|
+
worker.removeListener("message", messageHandler);
|
|
78
|
+
}
|
|
79
|
+
messageHandler = createMessageHandler({
|
|
80
|
+
handlers,
|
|
81
|
+
logger,
|
|
82
|
+
});
|
|
83
|
+
worker.on("message", messageHandler);
|
|
100
84
|
});
|
|
101
|
-
|
|
85
|
+
|
|
102
86
|
if (chunk.length === 0) {
|
|
103
87
|
break;
|
|
104
88
|
}
|
|
89
|
+
|
|
105
90
|
yield chunk;
|
|
106
91
|
}
|
|
107
|
-
}
|
|
92
|
+
} finally {
|
|
93
|
+
// Clean up message handler in finally block
|
|
94
|
+
if (messageHandler) {
|
|
95
|
+
worker.removeListener("message", messageHandler);
|
|
96
|
+
messageHandler = null;
|
|
97
|
+
}
|
|
98
|
+
handlers.onEnd();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -65,7 +65,6 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
|
|
|
65
65
|
userConfig = resolvedConfig.userConfig;
|
|
66
66
|
return userConfig;
|
|
67
67
|
},
|
|
68
|
-
|
|
69
68
|
async configurePreviewServer(server) {
|
|
70
69
|
await configurePreviewServer({
|
|
71
70
|
server,
|
|
@@ -82,9 +81,7 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
|
|
|
82
81
|
autoDiscoveredFiles,
|
|
83
82
|
userOptions,
|
|
84
83
|
hmrChannel,
|
|
85
|
-
onMetrics: userOptions.onMetrics
|
|
86
|
-
userOptions.onMetrics?.(metrics);
|
|
87
|
-
} : undefined,
|
|
84
|
+
onMetrics: userOptions.onMetrics,
|
|
88
85
|
});
|
|
89
86
|
},
|
|
90
87
|
|
|
@@ -22,8 +22,8 @@ export async function restartWorker(
|
|
|
22
22
|
try {
|
|
23
23
|
// Terminate the current worker if it exists
|
|
24
24
|
if (currentWorker) {
|
|
25
|
-
currentWorker.
|
|
26
|
-
currentWorker
|
|
25
|
+
currentWorker.removeAllListeners();
|
|
26
|
+
return currentWorker;
|
|
27
27
|
}
|
|
28
28
|
const routeCount = autoDiscoveredFiles.urlMap.size;
|
|
29
29
|
const hmrBuffer = 20; // Buffer for HMR and other operations
|
|
@@ -6,21 +6,15 @@ import type {
|
|
|
6
6
|
ResolvedUserOptions,
|
|
7
7
|
StreamMetrics,
|
|
8
8
|
} from "../types.js";
|
|
9
|
-
import type {
|
|
10
|
-
RscRenderMessage,
|
|
11
|
-
} from "../worker/types.js";
|
|
9
|
+
import type { RscRenderMessage } from "../worker/types.js";
|
|
12
10
|
import type { Worker as NodeWorker } from "node:worker_threads";
|
|
13
11
|
import { MessageChannel } from "node:worker_threads";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
} from "../helpers/serializeUserOptions.js";
|
|
17
|
-
import { getRouteFiles } from "../helpers/getRouteFiles.js";
|
|
18
|
-
import { requestToRoute } from "../helpers/requestToRoute.js";
|
|
12
|
+
import { serializedOptions } from "../helpers/serializeUserOptions.js";
|
|
13
|
+
import { requestInfo } from "../helpers/requestInfo.js";
|
|
19
14
|
import { performance } from "node:perf_hooks";
|
|
20
15
|
import { createWorkerStream } from "./createWorkerStream.js";
|
|
21
16
|
import { restartWorker } from "./restartWorker.js";
|
|
22
17
|
|
|
23
|
-
|
|
24
18
|
/**
|
|
25
19
|
* Handles the RSC stream from the worker.
|
|
26
20
|
* Creates a ReadableStream that pipes RSC chunks to the response.
|
|
@@ -103,65 +97,45 @@ export async function configureWorkerRequestHandler({
|
|
|
103
97
|
...handlerUserOptions
|
|
104
98
|
} = _userOptions;
|
|
105
99
|
const handlerOptions = Object.assign({}, handlerUserOptions, {
|
|
106
|
-
moduleBaseURL:
|
|
107
|
-
|
|
108
|
-
? `${server.config.server.https ? "https" : "http"}://${
|
|
109
|
-
server.config.server.host
|
|
110
|
-
}:${server.config.server.port}`
|
|
111
|
-
: _moduleBaseURL,
|
|
112
|
-
moduleBasePath:
|
|
113
|
-
server.config.base === "/"
|
|
114
|
-
? ""
|
|
115
|
-
: server.config.base.endsWith("/")
|
|
116
|
-
? server.config.base.slice(0, -1)
|
|
117
|
-
: server.config.base,
|
|
100
|
+
moduleBaseURL: server.config.base,
|
|
101
|
+
moduleBasePath: _moduleBasePath,
|
|
118
102
|
projectRoot: server.config.root,
|
|
119
103
|
});
|
|
120
104
|
|
|
121
105
|
// Start the worker
|
|
122
|
-
const currentWorker = await restartWorker(
|
|
106
|
+
const currentWorker = await restartWorker(
|
|
107
|
+
server,
|
|
108
|
+
autoDiscoveredFiles,
|
|
109
|
+
handlerOptions,
|
|
110
|
+
hmrChannel
|
|
111
|
+
);
|
|
123
112
|
|
|
124
113
|
// Create the request handler
|
|
125
114
|
const handler: RequestHandler = async (req, res, next) => {
|
|
126
|
-
if (!req.url
|
|
127
|
-
try {
|
|
128
|
-
if (!currentWorker) {
|
|
129
|
-
server.config.logger.error("[react-client] No worker available");
|
|
130
|
-
return next();
|
|
131
|
-
}
|
|
115
|
+
if (!req.url) return next();
|
|
132
116
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
server.config.logger.error(
|
|
150
|
-
`[react-client] Error fetching route files for ${route}`,
|
|
151
|
-
{
|
|
152
|
-
error: routeFiles.error,
|
|
153
|
-
timestamp: true,
|
|
154
|
-
environment: "server",
|
|
155
|
-
}
|
|
156
|
-
);
|
|
157
|
-
return next();
|
|
158
|
-
}
|
|
159
|
-
const { page, props } = routeFiles;
|
|
117
|
+
const info = requestInfo(req, handlerOptions, "");
|
|
118
|
+
if (!info.isRscRequest) return next();
|
|
119
|
+
|
|
120
|
+
if (!currentWorker) {
|
|
121
|
+
server.config.logger.warn("[react-client] No worker available");
|
|
122
|
+
return next();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!autoDiscoveredFiles.urlMap.has(info.route)) {
|
|
126
|
+
server.config.logger.warn(`[react-client] No route found for route: ${info.route}`);
|
|
127
|
+
return next();
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const routeFiles = autoDiscoveredFiles.urlMap.get(info.route)!;
|
|
131
|
+
const pagePath = routeFiles.page;
|
|
132
|
+
const propsPath = routeFiles.props;
|
|
160
133
|
|
|
161
134
|
// Set up response headers for streaming
|
|
162
|
-
res.setHeader("Content-Type",
|
|
135
|
+
res.setHeader("Content-Type", info.contentType);
|
|
163
136
|
res.setHeader("Transfer-Encoding", "chunked");
|
|
164
137
|
res.setHeader("Connection", "keep-alive");
|
|
138
|
+
|
|
165
139
|
const serializedUserOptions = serializedOptions(
|
|
166
140
|
handlerOptions,
|
|
167
141
|
autoDiscoveredFiles
|
|
@@ -172,9 +146,9 @@ export async function configureWorkerRequestHandler({
|
|
|
172
146
|
{
|
|
173
147
|
...serializedUserOptions,
|
|
174
148
|
// we make the worker stream aware of the route, pagePath, propsPath
|
|
175
|
-
route,
|
|
176
|
-
pagePath:
|
|
177
|
-
propsPath:
|
|
149
|
+
route: info.route,
|
|
150
|
+
pagePath: pagePath,
|
|
151
|
+
propsPath: propsPath,
|
|
178
152
|
// override these at all times to ensure the settings will work for the dev server
|
|
179
153
|
projectRoot: server.config.root,
|
|
180
154
|
build: serializedUserOptions.build,
|
|
@@ -187,7 +161,7 @@ export async function configureWorkerRequestHandler({
|
|
|
187
161
|
? (metrics) => {
|
|
188
162
|
const elapsedTime = performance.now() - startTime;
|
|
189
163
|
const formattedMetrics = {
|
|
190
|
-
route,
|
|
164
|
+
route: info.route,
|
|
191
165
|
htmlSize: 0,
|
|
192
166
|
rscSize: metrics.bytes,
|
|
193
167
|
processingTime: elapsedTime,
|
|
@@ -196,10 +170,10 @@ export async function configureWorkerRequestHandler({
|
|
|
196
170
|
memoryUsage: process.memoryUsage(),
|
|
197
171
|
streamMetrics: {
|
|
198
172
|
...metrics,
|
|
199
|
-
duration: elapsedTime
|
|
173
|
+
duration: elapsedTime,
|
|
200
174
|
},
|
|
201
175
|
htmlSizes: new Map(),
|
|
202
|
-
rscSizes: new Map([[route, metrics.bytes]]),
|
|
176
|
+
rscSizes: new Map([[info.route, metrics.bytes]]),
|
|
203
177
|
} satisfies RenderMetrics;
|
|
204
178
|
onMetrics(formattedMetrics);
|
|
205
179
|
}
|
|
@@ -6,6 +6,7 @@ import { collectViteModuleGraphCss } from "../helpers/collectViteModuleGraphCss.
|
|
|
6
6
|
import { resolvePageAndProps } from "../helpers/resolvePageAndProps.js";
|
|
7
7
|
import { createHandler } from "../helpers/createHandler.js";
|
|
8
8
|
import React from "react";
|
|
9
|
+
import { requestInfo } from "../helpers/requestInfo.js";
|
|
9
10
|
|
|
10
11
|
export async function configureReactServer({
|
|
11
12
|
server,
|
|
@@ -31,18 +32,8 @@ export async function configureReactServer({
|
|
|
31
32
|
} = _userOptions;
|
|
32
33
|
|
|
33
34
|
const handlerOptions = Object.assign({}, handlerUserOptions, {
|
|
34
|
-
moduleBaseURL:
|
|
35
|
-
|
|
36
|
-
? `${server.config.server.https ? "https" : "http"}://${
|
|
37
|
-
server.config.server.host
|
|
38
|
-
}:${server.config.server.port}`
|
|
39
|
-
: _moduleBaseURL,
|
|
40
|
-
moduleBasePath:
|
|
41
|
-
server.config.base === "/"
|
|
42
|
-
? ""
|
|
43
|
-
: server.config.base.endsWith("/")
|
|
44
|
-
? server.config.base.slice(0, -1)
|
|
45
|
-
: server.config.base,
|
|
35
|
+
moduleBaseURL: server.config.base,
|
|
36
|
+
moduleBasePath: _moduleBasePath,
|
|
46
37
|
projectRoot: server.config.root,
|
|
47
38
|
});
|
|
48
39
|
// Handle Vite server restarts
|
|
@@ -64,32 +55,28 @@ export async function configureReactServer({
|
|
|
64
55
|
});
|
|
65
56
|
|
|
66
57
|
server.middlewares.use(async (req, res, next) => {
|
|
58
|
+
if(!req.url) {
|
|
59
|
+
return next();
|
|
60
|
+
}
|
|
61
|
+
const info = requestInfo(req, handlerOptions, "");
|
|
62
|
+
if (!info.isRscRequest) return next();
|
|
67
63
|
try {
|
|
68
|
-
if (
|
|
69
|
-
let route = req.url?.replace("/" + handlerOptions.build.rscOutputPath, "");
|
|
70
|
-
if(handlerOptions.moduleBasePath !== '' && !route?.startsWith(handlerOptions.moduleBasePath)) {
|
|
71
|
-
next();
|
|
72
|
-
} else if(route && handlerOptions.moduleBasePath.length) {
|
|
73
|
-
route = route.slice(handlerOptions.moduleBasePath.length);
|
|
74
|
-
}
|
|
75
|
-
if (!route || route === "") {
|
|
76
|
-
route = "/";
|
|
77
|
-
}
|
|
78
|
-
if(!route.startsWith("/")) {
|
|
79
|
-
route = "/" + route;
|
|
80
|
-
}
|
|
81
|
-
if (!autoDiscoveredFiles.urlMap.has(route)) {
|
|
64
|
+
if (!autoDiscoveredFiles.urlMap.has(info.route)) {
|
|
82
65
|
return next();
|
|
83
66
|
}
|
|
84
|
-
const routeFiles = autoDiscoveredFiles.urlMap.get(route)!;
|
|
67
|
+
const routeFiles = autoDiscoveredFiles.urlMap.get(info.route)!;
|
|
85
68
|
const pagePath = routeFiles.page;
|
|
86
69
|
const propsPath = routeFiles.props;
|
|
87
|
-
|
|
70
|
+
const port = server.config.server.port ?? 5173;
|
|
71
|
+
const host = server.config.server.host ?? 'localhost';
|
|
72
|
+
const protocol = server.config.server.https ? 'https' : 'http';
|
|
73
|
+
process.env['VITE_BASE_URL'] = `${server.config.base}${server.config.base.endsWith('/') ? '' : '/'}`;
|
|
74
|
+
process.env['VITE_PUBLIC_ORIGIN'] = `${protocol}://${host}:${port}`;
|
|
88
75
|
// first load the page and props
|
|
89
76
|
const pageAndPropsResult = await resolvePageAndProps({
|
|
90
77
|
pagePath,
|
|
91
78
|
propsPath,
|
|
92
|
-
route,
|
|
79
|
+
route: info.route,
|
|
93
80
|
loader: server.ssrLoadModule,
|
|
94
81
|
pageExportName: handlerOptions.pageExportName ?? "default",
|
|
95
82
|
propsExportName: handlerOptions.propsExportName ?? "default",
|
|
@@ -130,7 +117,7 @@ export async function configureReactServer({
|
|
|
130
117
|
onEvent: eventHandler,
|
|
131
118
|
manifest: serverManifest,
|
|
132
119
|
worker: server as any,
|
|
133
|
-
route,
|
|
120
|
+
route: info.route,
|
|
134
121
|
pagePath,
|
|
135
122
|
propsPath,
|
|
136
123
|
cssFiles: cssFilesResult.cssFiles ?? new Map(),
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { PreviewServer } from "vite";
|
|
2
|
-
import { MIME_TYPES } from "../config/mimeTypes.js";
|
|
3
2
|
import type { ResolvedUserOptions } from "../types.js";
|
|
4
3
|
import { join } from "node:path";
|
|
5
4
|
import { createReadStream } from "node:fs";
|
|
6
5
|
import { stat } from "node:fs/promises";
|
|
7
6
|
import { pipeline } from "node:stream/promises";
|
|
7
|
+
import { requestInfo } from "../helpers/requestInfo.js";
|
|
8
|
+
|
|
9
|
+
interface StreamError extends Error {
|
|
10
|
+
code?: string;
|
|
11
|
+
}
|
|
8
12
|
|
|
9
13
|
export async function configurePreviewServer({
|
|
10
14
|
server,
|
|
@@ -13,77 +17,86 @@ export async function configurePreviewServer({
|
|
|
13
17
|
server: PreviewServer;
|
|
14
18
|
userOptions: ResolvedUserOptions;
|
|
15
19
|
}) {
|
|
16
|
-
const staticHostDir = join(
|
|
20
|
+
const staticHostDir = join(
|
|
21
|
+
userOptions.projectRoot,
|
|
22
|
+
userOptions.build.outDir,
|
|
23
|
+
userOptions.build.static
|
|
24
|
+
);
|
|
17
25
|
server.middlewares.use(async (req, res, next) => {
|
|
18
|
-
if(!req.url) {
|
|
19
|
-
console.log("no url")
|
|
26
|
+
if (!req.url) {
|
|
20
27
|
return next();
|
|
21
28
|
}
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
const ext = value.slice(value.lastIndexOf("."));
|
|
25
|
-
// handle index.html
|
|
26
|
-
const isHtml = userOptions.autoDiscover.htmlPattern(value)
|
|
27
|
-
if (isHtml || (req.headers.accept?.includes("text/html"))) {
|
|
28
|
-
const indexHtml = isHtml ? join(staticHostDir, value) : join(staticHostDir, value, userOptions.build.htmlOutputPath);
|
|
29
|
-
try {
|
|
30
|
-
const stats = await stat(indexHtml);
|
|
31
|
-
if (stats.isFile()) {
|
|
32
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
33
|
-
await pipeline(createReadStream(indexHtml), res);
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
} catch {
|
|
37
|
-
// File doesn't exist, continue to next middleware
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
const isRsc = userOptions.autoDiscover.rscPattern(value)
|
|
41
|
-
if (isRsc || (req.headers.accept?.includes("text/x-component"))) {
|
|
42
|
-
const rsc = isRsc ? join(staticHostDir, value) : join(staticHostDir, value, userOptions.build.rscOutputPath);
|
|
43
|
-
try {
|
|
44
|
-
const stats = await stat(rsc);
|
|
45
|
-
if (stats.isFile()) {
|
|
46
|
-
res.setHeader("Content-Type", "text/x-component; charset=utf-8");
|
|
47
|
-
await pipeline(createReadStream(rsc), res);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
} catch {
|
|
51
|
-
// File doesn't exist, continue to next middleware
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
const isCss = userOptions.autoDiscover.cssPattern(value)
|
|
55
|
-
if (isCss || (req.headers.accept?.includes("text/css") && (ext === ""))) {
|
|
56
|
-
const css = isCss ? join(staticHostDir, value) : join(staticHostDir, value);
|
|
57
|
-
try {
|
|
58
|
-
const stats = await stat(css);
|
|
59
|
-
if (stats.isFile()) {
|
|
60
|
-
res.setHeader("Content-Type", "text/css; charset=utf-8");
|
|
61
|
-
await pipeline(createReadStream(css), res);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
} catch {
|
|
65
|
-
// File doesn't exist, continue to next middleware
|
|
66
|
-
}
|
|
67
|
-
}
|
|
29
|
+
const { contentType, filePath } = requestInfo(req, userOptions, staticHostDir);
|
|
30
|
+
|
|
68
31
|
// Handle static files including CSS
|
|
69
|
-
if (
|
|
70
|
-
const filePath = join(staticHostDir, value);
|
|
32
|
+
if (filePath) {
|
|
71
33
|
try {
|
|
72
34
|
const stats = await stat(filePath);
|
|
73
35
|
if (stats.isFile()) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
36
|
+
res.setHeader("Content-Type", contentType);
|
|
37
|
+
|
|
38
|
+
// Create abort controller for the stream
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
const { signal } = controller;
|
|
41
|
+
|
|
42
|
+
// Check if response is still writable before streaming
|
|
43
|
+
if (!res.writable) {
|
|
44
|
+
res.statusCode = 499;
|
|
45
|
+
res.end("Client closed request");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const readStream = createReadStream(filePath);
|
|
51
|
+
readStream.on('error', () => {
|
|
52
|
+
if (!res.writable) {
|
|
53
|
+
controller.abort();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
await pipeline(readStream, res, { signal });
|
|
57
|
+
} catch (error) {
|
|
58
|
+
const streamError = error as StreamError;
|
|
59
|
+
// Handle different error cases
|
|
60
|
+
if (streamError.code === 'ERR_STREAM_PREMATURE_CLOSE' ||
|
|
61
|
+
streamError.name === 'AbortError') {
|
|
62
|
+
// Client closed the connection
|
|
63
|
+
if (res.writable) {
|
|
64
|
+
res.statusCode = 499;
|
|
65
|
+
res.end("Client closed request");
|
|
66
|
+
}
|
|
67
|
+
} else if (streamError.code === 'ENOENT') {
|
|
68
|
+
// File not found
|
|
69
|
+
res.statusCode = 404;
|
|
70
|
+
server.config.logger.error(`File not found: ${filePath}. ${streamError.message}`, {
|
|
71
|
+
error: streamError,
|
|
72
|
+
});
|
|
73
|
+
res.end("File not found");
|
|
74
|
+
} else {
|
|
75
|
+
// Server error
|
|
76
|
+
server.config.logger.error(`Error loading file: ${filePath}. ${streamError.message}`, {
|
|
77
|
+
error: streamError,
|
|
78
|
+
});
|
|
79
|
+
res.statusCode = 500;
|
|
80
|
+
res.end("Internal server error");
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
81
83
|
}
|
|
82
|
-
await pipeline(createReadStream(filePath), res);
|
|
83
84
|
return;
|
|
84
85
|
}
|
|
85
|
-
} catch {
|
|
86
|
-
|
|
86
|
+
} catch (error) {
|
|
87
|
+
const err = error as Error;
|
|
88
|
+
// Handle file system errors
|
|
89
|
+
if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
90
|
+
res.statusCode = 404;
|
|
91
|
+
res.end("File not found");
|
|
92
|
+
} else {
|
|
93
|
+
server.config.logger.error(`Error loading file: ${filePath}.`, {
|
|
94
|
+
error: err,
|
|
95
|
+
});
|
|
96
|
+
res.statusCode = 500;
|
|
97
|
+
res.end("Internal server error");
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
87
100
|
}
|
|
88
101
|
}
|
|
89
102
|
next();
|