vite-plugin-react-server 0.3.12 → 0.3.14

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.
@@ -32,6 +32,7 @@ import { createHandler } from "./createHandler.js";
32
32
  import { mkdir, readFile, writeFile } from "node:fs/promises";
33
33
  import { getBundleManifest } from "../helpers/getBundleManifest.js";
34
34
  import type { ServerResponse } from "node:http";
35
+ import { collectManifestCss } from "../collect-css-manifest.js";
35
36
 
36
37
  let resolvedConfig: ResolvedConfig | null = null;
37
38
  let serverManifestPath: string | null = null;
@@ -145,9 +146,7 @@ export function reactServerPlugin(
145
146
  );
146
147
  }
147
148
  },
148
- async configurePreviewServer(server) {
149
-
150
- },
149
+ async configurePreviewServer(server) {},
151
150
  async configureServer(server: ViteDevServer) {
152
151
  if (typeof loader !== "function") {
153
152
  loader = server.ssrLoadModule;
@@ -166,7 +165,6 @@ export function reactServerPlugin(
166
165
  root = server.config.root;
167
166
  }
168
167
 
169
-
170
168
  const activeStreams = new Set<ServerResponse>();
171
169
 
172
170
  // Handle Vite server restarts
@@ -308,7 +306,9 @@ export function reactServerPlugin(
308
306
  // Create the loader
309
307
  if (typeof loader !== "function") {
310
308
  if (!Object.keys(serverManifest).length) {
311
- console.warn("[vite-plugin-react-server] No server manifest found, the plugin will try to use the plugin context - it may differ from vite's manifest.");
309
+ console.warn(
310
+ "[vite-plugin-react-server] No server manifest found, the plugin will try to use the plugin context - it may differ from vite's manifest."
311
+ );
312
312
  serverManifest = getBundleManifest({
313
313
  pluginContext: this,
314
314
  bundle: outpuptBundle,
@@ -316,15 +316,22 @@ export function reactServerPlugin(
316
316
  preserveModulesRoot: userOptions.build.preserveModulesRoot,
317
317
  });
318
318
  if (!Object.keys(serverManifest).length) {
319
- console.warn("[vite-plugin-react-server] That didn't work, retrying to read manifest.");
319
+ console.warn(
320
+ "[vite-plugin-react-server] That didn't work, retrying to read manifest."
321
+ );
320
322
  const resolvedServerManifest = tryManifest({
321
323
  root: root,
322
- outDir: join(userOptions.build.outDir, userOptions.build.server),
324
+ outDir: join(
325
+ userOptions.build.outDir,
326
+ userOptions.build.server
327
+ ),
323
328
  ssrManifest: false,
324
329
  });
325
330
  if (resolvedServerManifest.type === "error") {
326
331
  // dont build the static files without a server manifest
327
- console.error("[vite-plugin-react-server] Failed to read manifest, aborting build.");
332
+ console.error(
333
+ "[vite-plugin-react-server] Failed to read manifest, aborting build."
334
+ );
328
335
  return;
329
336
  }
330
337
  serverManifest = resolvedServerManifest.manifest;
@@ -343,34 +350,73 @@ export function reactServerPlugin(
343
350
  if (resolvedPages.type === "error") {
344
351
  throw resolvedPages.error;
345
352
  }
353
+
354
+ const onCssFile = async (path: string, parentUrl: string) => {
355
+ if (buildCssFiles && path.endsWith(".css")) {
356
+ buildCssFiles.add(path);
357
+ if (parentUrl.endsWith(userOptions.build.client)) {
358
+ // copy the file to the client build dir
359
+ const serverPath = join(
360
+ userOptions.build.outDir,
361
+ userOptions.build.server,
362
+ path
363
+ );
364
+ await writeFile(
365
+ serverPath,
366
+ await readFile(
367
+ join(
368
+ root,
369
+ userOptions.build.outDir,
370
+ userOptions.build.client,
371
+ path
372
+ )
373
+ )
374
+ );
375
+ } else {
376
+ // copy the file to the client build dir, assume it's in server build dir
377
+ const clientPath = join(
378
+ userOptions.build.outDir,
379
+ userOptions.build.client,
380
+ path
381
+ );
382
+ await mkdir(dirname(clientPath), { recursive: true });
383
+ await writeFile(
384
+ clientPath,
385
+ await readFile(
386
+ join(
387
+ root,
388
+ userOptions.build.outDir,
389
+ userOptions.build.server,
390
+ path
391
+ )
392
+ )
393
+ );
394
+ }
395
+ }
396
+ };
397
+
346
398
  const { failedRoutes, completedRoutes } = await renderPages(
347
399
  this,
348
400
  resolvedPages.pages,
349
401
  files,
350
402
  {
351
- pipableStreamOptions: {},
403
+ pipableStreamOptions: {
404
+ bootstrapModules: clientManifest["index.html"]?.file
405
+ ? [clientManifest["index.html"].file]
406
+ : [],
407
+ },
352
408
  moduleBasePath: "",
353
409
  moduleBaseURL: "",
354
- clientCss:
355
- Object.values(clientManifest)
356
- .flatMap((entry) => entry.css)
357
- .filter((css) => typeof css === "string")
358
- .map((css) => "/" + css) ?? [],
410
+ clientCss: clientManifest["index.html"]?.css
411
+ ? clientManifest["index.html"].css
412
+ : [],
359
413
  userConfig,
360
414
  pluginOptions: userOptions,
361
415
  worker: worker,
362
416
  clientManifest: clientManifest,
363
417
  serverManifest: serverManifest,
364
418
  loader,
365
- onCssFile: async (path: string) => {
366
- if (buildCssFiles && path.endsWith(".css")) {
367
- buildCssFiles.add(path);
368
- // copy the file to the client build dir
369
- const clientPath = join(userOptions.build.outDir, userOptions.build.client, path);
370
- await mkdir(dirname(clientPath), { recursive: true });
371
- await writeFile(clientPath, await readFile(join(root, userOptions.build.outDir, userOptions.build.server, path)));
372
- }
373
- },
419
+ onCssFile: onCssFile,
374
420
  }
375
421
  );
376
422
 
@@ -99,7 +99,7 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
99
99
  return null
100
100
  }
101
101
  return {
102
- code: transformed.replace(key, join(resolvedOptions.userOptions.build.client, clientPath)),
102
+ code: transformed.replace(key, clientPath),
103
103
  map: null,
104
104
  };
105
105
  },
package/plugin/types.ts CHANGED
@@ -181,7 +181,7 @@ export interface CreateHandlerOptions<T = any> {
181
181
  serverManifest?: import("vite").Manifest;
182
182
  moduleGraph?: import("vite").ModuleGraph;
183
183
  cssFiles?: string[];
184
- onCssFile?: (path: string) => void;
184
+ onCssFile?: (path: string, parentUrl: string) => void;
185
185
  logger?: import("vite").Logger;
186
186
  pipableStreamOptions?: PipeableStreamOptions;
187
187
  }
@@ -41,7 +41,7 @@ type RenderPagesOptions = {
41
41
  worker: Worker;
42
42
  pipableStreamOptions?: PipeableStreamOptions;
43
43
  loader: (id: string) => Promise<Record<string, any>>;
44
- onCssFile?: (path: string) => void;
44
+ onCssFile?: (url: string, parentUrl: string) => void;
45
45
  clientCss?: string[];
46
46
  moduleBasePath: string;
47
47
  moduleBaseURL: string;
@@ -51,14 +51,14 @@ export async function renderPages(
51
51
  pluginContext: PluginContext,
52
52
  routes: string[],
53
53
  files: CheckFilesExistReturn,
54
- options: RenderPagesOptions
54
+ options: RenderPagesOptions,
55
55
  ) {
56
56
  const root = pluginContext.environment.config.root;
57
57
  const outDir = pluginContext.environment.config.build.outDir;
58
58
  const failedRoutes = new Map<string, Error>();
59
59
  const completedRoutes = new Set<string>();
60
60
  const writePromises = new Map<string, Promise<void>>();
61
-
61
+ const clientCss = options.clientCss ?? [];
62
62
  try {
63
63
  // Set up worker message handling
64
64
  const allRoutesComplete = new Promise<void>((resolve, reject) => {
@@ -92,6 +92,19 @@ export async function renderPages(
92
92
  });
93
93
  });
94
94
 
95
+ collectManifestCss(
96
+ options.clientManifest,
97
+ options.moduleBasePath,
98
+ 'index.html',
99
+ (url, parentUrl)=>{
100
+ options?.onCssFile?.(url, parentUrl);
101
+ if(!clientCss.includes(url)){
102
+ clientCss.push(url);
103
+ }
104
+ },
105
+ join(root, options.pluginOptions.build.outDir, options.pluginOptions.build.client)
106
+ );
107
+
95
108
  // Process routes sequentially
96
109
  for (const route of routes) {
97
110
  const routeFiles = files.urlMap.get(route);
@@ -101,11 +114,16 @@ export async function renderPages(
101
114
  continue;
102
115
  }
103
116
 
104
- const cssFiles = collectManifestCss(
117
+ collectManifestCss(
105
118
  options.serverManifest,
106
119
  options.moduleBasePath,
107
120
  routeFiles.page,
108
- options.onCssFile
121
+ (url, parentUrl)=>{
122
+ options.onCssFile?.(url, parentUrl);
123
+ if(!clientCss.includes(url)){
124
+ clientCss.push(url);
125
+ }
126
+ }
109
127
  );
110
128
 
111
129
  // Create handler for pure RSC output
@@ -116,12 +134,12 @@ export async function renderPages(
116
134
  loader: options.loader,
117
135
  clientManifest: options.clientManifest,
118
136
  serverManifest: options.serverManifest,
137
+ cssFiles: clientCss,
119
138
  pipableStreamOptions: {
120
139
  ...options.pipableStreamOptions,
121
140
  importMap: {
122
141
  imports: {
123
142
  ...options.pipableStreamOptions?.importMap?.imports,
124
- ...Object.fromEntries(Array.from(cssFiles.entries()))
125
143
  }
126
144
  }
127
145
  },
@@ -132,12 +150,12 @@ export async function renderPages(
132
150
  loader: options.loader,
133
151
  clientManifest: options.clientManifest,
134
152
  serverManifest: options.serverManifest,
153
+ cssFiles: clientCss,
135
154
  pipableStreamOptions: {
136
155
  ...options.pipableStreamOptions,
137
156
  importMap: {
138
157
  imports: {
139
- ...options.pipableStreamOptions?.importMap?.imports,
140
- ...Object.fromEntries(Array.from(cssFiles.entries()))
158
+ ...options.pipableStreamOptions?.importMap?.imports
141
159
  }
142
160
  }
143
161
  },
@@ -200,7 +218,7 @@ export async function renderPages(
200
218
  type: "RSC_CHUNK",
201
219
  id: route,
202
220
  chunk: chunk.toString(),
203
- moduleRootPath: join(root, options.pluginOptions.build.outDir),
221
+ moduleRootPath: join(root, options.pluginOptions.build.outDir, options.pluginOptions.build.client),
204
222
  moduleBaseURL: options.moduleBaseURL,
205
223
  htmlOutputPath: join(options.pluginOptions.build.outDir, options.pluginOptions.build.client, route, 'index.html'),
206
224
  pipableStreamOptions: options.pipableStreamOptions,