vite-plugin-react-server 0.3.19 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +219 -141
  2. package/dist/package.json +13 -6
  3. package/dist/plugin/collect-manifest-client-files.d.ts.map +1 -1
  4. package/dist/plugin/collect-manifest-client-files.js +25 -11
  5. package/dist/plugin/collect-manifest-client-files.js.map +1 -1
  6. package/dist/plugin/components.d.ts +3 -13
  7. package/dist/plugin/components.d.ts.map +1 -1
  8. package/dist/plugin/components.js +3 -54
  9. package/dist/plugin/config/defaults.d.ts +9 -2
  10. package/dist/plugin/config/defaults.d.ts.map +1 -1
  11. package/dist/plugin/config/defaults.js +3 -2
  12. package/dist/plugin/config/defaults.js.map +1 -1
  13. package/dist/plugin/config/resolveOptions.d.ts +2 -2
  14. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  15. package/dist/plugin/config/resolveOptions.js +6 -0
  16. package/dist/plugin/config/resolveOptions.js.map +1 -1
  17. package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
  18. package/dist/plugin/config/resolveUserConfig.js +178 -149
  19. package/dist/plugin/config/resolveUserConfig.js.map +1 -1
  20. package/dist/plugin/css-collector-inline.d.ts +10 -0
  21. package/dist/plugin/css-collector-inline.d.ts.map +1 -0
  22. package/dist/plugin/css-collector-inline.js +55 -0
  23. package/dist/plugin/css-collector-inline.js.map +1 -0
  24. package/dist/plugin/css-collector.d.ts +14 -0
  25. package/dist/plugin/css-collector.d.ts.map +1 -0
  26. package/dist/plugin/css-collector.js +49 -0
  27. package/dist/plugin/css-collector.js.map +1 -0
  28. package/dist/plugin/helpers/createHandler.d.ts +3 -8
  29. package/dist/plugin/helpers/createHandler.d.ts.map +1 -1
  30. package/dist/plugin/helpers/createHandler.js +52 -55
  31. package/dist/plugin/helpers/createHandler.js.map +1 -1
  32. package/dist/plugin/helpers/createRscStream.d.ts +14 -4
  33. package/dist/plugin/helpers/createRscStream.d.ts.map +1 -1
  34. package/dist/plugin/helpers/createRscStream.js +25 -16
  35. package/dist/plugin/helpers/createRscStream.js.map +1 -1
  36. package/dist/plugin/html.d.ts +5 -0
  37. package/dist/plugin/html.d.ts.map +1 -0
  38. package/dist/plugin/html.js +11 -0
  39. package/dist/plugin/html.js.map +1 -0
  40. package/dist/plugin/react-client/plugin.d.ts.map +1 -1
  41. package/dist/plugin/react-client/plugin.js +3 -2
  42. package/dist/plugin/react-client/plugin.js.map +1 -1
  43. package/dist/plugin/react-server/plugin.d.ts.map +1 -1
  44. package/dist/plugin/react-server/plugin.js +47 -16
  45. package/dist/plugin/react-server/plugin.js.map +1 -1
  46. package/dist/plugin/react-static/plugin.d.ts.map +1 -1
  47. package/dist/plugin/react-static/plugin.js +20 -12
  48. package/dist/plugin/react-static/plugin.js.map +1 -1
  49. package/dist/plugin/react-static/types.d.ts +2 -0
  50. package/dist/plugin/react-static/types.d.ts.map +1 -0
  51. package/dist/plugin/react-static/types.js +1 -0
  52. package/dist/plugin/types.d.ts +48 -11
  53. package/dist/plugin/types.d.ts.map +1 -1
  54. package/dist/plugin/worker/html/messageHandler.d.ts.map +1 -1
  55. package/dist/plugin/worker/html/messageHandler.js +4 -1
  56. package/dist/plugin/worker/html/messageHandler.js.map +1 -1
  57. package/dist/plugin/worker/html/renderPages.d.ts +8 -25
  58. package/dist/plugin/worker/html/renderPages.d.ts.map +1 -1
  59. package/dist/plugin/worker/html/renderPages.js +61 -44
  60. package/dist/plugin/worker/html/renderPages.js.map +1 -1
  61. package/dist/plugin/worker/rsc/messageHandler.d.ts.map +1 -1
  62. package/dist/plugin/worker/rsc/messageHandler.js +37 -22
  63. package/dist/plugin/worker/rsc/messageHandler.js.map +1 -1
  64. package/dist/plugin/worker/types.d.ts +3 -0
  65. package/dist/plugin/worker/types.d.ts.map +1 -1
  66. package/dist/tsconfig.tsbuildinfo +1 -1
  67. package/package.json +12 -4
  68. package/plugin/collect-manifest-client-files.ts +25 -10
  69. package/plugin/components.ts +3 -0
  70. package/plugin/config/defaults.tsx +10 -9
  71. package/plugin/config/resolveOptions.ts +10 -5
  72. package/plugin/config/resolveUserConfig.ts +218 -177
  73. package/plugin/css-collector-inline.tsx +60 -0
  74. package/plugin/css-collector.tsx +62 -0
  75. package/plugin/helpers/createHandler.ts +73 -83
  76. package/plugin/helpers/createRscStream.ts +49 -21
  77. package/plugin/html.tsx +9 -0
  78. package/plugin/react-client/plugin.ts +3 -2
  79. package/plugin/react-server/plugin.ts +58 -22
  80. package/plugin/react-static/plugin.ts +20 -11
  81. package/plugin/react-static/types.ts +3 -0
  82. package/plugin/types.ts +53 -11
  83. package/plugin/worker/html/messageHandler.ts +5 -2
  84. package/plugin/worker/html/renderPages.ts +82 -78
  85. package/plugin/worker/rsc/messageHandler.tsx +41 -26
  86. package/plugin/worker/types.ts +3 -0
  87. package/dist/plugin/components.js.map +0 -1
  88. package/dist/plugin/getEnv.d.ts +0 -19
  89. package/dist/plugin/getEnv.d.ts.map +0 -1
  90. package/dist/plugin/getEnv.js +0 -107
  91. package/dist/plugin/module-graph.d.ts +0 -10
  92. package/dist/plugin/module-graph.d.ts.map +0 -1
  93. package/dist/plugin/module-graph.js +0 -35
  94. package/dist/plugin/worker/html/plugin.d.ts +0 -4
  95. package/dist/plugin/worker/html/plugin.d.ts.map +0 -1
  96. package/dist/plugin/worker/html/plugin.js +0 -93
  97. package/dist/plugin/worker/plugin.d.ts +0 -19
  98. package/dist/plugin/worker/plugin.d.ts.map +0 -1
  99. package/dist/plugin/worker/plugin.js +0 -23
  100. package/dist/plugin/worker/rsc/plugin.d.ts +0 -4
  101. package/dist/plugin/worker/rsc/plugin.d.ts.map +0 -1
  102. package/dist/plugin/worker/rsc/plugin.js +0 -75
  103. package/plugin/components.tsx +0 -59
  104. package/plugin/getEnv.ts +0 -135
  105. package/plugin/module-graph.ts +0 -48
  106. package/plugin/worker/html/plugin.ts +0 -100
  107. package/plugin/worker/plugin.ts +0 -26
  108. package/plugin/worker/rsc/plugin.ts +0 -83
