vite-plugin-react-server 1.1.7 → 1.1.9
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 +10 -5
- package/dist/plugin/config/defaults.d.ts +1 -1
- package/dist/plugin/config/defaults.js +1 -1
- package/dist/plugin/config/defaults.js.map +1 -1
- package/dist/plugin/config/resolveAutoDiscover.d.ts +2 -0
- package/dist/plugin/config/resolveAutoDiscover.d.ts.map +1 -1
- package/dist/plugin/config/resolveAutoDiscover.js +15 -18
- package/dist/plugin/config/resolveAutoDiscover.js.map +1 -1
- package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
- package/dist/plugin/config/resolveOptions.js +4 -1
- package/dist/plugin/config/resolveOptions.js.map +1 -1
- package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
- package/dist/plugin/config/resolveUserConfig.js +64 -30
- package/dist/plugin/config/resolveUserConfig.js.map +1 -1
- package/dist/plugin/helpers/collectBundleManifestCss.d.ts +0 -6
- package/dist/plugin/helpers/collectBundleManifestCss.d.ts.map +1 -1
- package/dist/plugin/helpers/collectBundleManifestCss.js +2 -110
- package/dist/plugin/helpers/collectViteModuleGraphCss.d.ts +2 -1
- package/dist/plugin/helpers/collectViteModuleGraphCss.d.ts.map +1 -1
- package/dist/plugin/helpers/collectViteModuleGraphCss.js +19 -18
- package/dist/plugin/helpers/collectViteModuleGraphCss.js.map +1 -1
- package/dist/plugin/helpers/createCssProps.d.ts +3 -2
- package/dist/plugin/helpers/createCssProps.d.ts.map +1 -1
- package/dist/plugin/helpers/createCssProps.js +10 -6
- package/dist/plugin/helpers/createCssProps.js.map +1 -1
- package/dist/plugin/helpers/createRscStream.d.ts.map +1 -1
- package/dist/plugin/helpers/createRscStream.js +37 -43
- package/dist/plugin/helpers/createRscStream.js.map +1 -1
- package/dist/plugin/helpers/formatMetrics.d.ts +4 -0
- package/dist/plugin/helpers/formatMetrics.d.ts.map +1 -0
- package/dist/plugin/helpers/formatMetrics.js +24 -0
- package/dist/plugin/helpers/tryManifest.d.ts.map +1 -1
- package/dist/plugin/helpers/tryManifest.js +0 -8
- package/dist/plugin/helpers/tryManifest.js.map +1 -1
- package/dist/plugin/html.js +1 -1
- package/dist/plugin/html.js.map +1 -1
- package/dist/plugin/loader/createBuildLoader.d.ts.map +1 -1
- package/dist/plugin/loader/createBuildLoader.js +2 -0
- package/dist/plugin/loader/createBuildLoader.js.map +1 -1
- package/dist/plugin/metrics/formatMetrics.d.ts +4 -0
- package/dist/plugin/metrics/formatMetrics.d.ts.map +1 -0
- package/dist/plugin/metrics/formatMetrics.js +39 -0
- package/dist/plugin/metrics/formatMetrics.js.map +1 -0
- package/dist/plugin/metrics/index.d.ts +3 -0
- package/dist/plugin/metrics/index.d.ts.map +1 -0
- package/dist/plugin/metrics/index.js +1 -0
- package/dist/plugin/metrics.js +7 -0
- package/dist/plugin/metrics.js.map +1 -0
- package/dist/plugin/react-client/createWorkerStream.d.ts +16 -0
- package/dist/plugin/react-client/createWorkerStream.d.ts.map +1 -0
- package/dist/plugin/react-client/createWorkerStream.js +88 -0
- package/dist/plugin/react-client/createWorkerStream.js.map +1 -0
- package/dist/plugin/react-client/plugin.d.ts.map +1 -1
- package/dist/plugin/react-client/plugin.js +4 -1
- package/dist/plugin/react-client/plugin.js.map +1 -1
- package/dist/plugin/react-client/restartWorker.d.ts +6 -0
- package/dist/plugin/react-client/restartWorker.d.ts.map +1 -0
- package/dist/plugin/react-client/restartWorker.js +53 -0
- package/dist/plugin/react-client/restartWorker.js.map +1 -0
- package/dist/plugin/react-client/server.d.ts +5 -4
- package/dist/plugin/react-client/server.d.ts.map +1 -1
- package/dist/plugin/react-client/server.js +79 -110
- 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 +23 -28
- package/dist/plugin/react-server/server.js.map +1 -1
- package/dist/plugin/react-static/collectHtmlWorkerContent.js +1 -1
- package/dist/plugin/react-static/collectHtmlWorkerContent.js.map +1 -1
- package/dist/plugin/react-static/collectRscContent.js +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 +23 -4
- package/dist/plugin/react-static/configurePreviewServer.js.map +1 -1
- package/dist/plugin/react-static/fileWriter.d.ts.map +1 -1
- package/dist/plugin/react-static/fileWriter.js +5 -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 +50 -33
- package/dist/plugin/react-static/plugin.js.map +1 -1
- package/dist/plugin/types.d.ts +6 -7
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/plugin/utils/callServer.d.ts +2 -0
- package/dist/plugin/utils/callServer.d.ts.map +1 -0
- package/dist/plugin/utils/callServer.js +26 -0
- package/dist/plugin/utils/callServer.js.map +1 -0
- package/dist/plugin/utils/createReactFetcher.d.ts +7 -0
- package/dist/plugin/utils/createReactFetcher.d.ts.map +1 -0
- package/dist/plugin/utils/createReactFetcher.js +33 -0
- package/dist/plugin/utils/createReactFetcher.js.map +1 -0
- package/dist/plugin/utils/index.d.ts +4 -0
- package/dist/plugin/utils/index.d.ts.map +1 -0
- package/dist/plugin/utils/index.js +3 -0
- package/dist/plugin/utils/pageURL.d.ts +2 -0
- package/dist/plugin/utils/pageURL.d.ts.map +1 -0
- package/dist/plugin/utils/pageURL.js +21 -0
- package/dist/plugin/utils/pageURL.js.map +1 -0
- package/dist/plugin/utils.js +9 -0
- package/dist/plugin/utils.js.map +1 -0
- package/dist/plugin/worker/rsc/handleRender.d.ts +6 -2
- package/dist/plugin/worker/rsc/handleRender.d.ts.map +1 -1
- package/dist/plugin/worker/rsc/handleRender.js +26 -55
- package/dist/plugin/worker/rsc/handleRender.js.map +1 -1
- package/dist/plugin/worker/rsc/messageHandler.d.ts +1 -2
- package/dist/plugin/worker/rsc/messageHandler.d.ts.map +1 -1
- package/dist/plugin/worker/rsc/messageHandler.js +45 -2
- package/dist/plugin/worker/rsc/messageHandler.js.map +1 -1
- package/dist/plugin/worker/rsc/state.d.ts.map +1 -1
- package/dist/plugin/worker/rsc/state.js +1 -5
- package/dist/plugin/worker/rsc/state.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -5
- package/plugin/config/defaults.tsx +1 -1
- package/plugin/config/resolveAutoDiscover.ts +17 -22
- package/plugin/config/resolveOptions.ts +5 -1
- package/plugin/config/resolveUserConfig.ts +72 -37
- package/plugin/helpers/collectBundleManifestCss.ts +1 -160
- package/plugin/helpers/collectViteModuleGraphCss.ts +31 -29
- package/plugin/helpers/createCssProps.tsx +22 -11
- package/plugin/helpers/createRscStream.tsx +42 -46
- package/plugin/helpers/formatMetrics.ts +37 -0
- package/plugin/helpers/tryManifest.ts +0 -9
- package/plugin/html.tsx +1 -1
- package/plugin/loader/createBuildLoader.ts +2 -0
- package/plugin/metrics/formatMetrics.ts +37 -0
- package/plugin/metrics/index.ts +2 -0
- package/plugin/react-client/createWorkerStream.ts +107 -0
- package/plugin/react-client/plugin.ts +3 -0
- package/plugin/react-client/restartWorker.ts +65 -0
- package/plugin/react-client/server.ts +97 -146
- package/plugin/react-server/server.ts +24 -29
- package/plugin/react-static/collectHtmlWorkerContent.ts +1 -1
- package/plugin/react-static/collectRscContent.ts +2 -2
- package/plugin/react-static/configurePreviewServer.ts +29 -6
- package/plugin/react-static/fileWriter.ts +5 -1
- package/plugin/react-static/plugin.ts +58 -38
- package/plugin/types.ts +11 -11
- package/plugin/utils/callServer.ts +25 -0
- package/plugin/utils/createReactFetcher.ts +31 -0
- package/plugin/utils/index.ts +3 -0
- package/plugin/utils/pageURL.ts +28 -0
- package/plugin/worker/rsc/handleRender.ts +33 -71
- package/plugin/worker/rsc/messageHandler.tsx +48 -6
- package/plugin/worker/rsc/state.ts +1 -5
|
@@ -28,7 +28,7 @@ export async function collectRscContent(
|
|
|
28
28
|
handlerOptions: CreateHandlerOptions
|
|
29
29
|
): Promise<{ stream: PassThrough; metrics: StreamMetrics }> {
|
|
30
30
|
const metrics = createStreamMetrics();
|
|
31
|
-
const startTime = performance.now()
|
|
31
|
+
const startTime = performance.now();
|
|
32
32
|
|
|
33
33
|
const outputPath = join(
|
|
34
34
|
handlerOptions.build.outDir,
|
|
@@ -49,7 +49,7 @@ export async function collectRscContent(
|
|
|
49
49
|
callback(null, chunk);
|
|
50
50
|
},
|
|
51
51
|
flush(callback) {
|
|
52
|
-
metrics.duration =
|
|
52
|
+
metrics.duration = performance.now() - startTime;
|
|
53
53
|
callback();
|
|
54
54
|
}
|
|
55
55
|
});
|
|
@@ -16,12 +16,15 @@ export async function configurePreviewServer({
|
|
|
16
16
|
const staticHostDir = join(userOptions.projectRoot, userOptions.build.outDir, userOptions.build.static);
|
|
17
17
|
server.middlewares.use(async (req, res, next) => {
|
|
18
18
|
if(!req.url) {
|
|
19
|
+
console.log("no url")
|
|
19
20
|
return next();
|
|
20
21
|
}
|
|
21
|
-
const [
|
|
22
|
+
const [withoutQuery] = req.url.split("?");
|
|
23
|
+
const [, value] = userOptions.normalizer(withoutQuery);
|
|
24
|
+
const ext = value.slice(value.lastIndexOf("."));
|
|
22
25
|
// handle index.html
|
|
23
26
|
const isHtml = userOptions.autoDiscover.htmlPattern(value)
|
|
24
|
-
if (isHtml || req.headers.accept?.includes("text/html")) {
|
|
27
|
+
if (isHtml || (req.headers.accept?.includes("text/html"))) {
|
|
25
28
|
const indexHtml = isHtml ? join(staticHostDir, value) : join(staticHostDir, value, userOptions.build.htmlOutputPath);
|
|
26
29
|
try {
|
|
27
30
|
const stats = await stat(indexHtml);
|
|
@@ -35,7 +38,7 @@ export async function configurePreviewServer({
|
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
const isRsc = userOptions.autoDiscover.rscPattern(value)
|
|
38
|
-
if (isRsc || req.headers.accept?.includes("text/x-component")) {
|
|
41
|
+
if (isRsc || (req.headers.accept?.includes("text/x-component"))) {
|
|
39
42
|
const rsc = isRsc ? join(staticHostDir, value) : join(staticHostDir, value, userOptions.build.rscOutputPath);
|
|
40
43
|
try {
|
|
41
44
|
const stats = await stat(rsc);
|
|
@@ -48,14 +51,34 @@ export async function configurePreviewServer({
|
|
|
48
51
|
// File doesn't exist, continue to next middleware
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
|
-
const
|
|
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
|
+
}
|
|
68
|
+
// Handle static files including CSS
|
|
52
69
|
if (ext) {
|
|
53
70
|
const filePath = join(staticHostDir, value);
|
|
54
71
|
try {
|
|
55
72
|
const stats = await stat(filePath);
|
|
56
73
|
if (stats.isFile()) {
|
|
57
|
-
|
|
58
|
-
|
|
74
|
+
// Set proper MIME type based on file extension
|
|
75
|
+
const contentType = MIME_TYPES[ext];
|
|
76
|
+
// Ensure CSS files are served with the correct MIME type
|
|
77
|
+
if (contentType) {
|
|
78
|
+
res.setHeader("Content-Type", `${contentType}; charset=utf-8`);
|
|
79
|
+
} else {
|
|
80
|
+
res.setHeader("Content-Type", "application/octet-stream");
|
|
81
|
+
}
|
|
59
82
|
await pipeline(createReadStream(filePath), res);
|
|
60
83
|
return;
|
|
61
84
|
}
|
|
@@ -43,7 +43,11 @@ export async function fileWriter(
|
|
|
43
43
|
);
|
|
44
44
|
|
|
45
45
|
// Ensure directory exists
|
|
46
|
-
|
|
46
|
+
try {
|
|
47
|
+
await mkdir(join(options.build.outDir, options.build.static, options.route), { recursive: true });
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(`Error creating directory: ${error}`);
|
|
50
|
+
}
|
|
47
51
|
|
|
48
52
|
// Create write stream
|
|
49
53
|
const writeStream = createWriteStream(outputPath);
|
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
import { collectManifestCss } from "../helpers/collectManifestCss.js";
|
|
49
49
|
import { createCssProps } from "../helpers/createCssProps.js";
|
|
50
50
|
import { tryManifest } from "../helpers/tryManifest.js";
|
|
51
|
+
import { performance } from "node:perf_hooks";
|
|
51
52
|
|
|
52
53
|
if (getCondition() !== "react-server") {
|
|
53
54
|
throw new Error(
|
|
@@ -138,7 +139,6 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
138
139
|
timing.renderStart = Date.now();
|
|
139
140
|
},
|
|
140
141
|
|
|
141
|
-
|
|
142
142
|
async writeBundle(options, bundle) {
|
|
143
143
|
try {
|
|
144
144
|
const bundleManifest = getBundleManifest<false>({
|
|
@@ -159,10 +159,7 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
159
159
|
|
|
160
160
|
const clientManifestResult = await tryManifest({
|
|
161
161
|
root: userOptions.projectRoot,
|
|
162
|
-
outDir: join(
|
|
163
|
-
userOptions.build.outDir,
|
|
164
|
-
userOptions.build.client
|
|
165
|
-
),
|
|
162
|
+
outDir: join(userOptions.build.outDir, userOptions.build.client),
|
|
166
163
|
ssrManifest: false,
|
|
167
164
|
});
|
|
168
165
|
if (clientManifestResult.type === "error") {
|
|
@@ -195,15 +192,29 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
195
192
|
// Collect CSS files for each page and its props
|
|
196
193
|
for (const [url, { page, props }] of autoDiscoveredFiles?.urlMap ??
|
|
197
194
|
[]) {
|
|
195
|
+
const transformedServerManifest = Object.fromEntries(
|
|
196
|
+
Object.entries(serverManifest).map(([key, value]) => {
|
|
197
|
+
if (!value.css?.length) {
|
|
198
|
+
return [key, value];
|
|
199
|
+
}
|
|
200
|
+
return [
|
|
201
|
+
key,
|
|
202
|
+
{
|
|
203
|
+
...value,
|
|
204
|
+
css:
|
|
205
|
+
autoDiscoveredFiles?.staticManifest[key]?.css ?? value.css,
|
|
206
|
+
},
|
|
207
|
+
];
|
|
208
|
+
})
|
|
209
|
+
);
|
|
198
210
|
const cssInputs = collectManifestCss(
|
|
199
|
-
|
|
211
|
+
transformedServerManifest,
|
|
200
212
|
props ? [page, props] : page,
|
|
201
213
|
userOptions
|
|
202
214
|
);
|
|
203
215
|
|
|
204
216
|
// Create a map for this page's CSS files
|
|
205
217
|
const pageCssMap: Map<string, CssContent> = new Map();
|
|
206
|
-
|
|
207
218
|
// Add global styles if they exist
|
|
208
219
|
if (Object.keys(globalCssInputs).length > 0) {
|
|
209
220
|
for (const [, value] of Object.entries(globalCssInputs)) {
|
|
@@ -219,11 +230,7 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
219
230
|
createCssProps({
|
|
220
231
|
id: value,
|
|
221
232
|
code: cssContent,
|
|
222
|
-
|
|
223
|
-
moduleBaseURL: userOptions.moduleBaseURL,
|
|
224
|
-
moduleBasePath: userOptions.moduleBasePath,
|
|
225
|
-
moduleRootPath: userOptions.moduleRootPath,
|
|
226
|
-
projectRoot: userOptions.projectRoot,
|
|
233
|
+
userOptions: userOptions,
|
|
227
234
|
})
|
|
228
235
|
);
|
|
229
236
|
}
|
|
@@ -232,25 +239,28 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
232
239
|
|
|
233
240
|
// Add page-specific styles
|
|
234
241
|
for (const [, value] of Object.entries(cssInputs)) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
if (typeof cssContent !== "string") {
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
if (cssContent) {
|
|
242
|
-
pageCssMap.set(
|
|
243
|
-
value,
|
|
244
|
-
createCssProps({
|
|
245
|
-
id: value,
|
|
246
|
-
code: cssContent,
|
|
247
|
-
css: userOptions.css,
|
|
248
|
-
moduleBaseURL: userOptions.moduleBaseURL,
|
|
249
|
-
moduleBasePath: userOptions.moduleBasePath,
|
|
250
|
-
moduleRootPath: userOptions.moduleRootPath,
|
|
251
|
-
projectRoot: userOptions.projectRoot,
|
|
252
|
-
})
|
|
242
|
+
try {
|
|
243
|
+
const { default: cssContent } = await buildLoader(
|
|
244
|
+
value + "?inline"
|
|
253
245
|
);
|
|
246
|
+
if (typeof cssContent !== "string") {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (cssContent) {
|
|
250
|
+
// Ensure the CSS file path is properly resolved
|
|
251
|
+
const cssPath = value.startsWith("/") ? value.slice(1) : value;
|
|
252
|
+
pageCssMap.set(
|
|
253
|
+
cssPath,
|
|
254
|
+
createCssProps({
|
|
255
|
+
id: cssPath,
|
|
256
|
+
code: cssContent,
|
|
257
|
+
userOptions: userOptions,
|
|
258
|
+
})
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.warn(`Failed to process CSS file ${value}:`, error);
|
|
263
|
+
continue;
|
|
254
264
|
}
|
|
255
265
|
}
|
|
256
266
|
cssFilesByPage.set(url, pageCssMap);
|
|
@@ -269,17 +279,19 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
269
279
|
}
|
|
270
280
|
const staticManifest = autoDiscoveredFiles?.staticManifest ?? {};
|
|
271
281
|
const indexHtml = staticManifest?.["index.html"]?.file;
|
|
282
|
+
const safeParseURL = (() => {
|
|
283
|
+
try {
|
|
284
|
+
return new URL(join(userOptions.moduleBasePath, indexHtml), userOptions.moduleBaseURL).href;
|
|
285
|
+
} catch (error) {
|
|
286
|
+
return userOptions.moduleBaseURL + join(userOptions.moduleBasePath, indexHtml);
|
|
287
|
+
}
|
|
288
|
+
})();
|
|
272
289
|
const pipeableStreamOptions = {
|
|
273
290
|
...userOptions.pipeableStreamOptions,
|
|
274
291
|
bootstrapModules: [
|
|
275
|
-
...(
|
|
292
|
+
...(safeParseURL
|
|
276
293
|
? [
|
|
277
|
-
|
|
278
|
-
? new URL(
|
|
279
|
-
join(userOptions.moduleBasePath, indexHtml),
|
|
280
|
-
userOptions.moduleBaseURL
|
|
281
|
-
).href
|
|
282
|
-
: join(userOptions.moduleBasePath, indexHtml),
|
|
294
|
+
safeParseURL,
|
|
283
295
|
]
|
|
284
296
|
: []),
|
|
285
297
|
...(userOptions.pipeableStreamOptions?.bootstrapModules ?? []),
|
|
@@ -292,12 +304,20 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
|
|
|
292
304
|
);
|
|
293
305
|
// Create worker
|
|
294
306
|
if (!worker) {
|
|
295
|
-
const viteEnvPrefix =
|
|
307
|
+
const viteEnvPrefix =
|
|
308
|
+
typeof resolvedConfig.envPrefix === "string"
|
|
309
|
+
? resolvedConfig.envPrefix
|
|
310
|
+
: Array.isArray(resolvedConfig.envPrefix)
|
|
311
|
+
? resolvedConfig.envPrefix[0]
|
|
312
|
+
: "VITE_";
|
|
313
|
+
const routeCount = autoDiscoveredFiles?.urlMap.size ?? 0;
|
|
314
|
+
const maxListeners = routeCount + 1;
|
|
296
315
|
const workerResult = await createWorker({
|
|
297
316
|
projectRoot: userOptions.projectRoot,
|
|
298
317
|
workerPath: userOptions.htmlWorkerPath,
|
|
299
318
|
currentCondition: "react-server",
|
|
300
319
|
reverseCondition: "react-client",
|
|
320
|
+
maxListeners: maxListeners,
|
|
301
321
|
envPrefix: viteEnvPrefix,
|
|
302
322
|
workerData: {
|
|
303
323
|
resolvedConfig: serializeResolvedConfig(resolvedConfig),
|
package/plugin/types.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
+
import { Readable } from "node:stream";
|
|
2
|
+
import type { MessagePort } from "node:worker_threads";
|
|
3
|
+
import type React from "react";
|
|
4
|
+
import type { PropsWithChildren } from "react";
|
|
1
5
|
import type {
|
|
2
6
|
NormalizedOutputOptions,
|
|
3
7
|
OutputBundle,
|
|
8
|
+
PreRenderedAsset,
|
|
4
9
|
PreRenderedChunk,
|
|
5
10
|
} from "rollup";
|
|
6
|
-
import type {
|
|
11
|
+
import type { PassThrough, Transform } from "stream";
|
|
7
12
|
import type {
|
|
8
|
-
UserConfig,
|
|
9
|
-
BuildOptions,
|
|
10
|
-
InlineConfig,
|
|
11
13
|
AliasOptions,
|
|
14
|
+
BuildOptions,
|
|
12
15
|
Connect,
|
|
13
|
-
|
|
14
|
-
Manifest,
|
|
16
|
+
InlineConfig,
|
|
15
17
|
Logger,
|
|
18
|
+
Manifest,
|
|
19
|
+
ResolveOptions,
|
|
20
|
+
UserConfig,
|
|
16
21
|
} from "vite";
|
|
17
22
|
import type { ReactServerDomEsmOptions } from "./worker/types.js";
|
|
18
|
-
import type React from "react";
|
|
19
|
-
import type { PassThrough, Transform } from "stream";
|
|
20
|
-
import type { MessagePort } from "node:worker_threads";
|
|
21
|
-
import type { PropsWithChildren } from "react";
|
|
22
|
-
import { Readable } from "node:stream";
|
|
23
23
|
|
|
24
24
|
export type OnEvent = (event: PluginEvent) => void;
|
|
25
25
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { createFromFetch, encodeReply } from "react-server-dom-esm/client.browser";
|
|
3
|
+
|
|
4
|
+
type ServerResponse = { returnValue: unknown };
|
|
5
|
+
|
|
6
|
+
export const callServer = async (
|
|
7
|
+
id: string,
|
|
8
|
+
args: unknown[]
|
|
9
|
+
): Promise<unknown> => {
|
|
10
|
+
let baseURL = import.meta.env.BASE_URL
|
|
11
|
+
const response = await createFromFetch(
|
|
12
|
+
fetch(baseURL, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
body: await encodeReply(args),
|
|
15
|
+
headers: {
|
|
16
|
+
Accept: "application/json",
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
},
|
|
19
|
+
}),
|
|
20
|
+
{ callServer, moduleBaseURL: baseURL }
|
|
21
|
+
);
|
|
22
|
+
const returnValue = (response as ServerResponse).returnValue;
|
|
23
|
+
return returnValue;
|
|
24
|
+
};
|
|
25
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
// @ts-ignore
|
|
3
|
+
import { createFromFetch } from "react-server-dom-esm/client.browser";
|
|
4
|
+
import { callServer } from "./callServer.js";
|
|
5
|
+
import { pageURL } from "./pageURL.js";
|
|
6
|
+
|
|
7
|
+
export function createReactFetcher({
|
|
8
|
+
url = pageURL().pathname,
|
|
9
|
+
moduleBaseURL = new URL(import.meta.env.BASE_URL, window.location.href).href,
|
|
10
|
+
headers = {
|
|
11
|
+
Accept: "text/x-component",
|
|
12
|
+
},
|
|
13
|
+
}: {
|
|
14
|
+
url?: string;
|
|
15
|
+
moduleBaseURL?: string;
|
|
16
|
+
headers?: HeadersInit;
|
|
17
|
+
} = {}): Promise<ReactNode> {
|
|
18
|
+
if(moduleBaseURL.endsWith("/")) {
|
|
19
|
+
moduleBaseURL = moduleBaseURL.slice(0, -1)
|
|
20
|
+
}
|
|
21
|
+
console.log("createReactFetcher", {url, moduleBaseURL})
|
|
22
|
+
return createFromFetch(
|
|
23
|
+
fetch(url, {
|
|
24
|
+
headers: headers,
|
|
25
|
+
}),
|
|
26
|
+
{
|
|
27
|
+
callServer: callServer,
|
|
28
|
+
moduleBaseURL:moduleBaseURL,
|
|
29
|
+
}
|
|
30
|
+
) as Promise<ReactNode>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const pageURL = () => {
|
|
2
|
+
const pathname = window.location.pathname;
|
|
3
|
+
const baseUrl = import.meta.env.BASE_URL;
|
|
4
|
+
|
|
5
|
+
// Remove base URL from pathname if it exists
|
|
6
|
+
const relativePath = pathname.startsWith(baseUrl)
|
|
7
|
+
? pathname.slice(baseUrl.length)
|
|
8
|
+
: pathname;
|
|
9
|
+
|
|
10
|
+
// Handle root path and index.html
|
|
11
|
+
if (relativePath === '/' || relativePath === '' || relativePath === '/index.html' || relativePath === 'index.html') {
|
|
12
|
+
return new URL('/index.rsc', window.location.origin);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Get the path without extension and remove any trailing index
|
|
16
|
+
const pathWithoutExt = relativePath
|
|
17
|
+
.replace(/\.(html|rsc)$/, '')
|
|
18
|
+
.replace(/\/index$/, '');
|
|
19
|
+
|
|
20
|
+
// Construct the RSC path
|
|
21
|
+
const rscPath = pathWithoutExt === '' ? '/index.rsc' : `${pathWithoutExt}/index.rsc`;
|
|
22
|
+
|
|
23
|
+
// Ensure no double slashes and ensure leading slash
|
|
24
|
+
const cleanPath = ('/' + rscPath.replace(/\/+/g, '/')).replace(/\/+/g, '/');
|
|
25
|
+
|
|
26
|
+
console.log("cleanPath", {cleanPath, rscPath, pathWithoutExt, relativePath, baseUrl, pathname})
|
|
27
|
+
return new URL(cleanPath, window.location.origin);
|
|
28
|
+
};
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
RscChunkOutputMessage,
|
|
3
|
-
RscEndMessage,
|
|
4
|
-
RscMetricsMessage,
|
|
5
|
-
RscWorkerOutputMessage,
|
|
6
|
-
} from "../types.js";
|
|
7
1
|
import { resolvePageAndProps } from "../../helpers/resolvePageAndProps.js";
|
|
8
2
|
import type { RscRenderMessage } from "../types.js";
|
|
9
3
|
import { activeStreams, cssFiles } from "./state.js";
|
|
@@ -11,43 +5,20 @@ import { createRscStream } from "../../helpers/createRscStream.js";
|
|
|
11
5
|
import { CssCollector } from "../../css-collector.js";
|
|
12
6
|
import { PassThrough } from "node:stream";
|
|
13
7
|
import { join } from "node:path";
|
|
14
|
-
import {
|
|
8
|
+
import { workerData } from "node:worker_threads";
|
|
15
9
|
import { React } from "../../vendor.server.js";
|
|
16
10
|
import { hmrState } from "./state.js";
|
|
17
|
-
|
|
11
|
+
import { performance } from "node:perf_hooks";
|
|
18
12
|
|
|
19
13
|
export async function handleRender(
|
|
20
14
|
msg: RscRenderMessage,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
handlers: {
|
|
16
|
+
onError: (error: any, errorInfo?: any) => void;
|
|
17
|
+
onData: (data: any) => void;
|
|
18
|
+
onEnd: () => void;
|
|
19
|
+
onMetrics: (metrics: any) => void;
|
|
20
|
+
}
|
|
24
21
|
) {
|
|
25
|
-
const postError = process.env["DEV"]
|
|
26
|
-
? (error: any, errorInfo?: any) => {
|
|
27
|
-
if (!(error instanceof Error)) {
|
|
28
|
-
error = new Error(String(error));
|
|
29
|
-
}
|
|
30
|
-
port?.postMessage({
|
|
31
|
-
type: "ERROR",
|
|
32
|
-
id: msg.id,
|
|
33
|
-
errorInfo,
|
|
34
|
-
error: {
|
|
35
|
-
message: error.message,
|
|
36
|
-
stack: error.stack,
|
|
37
|
-
name: error.name,
|
|
38
|
-
cause: error.cause,
|
|
39
|
-
},
|
|
40
|
-
} satisfies RscWorkerOutputMessage);
|
|
41
|
-
}
|
|
42
|
-
: (error: Error, errorInfo?: any) => {
|
|
43
|
-
port?.postMessage({
|
|
44
|
-
type: "ERROR",
|
|
45
|
-
id: msg.id,
|
|
46
|
-
errorInfo,
|
|
47
|
-
error: error.message,
|
|
48
|
-
} satisfies RscWorkerOutputMessage);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
22
|
let {
|
|
52
23
|
id = workerData.id,
|
|
53
24
|
route = workerData.route,
|
|
@@ -73,30 +44,30 @@ export async function handleRender(
|
|
|
73
44
|
pageExportName,
|
|
74
45
|
propsExportName,
|
|
75
46
|
route,
|
|
76
|
-
loader:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
47
|
+
loader: (id: string) => {
|
|
48
|
+
try {
|
|
49
|
+
if (hmrState.get(id)?.invalidated) {
|
|
50
|
+
// Clear the HMR state for this module
|
|
51
|
+
hmrState.delete(id);
|
|
52
|
+
// Force a reload by using a unique query parameter
|
|
53
|
+
return import(join(projectRoot, id) + `?t=${Date.now()}`);
|
|
54
|
+
}
|
|
55
|
+
return import(join(projectRoot, id));
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return Promise.reject(error);
|
|
83
58
|
}
|
|
84
|
-
return import(join(projectRoot, id));
|
|
85
59
|
},
|
|
86
60
|
});
|
|
87
|
-
|
|
88
61
|
if (pageAndPropsResult.type !== "success") {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
return;
|
|
62
|
+
const { error, ...rest } = pageAndPropsResult;
|
|
63
|
+
return handlers.onError(error, rest);
|
|
93
64
|
}
|
|
94
65
|
|
|
95
66
|
const { PageComponent, pageProps } = pageAndPropsResult;
|
|
96
67
|
|
|
97
68
|
const adaptedOnEvent = (event: "error" | "postpone", data: any) => {
|
|
98
69
|
if (event === "error") {
|
|
99
|
-
|
|
70
|
+
handlers.onError(data.error, data.errorInfo);
|
|
100
71
|
}
|
|
101
72
|
};
|
|
102
73
|
|
|
@@ -128,7 +99,7 @@ export async function handleRender(
|
|
|
128
99
|
});
|
|
129
100
|
|
|
130
101
|
if (streamResult.type !== "success") {
|
|
131
|
-
|
|
102
|
+
handlers.onError(streamResult.error);
|
|
132
103
|
return;
|
|
133
104
|
}
|
|
134
105
|
|
|
@@ -143,38 +114,29 @@ export async function handleRender(
|
|
|
143
114
|
|
|
144
115
|
// Handle data chunks
|
|
145
116
|
passThrough.on("data", (chunk) => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
} satisfies RscChunkOutputMessage);
|
|
117
|
+
metrics.chunks++;
|
|
118
|
+
metrics.bytes += chunk.length;
|
|
119
|
+
metrics.duration = performance.now() - metrics.startTime;
|
|
120
|
+
handlers.onData(chunk);
|
|
151
121
|
});
|
|
152
122
|
|
|
153
123
|
// Handle stream end
|
|
154
124
|
passThrough.on("end", () => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
id,
|
|
158
|
-
} satisfies RscEndMessage);
|
|
125
|
+
metrics.duration = performance.now() - metrics.startTime;
|
|
126
|
+
handlers.onEnd();
|
|
159
127
|
if (activeStreams.has(id)) {
|
|
160
|
-
|
|
161
|
-
type: "RSC_METRICS",
|
|
162
|
-
id,
|
|
163
|
-
metrics,
|
|
164
|
-
} satisfies RscMetricsMessage);
|
|
128
|
+
handlers.onMetrics(metrics);
|
|
165
129
|
activeStreams.delete(id);
|
|
166
130
|
}
|
|
167
131
|
});
|
|
168
132
|
|
|
169
133
|
// Handle errors
|
|
170
134
|
passThrough.on("error", (error) => {
|
|
171
|
-
|
|
135
|
+
handlers.onError(error as Error, { reason: `${id} stream error` });
|
|
172
136
|
activeStreams.delete(id);
|
|
173
137
|
});
|
|
174
138
|
} catch (error) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
postError(error as Error);
|
|
139
|
+
handlers.onError(error as Error, { reason: `${id} render error` });
|
|
140
|
+
return Promise.reject(error);
|
|
179
141
|
}
|
|
180
142
|
}
|
|
@@ -1,19 +1,60 @@
|
|
|
1
|
-
import { parentPort, workerData
|
|
1
|
+
import { parentPort, workerData } from "node:worker_threads";
|
|
2
2
|
import { addCssFileContent, hmrState } from "./state.js";
|
|
3
3
|
import { handleRender } from "./handleRender.js";
|
|
4
|
+
import type { RscWorkerOutputMessage } from "../types.js";
|
|
4
5
|
|
|
5
|
-
export function messageHandler(
|
|
6
|
+
export async function messageHandler(
|
|
6
7
|
msg: any,
|
|
7
8
|
port = parentPort,
|
|
8
|
-
reactLoaderPort: MessagePort,
|
|
9
|
-
cssLoaderPort: MessagePort
|
|
10
9
|
) {
|
|
11
10
|
if (!port) {
|
|
12
11
|
throw new Error("No port found");
|
|
13
12
|
}
|
|
13
|
+
const handlers = {
|
|
14
|
+
onError: (error: any, errorInfo?: any) => {
|
|
15
|
+
if (!(error instanceof Error)) {
|
|
16
|
+
error = new Error(String(error));
|
|
17
|
+
}
|
|
18
|
+
port.postMessage({
|
|
19
|
+
type: "ERROR",
|
|
20
|
+
id: msg.id,
|
|
21
|
+
errorInfo,
|
|
22
|
+
error: {
|
|
23
|
+
message: error.message,
|
|
24
|
+
stack: error.stack,
|
|
25
|
+
name: error.name,
|
|
26
|
+
cause: error.cause,
|
|
27
|
+
},
|
|
28
|
+
} satisfies RscWorkerOutputMessage);
|
|
29
|
+
port.postMessage({
|
|
30
|
+
type: "RSC_END",
|
|
31
|
+
id: msg.id,
|
|
32
|
+
} satisfies RscWorkerOutputMessage);
|
|
33
|
+
},
|
|
34
|
+
onData: (data: any) => {
|
|
35
|
+
port.postMessage({
|
|
36
|
+
type: "RSC_CHUNK",
|
|
37
|
+
id: msg.id,
|
|
38
|
+
chunk: data,
|
|
39
|
+
} satisfies RscWorkerOutputMessage);
|
|
40
|
+
},
|
|
41
|
+
onEnd: () => {
|
|
42
|
+
port.postMessage({
|
|
43
|
+
type: "RSC_END",
|
|
44
|
+
id: msg.id,
|
|
45
|
+
} satisfies RscWorkerOutputMessage);
|
|
46
|
+
},
|
|
47
|
+
onMetrics: (metrics: any) => {
|
|
48
|
+
port.postMessage({
|
|
49
|
+
type: "RSC_METRICS",
|
|
50
|
+
id: msg.id,
|
|
51
|
+
metrics,
|
|
52
|
+
} satisfies RscWorkerOutputMessage);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
14
55
|
switch (msg.type) {
|
|
15
56
|
case "RSC_RENDER":
|
|
16
|
-
return handleRender(msg,
|
|
57
|
+
return await handleRender(msg, handlers);
|
|
17
58
|
case "INITIALIZED_REACT_LOADER":
|
|
18
59
|
return;
|
|
19
60
|
case "INITIALIZED_CSS_LOADER":
|
|
@@ -46,7 +87,7 @@ export function messageHandler(
|
|
|
46
87
|
const cssOptions = workerData.userOptions.css || {
|
|
47
88
|
inlineThreshold: 1000,
|
|
48
89
|
};
|
|
49
|
-
|
|
90
|
+
|
|
50
91
|
addCssFileContent(msg.id, msg.content, {
|
|
51
92
|
projectRoot: workerData.userOptions.projectRoot || process.cwd(),
|
|
52
93
|
moduleBaseURL: workerData.userOptions.moduleBaseURL || "",
|
|
@@ -57,6 +98,7 @@ export function messageHandler(
|
|
|
57
98
|
}
|
|
58
99
|
return;
|
|
59
100
|
default: {
|
|
101
|
+
console.log("messageHandler", { msg: msg.type });
|
|
60
102
|
return;
|
|
61
103
|
}
|
|
62
104
|
}
|
|
@@ -70,11 +70,7 @@ export function addCssFileContent(id: string, code: string, userOptions: Pick<Re
|
|
|
70
70
|
cssFiles.set(normalizeId, createCssProps({
|
|
71
71
|
id,
|
|
72
72
|
code,
|
|
73
|
-
|
|
74
|
-
moduleBaseURL: userOptions.moduleBaseURL,
|
|
75
|
-
moduleBasePath: userOptions.moduleBasePath,
|
|
76
|
-
moduleRootPath: userOptions.moduleRootPath,
|
|
77
|
-
css: userOptions.css,
|
|
73
|
+
userOptions
|
|
78
74
|
}));
|
|
79
75
|
}
|
|
80
76
|
|