@@ -1,79 +1,58 @@
1
1
  import type { PipeableStream } from "react-dom/server";
2
- import { createLogger } from "vite";
3
- import {
4
- collectManifestClientFiles,
5
- collectModuleGraphCss,
6
- } from "../collect-manifest-client-files.js";
7
- import { DEFAULT_CONFIG } from "../config/defaults.js";
8
2
  import { resolvePage } from "../resolvePage.js";
9
3
  import { resolveProps } from "../resolveProps.js";
10
- import type { CheckFilesExistReturn, CreateHandlerOptions, ResolvedUserOptions } from "../types.js";
4
+ import type { CreateHandlerOptions, CssContent } from "../types.js";
11
5
  import { createRscStream } from "./createRscStream.js";
12
-
13
- type CreateHandlerResult =
14
- | { type: "success"; controller: AbortController; stream: PipeableStream; assets: any; clientPath: string }
6
+ type CreateHandlerResult =
7
+ | {
8
+ type: "success";
9
+ controller: AbortController;
10
+ stream: PipeableStream;
11
+ assets: any;
12
+ route: string;
13
+ }
15
14
  | { type: "error"; error: Error }
16
15
  | { type: "skip" };
17
16
 
18
17
  interface HandlerAssets {
19
- css: string[];
18
+ css: (string | CssContent)[];
20
19
  bootstrapModules: string[];
21
20
  }
22
21
 
23
22
  export async function createHandler<T>({
24
- url,
25
- urlMap,
26
- pluginOptions,
27
- streamOptions,
28
- }: {
29
- url: string,
30
- urlMap: CheckFilesExistReturn['urlMap'],
31
- pluginOptions: ResolvedUserOptions,
32
- streamOptions: CreateHandlerOptions<T>
33
- }): Promise<CreateHandlerResult> {
34
- const root = pluginOptions.projectRoot ?? process.cwd();
35
-
36
- const Html = pluginOptions.Html ?? DEFAULT_CONFIG.HTML;
37
- const pageExportName =
38
- pluginOptions.pageExportName ?? DEFAULT_CONFIG.PAGE_EXPORT_NAME;
39
- const propsExportName =
40
- pluginOptions.propsExportName ?? DEFAULT_CONFIG.PROPS_EXPORT_NAME;
23
+ getCss,
24
+ root,
25
+ cssFiles = [],
26
+ cssModules = new Map<string, string | CssContent>(),
27
+ onCssFile,
28
+ logger,
29
+ loader,
30
+ Html,
31
+ CssCollector,
32
+ pagePath,
33
+ propsPath,
34
+ pageExportName,
35
+ propsExportName,
36
+ inlineCss,
37
+ moduleBase,
38
+ preserveModulesRoot: _preserveModulesRoot,
39
+ moduleBasePath,
40
+ moduleRootPath,
41
+ moduleBaseURL,
42
+ route,
43
+ pipableStreamOptions,
44
+ }: CreateHandlerOptions<T>): Promise<CreateHandlerResult> {
41
45
  const controller = new AbortController();
42
46
 
43
- const cssFiles = streamOptions.cssFiles;
44
-
45
-
46
- const cssModules = streamOptions.cssModules ?? new Set<string>();
47
-
48
- if (!(streamOptions.serverManifest || streamOptions.moduleGraph))
49
- throw new Error("Missing server manifest or moduleGraph, pass it to options.");
50
-
51
- const getCss = streamOptions.serverManifest
52
- ? (id: string) =>
53
- collectManifestClientFiles({
54
- manifest: streamOptions.serverManifest!,
55
- root: root,
56
- pagePath: id,
57
- onCss: streamOptions.onCssFile,
58
- moduleBase: pluginOptions.moduleBase,
59
- preserveModulesRoot: pluginOptions.build.preserveModulesRoot,
60
- }).cssFiles
61
- : (id: string) =>
62
- collectModuleGraphCss({
63
- moduleGraph: streamOptions.moduleGraph!,
64
- pagePath: id,
65
- onCss: streamOptions.onCssFile,
66
- });
67
-
68
- const loadWithCss = async (id: string, parentUrl: string) => {
47
+ const loadWithCss = async (id: string) => {
69
48
  try {
70
- const mod = await streamOptions.loader(id);
49
+ const mod = await loader(id);
71
50
  const pageCss = await Promise.resolve(getCss(id));
72
- Array.from(pageCss.keys()).forEach((css) => {
73
- cssModules.add(css);
51
+ Array.from(pageCss.entries()).forEach(([css, linkOrContent]) => {
52
+ cssModules.set(css, linkOrContent);
74
53
  // Notify about new CSS file if callback exists
75
- if (streamOptions.onCssFile) {
76
- streamOptions.onCssFile(css, parentUrl);
54
+ if (typeof onCssFile === "function") {
55
+ onCssFile(css, id);
77
56
  }
78
57
  });
79
58
  return mod as Record<string, any>;
@@ -87,44 +66,55 @@ export async function createHandler<T>({
87
66
  };
88
67
 
89
68
  const PropsModule = await resolveProps({
90
- propsModule: await loadWithCss(urlMap.get(url)?.props ?? url, url),
91
- path: String(urlMap.get(url)?.props ?? url),
69
+ propsModule: propsPath
70
+ ? await loadWithCss(propsPath)
71
+ : { [propsExportName]: (url: string) => ({url}) },
72
+ path: String(propsPath),
92
73
  exportName: propsExportName,
93
- url,
74
+ url: route,
94
75
  });
95
76
  if (PropsModule.type !== "success") {
96
- return PropsModule
77
+ return PropsModule;
97
78
  }
98
79
  const PageModule = await resolvePage({
99
- pageModule: await loadWithCss(urlMap.get(url)?.page ?? url, url),
100
- path: String(urlMap.get(url)?.page ?? url),
80
+ pageModule: pagePath
81
+ ? await loadWithCss(pagePath)
82
+ : { [pageExportName]: () => null },
83
+ path: String(pagePath),
101
84
  exportName: pageExportName,
102
- url,
85
+ url: route,
103
86
  });
104
87
  if (PageModule.type !== "success") {
105
- return PageModule
88
+ return PageModule;
106
89
  }
107
90
 
108
91
  // Add any additional CSS files
109
- if (streamOptions.cssFiles) {
110
- streamOptions.cssFiles.forEach((css) => cssModules.add(css));
92
+ if (cssFiles) {
93
+ cssFiles.forEach((css) => cssModules.set(typeof css === "string" ? css : css.path, css));
94
+ cssFiles = Array.from(cssModules.values());
111
95
  }
96
+ const url =
97
+ typeof moduleBaseURL === "string" && moduleBaseURL !== ""
98
+ ? new URL(route, moduleBaseURL).href
99
+ : route;
112
100
  const stream = createRscStream({
113
101
  Html: Html,
102
+ CssCollector: CssCollector,
114
103
  Page: PageModule[pageExportName as keyof typeof PageModule],
115
104
  props: PropsModule[propsExportName as keyof typeof PropsModule],
116
- moduleBasePath: streamOptions.moduleBasePath,
117
- moduleBaseURL: streamOptions.moduleBaseURL,
118
- logger: streamOptions.logger ?? createLogger(),
119
- cssFiles: Array.from(cssModules),
120
- route: url,
105
+ moduleBase: moduleBase,
106
+ moduleRootPath: moduleRootPath,
107
+ moduleBasePath: moduleBasePath,
108
+ moduleBaseURL: moduleBaseURL,
109
+ logger: logger,
110
+ cssFiles: Array.from(cssModules.values()),
111
+ route,
121
112
  url,
122
- pipableStreamOptions: streamOptions.pipableStreamOptions,
123
- htmlProps: {
124
- pageProps: PropsModule[propsExportName as keyof typeof PropsModule],
125
- route: url,
126
- url: url,
127
- },
113
+ pipableStreamOptions: pipableStreamOptions,
114
+ htmlProps: {},
115
+ root: root,
116
+ loader: loader,
117
+ inlineCss: inlineCss,
128
118
  });
129
119
 
130
120
  if (!stream) {
@@ -132,14 +122,14 @@ export async function createHandler<T>({
132
122
  }
133
123
 
134
124
  const assets: HandlerAssets = {
135
- css: Array.from(cssModules).concat(cssFiles ?? []),
136
- bootstrapModules: streamOptions.pipableStreamOptions?.bootstrapModules ?? [],
125
+ css: cssFiles,
126
+ bootstrapModules: pipableStreamOptions?.bootstrapModules ?? [],
137
127
  };
138
128
  return {
139
129
  type: "success",
140
130
  controller,
141
131
  stream,
142
132
  assets,
143
- clientPath: urlMap.get(url)?.page ?? '',
133
+ route: route,
144
134
  };
145
135
  }
@@ -3,12 +3,19 @@ import * as React from "react";
3
3
  import { renderToPipeableStream } from "react-server-dom-esm/server.node";
4
4
  import type { PipeableStreamOptions } from "../worker/types.js";
5
5
  import type { Logger } from "vite";
6
- import { CssCollector } from "../components.js";
6
+ import type {
7
+ CreateHandlerOptions,
8
+ CssCollectorProps,
9
+ CssContent,
10
+ InlineCssCollectorProps,
11
+ } from "../types.js";
7
12
 
8
- export function createRscStream({
13
+ export function createRscStream<InlineCSS extends boolean = true>({
9
14
  Html,
10
15
  Page,
11
16
  props,
17
+ loader = (id) => import(id).then((m) => m.default),
18
+ moduleRootPath,
12
19
  moduleBasePath,
13
20
  moduleBaseURL,
14
21
  logger,
@@ -17,30 +24,47 @@ export function createRscStream({
17
24
  url,
18
25
  pipableStreamOptions,
19
26
  htmlProps,
27
+ inlineCss = true as InlineCSS,
28
+ CssCollector,
29
+ root,
20
30
  }: {
21
- Html: React.ComponentType<any>;
31
+ Html: CreateHandlerOptions["Html"];
22
32
  Page: React.ComponentType<any>;
33
+ loader: (id: string) => Promise<any>;
23
34
  props: any;
35
+ moduleBase: string;
36
+ moduleRootPath: string;
24
37
  moduleBasePath: string;
25
38
  moduleBaseURL: string;
26
39
  logger: Logger;
27
- cssFiles?: string[];
28
40
  route: string;
29
41
  url: string;
30
42
  pipableStreamOptions?: PipeableStreamOptions;
31
43
  htmlProps?: any;
32
- }) {
44
+ root: string;
45
+ inlineCss?: InlineCSS;
46
+ cssFiles?: (string | CssContent)[];
47
+ } & (InlineCSS extends true
48
+ ? {
49
+ CssCollector: React.FC<InlineCssCollectorProps>;
50
+ }
51
+ : {
52
+ CssCollector: React.FC<CssCollectorProps>;
53
+ })) {
33
54
  const htmlIsFragment = Html == React.Fragment;
34
55
  if (!htmlIsFragment) {
35
56
  if (!htmlProps) {
36
57
  htmlProps = {};
37
58
  }
38
- if(!("moduleBaseUrl" in htmlProps)) {
39
- htmlProps["moduleBaseUrl"] = moduleBaseURL;
59
+ if (!("moduleBaseURL" in htmlProps)) {
60
+ htmlProps["moduleBaseURL"] = moduleBaseURL;
40
61
  }
41
- if(!("moduleBasePath" in htmlProps)) {
62
+ if (!("moduleBasePath" in htmlProps)) {
42
63
  htmlProps["moduleBasePath"] = moduleBasePath;
43
64
  }
65
+ if (!("moduleRootPath" in htmlProps)) {
66
+ htmlProps["moduleRootPath"] = moduleRootPath;
67
+ }
44
68
  if (!("url" in htmlProps)) {
45
69
  htmlProps["url"] = url;
46
70
  }
@@ -52,8 +76,18 @@ export function createRscStream({
52
76
  }
53
77
  }
54
78
  const withCss = React.createElement(
55
- CssCollector,
56
- { cssFiles, route, moduleBaseUrl: moduleBaseURL },
79
+ CssCollector as any,
80
+ (inlineCss === true
81
+ ? {
82
+ cssFiles: cssFiles,
83
+ route,
84
+ moduleBaseURL,
85
+ moduleBasePath,
86
+ moduleRootPath,
87
+ root,
88
+ loader,
89
+ }
90
+ : { cssFiles: cssFiles, route, moduleBaseURL }) as any,
57
91
  React.createElement(Page, props)
58
92
  );
59
93
  // Otherwise wrap with Html component
@@ -61,17 +95,11 @@ export function createRscStream({
61
95
  ? withCss
62
96
  : React.createElement(Html, htmlProps, withCss);
63
97
  try {
64
- return renderToPipeableStream(content, moduleBaseURL, {
65
- onError: (error: Error) => {
66
- if (process.env["NODE_ENV"] === "development") {
67
- console.trace(error);
68
- }
69
- logger.error(`Stream error at ${route}.`, { error });
70
- },
71
- onPostpone: logger.info ?? console.info,
72
- environmentName: "Server",
73
- ...pipableStreamOptions,
74
- });
98
+ return renderToPipeableStream(
99
+ content,
100
+ moduleBasePath,
101
+ pipableStreamOptions
102
+ );
75
103
  } catch (error) {
76
104
  logger.error(`Failed to create stream for ${route}.`, {
77
105
  error: error as Error,
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ export const Html = ({ children }: { children: any }) => (
3
+ <html>
4
+ <head></head>
5
+ <body>
6
+ <div id="root">{children}</div>
7
+ </body>
8
+ </html>
9
+ );
@@ -301,8 +301,9 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
301
301
  userOptions.build.preserveModulesRoot === true
302
302
  ? userOptions.moduleBase
303
303
  : "",
304
- moduleBaseURL: ``,
305
- moduleBasePath: '/',
304
+ moduleBaseURL: userOptions.moduleBaseURL,
305
+ moduleBasePath: userOptions.moduleBasePath,
306
+ moduleBase: userOptions.moduleBase,
306
307
  pipableStreamOptions: userOptions.pipableStreamOptions,
307
308
  cssFiles: []
308
309
  } satisfies RscRenderMessage);
@@ -16,16 +16,20 @@ import { resolveUserConfig } from "../config/resolveUserConfig.js";
16
16
  import type {
17
17
  BuildTiming,
18
18
  CheckFilesExistReturn,
19
+ CssContent,
19
20
  ReactStreamPluginMeta,
20
21
  ResolvedUserOptions,
21
22
  } from "../types.js";
22
23
  import { type StreamPluginOptions } from "../types.js";
23
24
  import { createHandler } from "../helpers/createHandler.js";
24
- import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
25
+ import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
25
26
  import { getBundleManifest } from "../helpers/getBundleManifest.js";
26
27
  import type { ServerResponse } from "node:http";
27
28
  import { createInputNormalizer } from "../helpers/inputNormalizer.js";
28
29
  import { MIME_TYPES } from "../config/mimeTypes.js";
30
+ import { InlineCssCollector } from "../css-collector-inline.js";
31
+ import { CssCollector } from "../css-collector.js";
32
+ import { collectModuleGraphCss } from "../collect-manifest-client-files.js";
29
33
 
30
34
  let resolvedConfig: ResolvedConfig | null = null;
31
35
  let serverManifestPath: string | null = null;
@@ -105,7 +109,7 @@ export function reactServerPlugin(options: StreamPluginOptions): VitePlugin<{
105
109
  );
106
110
  }
107
111
  },
108
-
112
+
109
113
  async configurePreviewServer(server) {
110
114
  if (root !== server.config.root) {
111
115
  root = server.config.root;
@@ -128,11 +132,11 @@ export function reactServerPlugin(options: StreamPluginOptions): VitePlugin<{
128
132
  try {
129
133
  const filePath = join(fileRoot, value);
130
134
  const stats = await stat(filePath);
131
-
135
+
132
136
  if (stats.isFile()) {
133
- const ext = value.slice(value.lastIndexOf('.'));
134
- const contentType = MIME_TYPES[ext] || 'application/octet-stream';
135
- res.setHeader('Content-Type', contentType);
137
+ const ext = value.slice(value.lastIndexOf("."));
138
+ const contentType = MIME_TYPES[ext] || "application/octet-stream";
139
+ res.setHeader("Content-Type", contentType);
136
140
  const content = await readFile(filePath);
137
141
  res.end(content);
138
142
  return;
@@ -187,25 +191,57 @@ export function reactServerPlugin(options: StreamPluginOptions): VitePlugin<{
187
191
  if (typeof loader !== "function") {
188
192
  loader = server.ssrLoadModule;
189
193
  }
190
- const route = req.url?.replace('/index.rsc', '');
194
+ let route = req.url?.replace("/index.rsc", "");
195
+ if (!route || route === "") {
196
+ route = "/";
197
+ }
191
198
  try {
192
199
  const handler = await createHandler({
193
- url: !route || route === "" ? "/" : route,
194
- urlMap: files.urlMap,
195
- pluginOptions: {
196
- ...userOptions,
197
- // we'll leave the Html generation for later
198
- Html: React.Fragment,
199
- projectRoot: root,
200
+ root: root,
201
+ url:
202
+ typeof userOptions.moduleBaseURL === "string" &&
203
+ userOptions.moduleBaseURL !== ""
204
+ ? new URL(route, userOptions.moduleBaseURL).href
205
+ : route,
206
+ route: route,
207
+ getCss: async (id) => {
208
+ const cssFiles = await collectModuleGraphCss({
209
+ moduleGraph: server.moduleGraph,
210
+ pagePath: id,
211
+ onCss: undefined,
212
+ })
213
+ if (userOptions.inlineCss) {
214
+ const InlineMap = new Map<string, CssContent>();
215
+ await Promise.all(Array.from(cssFiles.entries()).map(async ([file, fileUrl]) => {
216
+ const content = await server.ssrLoadModule(fileUrl + "?inline");
217
+ if (content) {
218
+ InlineMap.set(file, {
219
+ content: content['default'],
220
+ path: file,
221
+ type: "text/css",
222
+ });
223
+ }
224
+ }));
225
+ return InlineMap;
226
+ }
227
+ return cssFiles;
200
228
  },
201
- streamOptions: {
202
- cssFiles: [],
203
- logger: createLogger(),
204
- loader,
205
- moduleGraph: server.moduleGraph,
206
- moduleBasePath: '',
207
- moduleBaseURL: '',
208
- }
229
+ cssFiles: [],
230
+ logger: createLogger(),
231
+ loader,
232
+ moduleBase: userOptions.moduleBase,
233
+ moduleBasePath: userOptions.moduleBasePath,
234
+ moduleBaseURL: userOptions.moduleBaseURL,
235
+ moduleRootPath: root,
236
+ pipableStreamOptions: userOptions.pipableStreamOptions,
237
+ Html: React.Fragment,
238
+ CssCollector: userOptions.inlineCss ? InlineCssCollector as any : CssCollector as any,
239
+ onCssFile: undefined,
240
+ inlineCss: userOptions.inlineCss,
241
+ propsPath: files.urlMap.get(route)?.props ?? route,
242
+ pagePath: files.urlMap.get(route)?.page ?? route,
243
+ pageExportName: userOptions.pageExportName,
244
+ propsExportName: userOptions.propsExportName,
209
245
  });
210
246
  if (handler.type === "success") {
211
247
  handler.stream?.pipe(res);
@@ -6,6 +6,7 @@ import {
6
6
  type Manifest,
7
7
  type IndexHtmlTransformHook,
8
8
  type Plugin as VitePlugin,
9
+ createLogger,
9
10
  } from "vite";
10
11
  import { checkFilesExist } from "../checkFilesExist.js";
11
12
  import { resolveOptions } from "../config/resolveOptions.js";
@@ -45,7 +46,7 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
45
46
  let root: string = process.cwd();
46
47
  let userConfig: ResolvedUserConfig;
47
48
  let userOptions: ResolvedUserOptions;
48
- let resolvedPages: string[];
49
+ let pages: string[];
49
50
  let serverManifest: Manifest = {};
50
51
  let clientManifest: Manifest = {};
51
52
 
@@ -83,12 +84,12 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
83
84
  ) {
84
85
  root = config.root;
85
86
  }
86
- const resolvedPagesResult = await resolvePages(userOptions.build.pages);
87
- if (resolvedPagesResult.type === "error") {
88
- throw resolvedPagesResult.error;
87
+ const resolvePagesResult = await resolvePages(userOptions.build.pages);
88
+ if (resolvePagesResult.type === "error") {
89
+ throw resolvePagesResult.error;
89
90
  }
90
- resolvedPages = resolvedPagesResult.pages;
91
- files = await checkFilesExist(resolvedPages, userOptions, root);
91
+ pages = resolvePagesResult.pages;
92
+ files = await checkFilesExist(pages, userOptions, root);
92
93
 
93
94
  const resolvedConfig = resolveUserConfig({
94
95
  isStatic: true,
@@ -176,7 +177,7 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
176
177
  indexCss.forEach((css) => globalCss.add(css));
177
178
 
178
179
  // Add CSS for each route's page component - use server manifest
179
- for (const route of resolvedPages) {
180
+ for (const route of pages) {
180
181
  const routeFiles = files.urlMap.get(route);
181
182
  if (routeFiles) {
182
183
  const pageCss = collectManifestClientFiles({
@@ -205,18 +206,26 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
205
206
  : [];
206
207
 
207
208
  const { failedRoutes, completedRoutes} = await renderPages(
208
- resolvedPages,
209
+ pages,
209
210
  files,
210
211
  {
212
+ root: root,
211
213
  outDir: userOptions.build.outDir,
212
214
  htmlOutputPath: join( userOptions.build.outDir, userOptions.build.static, "index.html"),
213
215
  pipableStreamOptions: {
214
216
  bootstrapModules: bootstrapModules,
215
217
  },
216
- moduleBasePath: join(root, userOptions.build.outDir, userOptions.build.client),
218
+ moduleRootPath: join(root, userOptions.build.outDir, userOptions.build.static, userOptions.moduleBasePath),
219
+ moduleBasePath: userOptions.moduleBasePath,
217
220
  moduleBaseURL: userOptions.moduleBaseURL,
218
- userConfig,
219
- pluginOptions: userOptions,
221
+ inlineCss: userOptions.inlineCss,
222
+ pageExportName: userOptions.pageExportName,
223
+ propsExportName: userOptions.propsExportName,
224
+ Html: userOptions.Html,
225
+ CssCollector: userOptions.CssCollector,
226
+ cssFiles: [],
227
+ logger: createLogger(),
228
+ moduleBase: userOptions.moduleBase,
220
229
  worker,
221
230
  clientManifest,
222
231
  serverManifest,
@@ -0,0 +1,3 @@
1
+ export type ReactStaticPluginOptions = {
2
+
3
+ };
package/plugin/types.ts CHANGED
@@ -65,7 +65,7 @@ export interface StreamPluginOptionsClient {
65
65
  cssFiles?: AliasOptions;
66
66
  }
67
67
 
68
- export type ResolvedUserOptions = Required<
68
+ export type ResolvedUserOptions<InlineCSS extends boolean = boolean> = Required<
69
69
  Pick<
70
70
  StreamPluginOptions,
71
71
  | "moduleBase"
@@ -76,10 +76,12 @@ export type ResolvedUserOptions = Required<
76
76
  | "Page"
77
77
  | "props"
78
78
  | "Html"
79
+ | "CssCollector"
79
80
  | "pageExportName"
80
81
  | "propsExportName"
81
82
  | "collectCss"
82
83
  | "collectAssets"
84
+ | "inlineCss"
83
85
  | "htmlWorkerPath"
84
86
  | "rscWorkerPath"
85
87
  | "loaderPath"
@@ -89,7 +91,7 @@ export type ResolvedUserOptions = Required<
89
91
  | "pipableStreamOptions"
90
92
  >
91
93
  > & {
92
- build: NonNullable<Required<StreamPluginOptions["build"]>>;
94
+ build: NonNullable<Required<StreamPluginOptions<InlineCSS>["build"]>>;
93
95
  autoDiscover: {
94
96
  modulePattern: (path: string) => boolean;
95
97
  cssPattern: (path: string) => boolean;
@@ -116,7 +118,7 @@ export type createBuildConfigFn<C extends "react-client" | "react-server"> =
116
118
  ? Promise<InlineConfig>
117
119
  : Promise<InlineConfig>;
118
120
 
119
- export interface StreamPluginOptions {
121
+ export interface StreamPluginOptions<InlineCSS extends boolean = boolean> {
120
122
  projectRoot?: string;
121
123
  moduleBase: string;
122
124
  moduleBasePath?: string;
@@ -164,25 +166,38 @@ export interface StreamPluginOptions {
164
166
  url: string;
165
167
  children: React.ReactNode;
166
168
  }>;
169
+ CssCollector?: InlineCSS extends true ? React.FC<React.PropsWithChildren<InlineCssCollectorProps>> : React.FC<React.PropsWithChildren<CssCollectorProps>>;
167
170
  collectCss?: boolean;
168
171
  collectAssets?: boolean;
172
+ inlineCss?: InlineCSS;
169
173
  build?: BuildConfig;
170
174
  moduleBaseExceptions?: string[];
171
175
  pipableStreamOptions?: PipeableStreamOptions;
172
176
  }
173
177
 
174
- export interface CreateHandlerOptions<T = any> {
178
+ export interface CreateHandlerOptions<T = any, InlineCSS extends boolean = boolean> {
179
+ root: string;
180
+ url: string;
181
+ route: string;
182
+ getCss: (id: string) => Promise<Map<string, string | CssContent>> | Map<string, string | CssContent>;
175
183
  loader: (id: string) => Promise<T>;
176
- clientManifest?: import("vite").Manifest;
177
- serverManifest?: import("vite").Manifest;
184
+ Html: NonNullable<StreamPluginOptions['Html']>
185
+ CssCollector: InlineCSS extends true ? React.FC<React.PropsWithChildren<InlineCssCollectorProps>> : React.FC<React.PropsWithChildren<CssCollectorProps>>;
186
+ inlineCss: InlineCSS;
187
+ propsPath?: string;
188
+ pagePath?: string;
189
+ pageExportName: string
190
+ propsExportName: string
191
+ moduleBase: string
192
+ preserveModulesRoot?: boolean | undefined
178
193
  moduleBasePath: string;
194
+ moduleRootPath: string;
179
195
  moduleBaseURL: string;
180
- moduleGraph?: import("vite").ModuleGraph;
181
- cssFiles?: string[];
182
- cssModules?: Set<string>;
196
+ cssFiles: (string | CssContent)[];
197
+ cssModules?: Map<string, string | CssContent> | undefined;
183
198
  onCssFile?: (path: string, parentUrl: string) => void;
184
- logger?: import("vite").Logger;
185
- pipableStreamOptions?: PipeableStreamOptions;
199
+ logger: import("vite").Logger;
200
+ pipableStreamOptions: PipeableStreamOptions;
186
201
  }
187
202
 
188
203
  export type ModuleLoader = (
@@ -378,3 +393,30 @@ export interface PageData {
378
393
  modules: Array<[string, string]>; // [modulePath, exportName]
379
394
  };
380
395
  }
396
+
397
+ export interface CssContent {
398
+ type?: string;
399
+ content: string;
400
+ key?: string;
401
+ path: string;
402
+ }
403
+
404
+ export interface InlineCssCollectorProps {
405
+ cssFiles: CssContent[];
406
+ root: string;
407
+ moduleBaseURL: string;
408
+ moduleBasePath: string;
409
+ moduleRootPath: string;
410
+ route: string;
411
+ children?: React.ReactNode;
412
+ }
413
+
414
+ export interface CssCollectorProps {
415
+ cssFiles: CssContent[];
416
+ root: string;
417
+ moduleBaseURL: string;
418
+ moduleBasePath: string;
419
+ moduleRootPath: string;
420
+ route: string;
421
+ children?: React.ReactNode;
422
+ }