vite-plugin-react-server 0.3.18 → 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 (246) hide show
  1. package/README.md +220 -141
  2. package/bin/patch.mjs +8 -2
  3. package/dist/package.json +15 -8
  4. package/dist/plugin/checkFilesExist.d.ts.map +1 -1
  5. package/dist/plugin/checkFilesExist.js +6 -2
  6. package/dist/plugin/checkFilesExist.js.map +1 -1
  7. package/dist/plugin/collect-manifest-client-files.d.ts +23 -0
  8. package/dist/plugin/collect-manifest-client-files.d.ts.map +1 -0
  9. package/dist/plugin/collect-manifest-client-files.js +131 -0
  10. package/dist/plugin/collect-manifest-client-files.js.map +1 -0
  11. package/dist/plugin/components.d.ts +3 -13
  12. package/dist/plugin/components.d.ts.map +1 -1
  13. package/dist/plugin/components.js +3 -13
  14. package/dist/plugin/config/defaults.d.ts +14 -6
  15. package/dist/plugin/config/defaults.d.ts.map +1 -1
  16. package/dist/plugin/config/defaults.js +9 -5
  17. package/dist/plugin/config/defaults.js.map +1 -1
  18. package/dist/plugin/config/getPaths.d.ts +0 -1
  19. package/dist/plugin/config/getPaths.d.ts.map +1 -1
  20. package/dist/plugin/config/getPaths.js +2 -7
  21. package/dist/plugin/config/getPaths.js.map +1 -1
  22. package/dist/plugin/config/mimeTypes.d.ts +2 -0
  23. package/dist/plugin/config/mimeTypes.d.ts.map +1 -0
  24. package/dist/plugin/config/mimeTypes.js +24 -0
  25. package/dist/plugin/config/mimeTypes.js.map +1 -0
  26. package/dist/plugin/config/resolveOptions.d.ts +2 -2
  27. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  28. package/dist/plugin/config/resolveOptions.js +47 -28
  29. package/dist/plugin/config/resolveOptions.js.map +1 -1
  30. package/dist/plugin/config/resolvePages.d.ts +1 -0
  31. package/dist/plugin/config/resolvePages.d.ts.map +1 -1
  32. package/dist/plugin/config/resolvePages.js +9 -5
  33. package/dist/plugin/config/resolvePages.js.map +1 -1
  34. package/dist/plugin/config/resolveUserConfig.d.ts +2 -1
  35. package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
  36. package/dist/plugin/config/resolveUserConfig.js +181 -147
  37. package/dist/plugin/config/resolveUserConfig.js.map +1 -1
  38. package/dist/plugin/copy-dir.js +23 -18
  39. package/dist/plugin/copy-dir.js.map +1 -0
  40. package/dist/plugin/css-collector-inline.d.ts +10 -0
  41. package/dist/plugin/css-collector-inline.d.ts.map +1 -0
  42. package/dist/plugin/css-collector-inline.js +55 -0
  43. package/dist/plugin/css-collector-inline.js.map +1 -0
  44. package/dist/plugin/css-collector.d.ts +14 -0
  45. package/dist/plugin/css-collector.d.ts.map +1 -0
  46. package/dist/plugin/css-collector.js +49 -0
  47. package/dist/plugin/css-collector.js.map +1 -0
  48. package/dist/plugin/helpers/createHandler.d.ts +17 -0
  49. package/dist/plugin/helpers/createHandler.d.ts.map +1 -0
  50. package/dist/plugin/helpers/createHandler.js +111 -0
  51. package/dist/plugin/helpers/createHandler.js.map +1 -0
  52. package/dist/plugin/helpers/createRscStream.d.ts +27 -0
  53. package/dist/plugin/helpers/createRscStream.d.ts.map +1 -0
  54. package/dist/plugin/helpers/createRscStream.js +80 -0
  55. package/dist/plugin/helpers/createRscStream.js.map +1 -0
  56. package/dist/plugin/helpers/getBundleManifest.d.ts.map +1 -1
  57. package/dist/plugin/helpers/getBundleManifest.js +12 -4
  58. package/dist/plugin/helpers/getBundleManifest.js.map +1 -1
  59. package/dist/plugin/html.d.ts +5 -0
  60. package/dist/plugin/html.d.ts.map +1 -0
  61. package/dist/plugin/html.js +11 -0
  62. package/dist/plugin/html.js.map +1 -0
  63. package/dist/plugin/loader/createBuildLoader.d.ts +1 -1
  64. package/dist/plugin/loader/createBuildLoader.d.ts.map +1 -1
  65. package/dist/plugin/loader/createBuildLoader.js +8 -5
  66. package/dist/plugin/loader/createBuildLoader.js.map +1 -1
  67. package/dist/plugin/loader/css-loader.d.ts.map +1 -1
  68. package/dist/plugin/loader/css-loader.js.map +1 -1
  69. package/dist/plugin/loader/react-loader.js +2 -2
  70. package/dist/plugin/loader/react-loader.js.map +1 -1
  71. package/dist/plugin/preserver/plugin.d.ts.map +1 -1
  72. package/dist/plugin/preserver/plugin.js +49 -14
  73. package/dist/plugin/preserver/plugin.js.map +1 -1
  74. package/dist/plugin/react-client/plugin.d.ts.map +1 -1
  75. package/dist/plugin/react-client/plugin.js +21 -78
  76. package/dist/plugin/react-client/plugin.js.map +1 -1
  77. package/dist/plugin/react-server/index.d.ts.map +1 -1
  78. package/dist/plugin/react-server/index.js +2 -0
  79. package/dist/plugin/react-server/index.js.map +1 -1
  80. package/dist/plugin/react-server/plugin.d.ts +2 -1
  81. package/dist/plugin/react-server/plugin.d.ts.map +1 -1
  82. package/dist/plugin/react-server/plugin.js +92 -225
  83. package/dist/plugin/react-server/plugin.js.map +1 -1
  84. package/dist/plugin/react-static/index.d.ts +2 -0
  85. package/dist/plugin/react-static/index.d.ts.map +1 -0
  86. package/dist/plugin/react-static/index.js +1 -0
  87. package/dist/plugin/react-static/plugin.d.ts +7 -0
  88. package/dist/plugin/react-static/plugin.d.ts.map +1 -0
  89. package/dist/plugin/react-static/plugin.js +207 -0
  90. package/dist/plugin/react-static/plugin.js.map +1 -0
  91. package/dist/plugin/react-static/types.d.ts +2 -0
  92. package/dist/plugin/react-static/types.d.ts.map +1 -0
  93. package/dist/plugin/resolvePage.d.ts.map +1 -1
  94. package/dist/plugin/resolvePage.js +9 -0
  95. package/dist/plugin/resolvePage.js.map +1 -1
  96. package/dist/plugin/root.d.ts +2 -0
  97. package/dist/plugin/root.d.ts.map +1 -0
  98. package/dist/plugin/root.js +12 -0
  99. package/dist/plugin/root.js.map +1 -0
  100. package/dist/plugin/transformer/plugin.d.ts.map +1 -1
  101. package/dist/plugin/transformer/plugin.js +32 -23
  102. package/dist/plugin/transformer/plugin.js.map +1 -1
  103. package/dist/plugin/transformer/types.d.ts +1 -18
  104. package/dist/plugin/transformer/types.d.ts.map +1 -1
  105. package/dist/plugin/types.d.ts +70 -15
  106. package/dist/plugin/types.d.ts.map +1 -1
  107. package/dist/plugin/worker/createWorker.js +0 -1
  108. package/dist/plugin/worker/createWorker.js.map +1 -1
  109. package/dist/plugin/worker/html/html-worker.development.d.ts +30 -0
  110. package/dist/plugin/worker/html/html-worker.development.d.ts.map +1 -1
  111. package/dist/plugin/worker/html/html-worker.development.js +30 -2
  112. package/dist/plugin/worker/html/html-worker.development.js.map +1 -1
  113. package/dist/plugin/worker/html/html-worker.production.js +3 -5
  114. package/dist/plugin/worker/html/html-worker.production.js.map +1 -1
  115. package/dist/plugin/worker/html/messageHandler.d.ts.map +1 -1
  116. package/dist/plugin/worker/html/messageHandler.js +12 -3
  117. package/dist/plugin/worker/html/messageHandler.js.map +1 -1
  118. package/dist/plugin/worker/html/renderPages.d.ts +13 -26
  119. package/dist/plugin/worker/html/renderPages.d.ts.map +1 -1
  120. package/dist/plugin/worker/html/renderPages.js +138 -86
  121. package/dist/plugin/worker/html/renderPages.js.map +1 -1
  122. package/dist/plugin/worker/rsc/messageHandler.d.ts.map +1 -1
  123. package/dist/plugin/worker/rsc/messageHandler.js +104 -84
  124. package/dist/plugin/worker/rsc/messageHandler.js.map +1 -1
  125. package/dist/plugin/worker/rsc/rsc-worker.development.js +13 -18
  126. package/dist/plugin/worker/rsc/rsc-worker.development.js.map +1 -1
  127. package/dist/plugin/worker/rsc/rsc-worker.production.js +4 -1
  128. package/dist/plugin/worker/rsc/rsc-worker.production.js.map +1 -1
  129. package/dist/plugin/worker/rsc/state.d.ts.map +1 -1
  130. package/dist/plugin/worker/rsc/state.js.map +1 -1
  131. package/dist/plugin/worker/types.d.ts +3 -0
  132. package/dist/plugin/worker/types.d.ts.map +1 -1
  133. package/dist/tsconfig.tsbuildinfo +1 -1
  134. package/package.json +14 -6
  135. package/plugin/checkFilesExist.ts +7 -3
  136. package/plugin/collect-manifest-client-files.ts +167 -0
  137. package/plugin/components.ts +3 -0
  138. package/plugin/config/defaults.tsx +70 -0
  139. package/plugin/config/getPaths.ts +1 -7
  140. package/plugin/config/mimeTypes.ts +17 -0
  141. package/plugin/config/resolveOptions.ts +58 -45
  142. package/plugin/config/resolvePages.ts +8 -4
  143. package/plugin/config/resolveUserConfig.ts +220 -176
  144. package/plugin/css-collector-inline.tsx +60 -0
  145. package/plugin/css-collector.tsx +62 -0
  146. package/plugin/helpers/createHandler.ts +135 -0
  147. package/plugin/helpers/createRscStream.ts +109 -0
  148. package/plugin/helpers/getBundleManifest.ts +14 -5
  149. package/plugin/html.tsx +9 -0
  150. package/plugin/loader/createBuildLoader.ts +9 -6
  151. package/plugin/loader/css-loader.ts +0 -2
  152. package/plugin/loader/react-loader.ts +2 -2
  153. package/plugin/preserver/plugin.ts +64 -17
  154. package/plugin/react-client/plugin.ts +23 -93
  155. package/plugin/react-server/index.ts +2 -0
  156. package/plugin/react-server/plugin.ts +111 -302
  157. package/plugin/react-static/index.ts +1 -0
  158. package/plugin/react-static/plugin.ts +256 -0
  159. package/plugin/react-static/types.ts +3 -0
  160. package/plugin/resolvePage.ts +9 -0
  161. package/plugin/root.ts +4 -0
  162. package/plugin/transformer/plugin.ts +40 -31
  163. package/plugin/transformer/types.ts +0 -19
  164. package/plugin/types.ts +77 -16
  165. package/plugin/worker/createWorker.ts +1 -1
  166. package/plugin/worker/html/README.md +63 -0
  167. package/plugin/worker/html/html-worker.development.tsx +89 -2
  168. package/plugin/worker/html/html-worker.production.tsx +8 -10
  169. package/plugin/worker/html/messageHandler.ts +12 -3
  170. package/plugin/worker/html/renderPages.ts +178 -138
  171. package/plugin/worker/rsc/README.md +58 -0
  172. package/plugin/worker/rsc/messageHandler.tsx +112 -113
  173. package/plugin/worker/rsc/rsc-worker.development.ts +12 -22
  174. package/plugin/worker/rsc/rsc-worker.production.ts +5 -1
  175. package/plugin/worker/rsc/state.ts +0 -3
  176. package/plugin/worker/types.ts +3 -0
  177. package/scripts/react+0.0.0-experimental-eda36a1c-20250228.patch +114 -12
  178. package/scripts/react-dom+0.0.0-experimental-eda36a1c-20250228.patch +10571 -121
  179. package/tsconfig.json +2 -2
  180. package/dist/plugin/collect-css-manifest.d.ts +0 -4
  181. package/dist/plugin/collect-css-manifest.d.ts.map +0 -1
  182. package/dist/plugin/collect-css-manifest.js +0 -65
  183. package/dist/plugin/collect-css-manifest.js.map +0 -1
  184. package/dist/plugin/config/createModuleIdGenerator.d.ts +0 -11
  185. package/dist/plugin/config/createModuleIdGenerator.d.ts.map +0 -1
  186. package/dist/plugin/config/createModuleIdGenerator.js +0 -44
  187. package/dist/plugin/config/createModuleIdGenerator.js.map +0 -1
  188. package/dist/plugin/getEnv.d.ts +0 -19
  189. package/dist/plugin/getEnv.d.ts.map +0 -1
  190. package/dist/plugin/getEnv.js +0 -107
  191. package/dist/plugin/loader/createCssLoader.d.ts +0 -30
  192. package/dist/plugin/loader/createCssLoader.d.ts.map +0 -1
  193. package/dist/plugin/loader/createCssLoader.js +0 -35
  194. package/dist/plugin/loader/createPageLoader.d.ts +0 -24
  195. package/dist/plugin/loader/createPageLoader.d.ts.map +0 -1
  196. package/dist/plugin/loader/createPageLoader.js +0 -50
  197. package/dist/plugin/loader/rsc/messageHandler.d.ts +0 -2
  198. package/dist/plugin/loader/rsc/messageHandler.d.ts.map +0 -1
  199. package/dist/plugin/loader/rsc/rsc-worker.development.d.ts +0 -2
  200. package/dist/plugin/loader/rsc/rsc-worker.development.d.ts.map +0 -1
  201. package/dist/plugin/loader/rsc/rsc-worker.development.js +0 -1
  202. package/dist/plugin/module-graph.d.ts +0 -10
  203. package/dist/plugin/module-graph.d.ts.map +0 -1
  204. package/dist/plugin/module-graph.js +0 -35
  205. package/dist/plugin/react-server/createHandler.d.ts +0 -17
  206. package/dist/plugin/react-server/createHandler.d.ts.map +0 -1
  207. package/dist/plugin/react-server/createHandler.js +0 -126
  208. package/dist/plugin/react-server/createHandler.js.map +0 -1
  209. package/dist/plugin/react-server/createRscStream.d.ts +0 -16
  210. package/dist/plugin/react-server/createRscStream.d.ts.map +0 -1
  211. package/dist/plugin/react-server/createRscStream.js +0 -70
  212. package/dist/plugin/react-server/createRscStream.js.map +0 -1
  213. package/dist/plugin/react-server/createSsrHandler.d.ts +0 -4
  214. package/dist/plugin/react-server/createSsrHandler.d.ts.map +0 -1
  215. package/dist/plugin/react-server/createSsrHandler.js +0 -95
  216. package/dist/plugin/utils/logger.d.ts +0 -9
  217. package/dist/plugin/utils/logger.d.ts.map +0 -1
  218. package/dist/plugin/utils/logger.js +0 -68
  219. package/dist/plugin/utils/logger.js.map +0 -1
  220. package/dist/plugin/worker/html/plugin.d.ts +0 -4
  221. package/dist/plugin/worker/html/plugin.d.ts.map +0 -1
  222. package/dist/plugin/worker/html/plugin.js +0 -94
  223. package/dist/plugin/worker/plugin.d.ts +0 -19
  224. package/dist/plugin/worker/plugin.d.ts.map +0 -1
  225. package/dist/plugin/worker/plugin.js +0 -23
  226. package/dist/plugin/worker/rsc/plugin.d.ts +0 -4
  227. package/dist/plugin/worker/rsc/plugin.d.ts.map +0 -1
  228. package/dist/plugin/worker/rsc/plugin.js +0 -76
  229. package/plugin/collect-css-manifest.ts +0 -82
  230. package/plugin/components.tsx +0 -14
  231. package/plugin/config/createModuleIdGenerator.ts +0 -52
  232. package/plugin/config/defaults.ts +0 -51
  233. package/plugin/getEnv.ts +0 -135
  234. package/plugin/loader/createCssLoader.ts +0 -73
  235. package/plugin/loader/createPageLoader.ts +0 -103
  236. package/plugin/loader/rsc/messageHandler.tsx +0 -1
  237. package/plugin/loader/rsc/rsc-worker.development.ts +0 -1
  238. package/plugin/module-graph.ts +0 -48
  239. package/plugin/react-server/createHandler.ts +0 -162
  240. package/plugin/react-server/createRscStream.ts +0 -86
  241. package/plugin/react-server/createSsrHandler.ts +0 -125
  242. package/plugin/utils/logger.ts +0 -52
  243. package/plugin/worker/html/plugin.ts +0 -101
  244. package/plugin/worker/plugin.ts +0 -26
  245. package/plugin/worker/rsc/plugin.ts +0 -84
  246. /package/dist/plugin/{loader/rsc/messageHandler.js → react-static/types.js} +0 -0
@@ -0,0 +1,135 @@
1
+ import type { PipeableStream } from "react-dom/server";
2
+ import { resolvePage } from "../resolvePage.js";
3
+ import { resolveProps } from "../resolveProps.js";
4
+ import type { CreateHandlerOptions, CssContent } from "../types.js";
5
+ import { createRscStream } from "./createRscStream.js";
6
+ type CreateHandlerResult =
7
+ | {
8
+ type: "success";
9
+ controller: AbortController;
10
+ stream: PipeableStream;
11
+ assets: any;
12
+ route: string;
13
+ }
14
+ | { type: "error"; error: Error }
15
+ | { type: "skip" };
16
+
17
+ interface HandlerAssets {
18
+ css: (string | CssContent)[];
19
+ bootstrapModules: string[];
20
+ }
21
+
22
+ export async function createHandler<T>({
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> {
45
+ const controller = new AbortController();
46
+
47
+ const loadWithCss = async (id: string) => {
48
+ try {
49
+ const mod = await loader(id);
50
+ const pageCss = await Promise.resolve(getCss(id));
51
+ Array.from(pageCss.entries()).forEach(([css, linkOrContent]) => {
52
+ cssModules.set(css, linkOrContent);
53
+ // Notify about new CSS file if callback exists
54
+ if (typeof onCssFile === "function") {
55
+ onCssFile(css, id);
56
+ }
57
+ });
58
+ return mod as Record<string, any>;
59
+ } catch (e: any) {
60
+ if (e.message?.includes("module runner has been closed")) {
61
+ return { type: "skip" } as Record<string, any>;
62
+ } else {
63
+ return { type: "error", error: e } as Record<string, any>;
64
+ }
65
+ }
66
+ };
67
+
68
+ const PropsModule = await resolveProps({
69
+ propsModule: propsPath
70
+ ? await loadWithCss(propsPath)
71
+ : { [propsExportName]: (url: string) => ({url}) },
72
+ path: String(propsPath),
73
+ exportName: propsExportName,
74
+ url: route,
75
+ });
76
+ if (PropsModule.type !== "success") {
77
+ return PropsModule;
78
+ }
79
+ const PageModule = await resolvePage({
80
+ pageModule: pagePath
81
+ ? await loadWithCss(pagePath)
82
+ : { [pageExportName]: () => null },
83
+ path: String(pagePath),
84
+ exportName: pageExportName,
85
+ url: route,
86
+ });
87
+ if (PageModule.type !== "success") {
88
+ return PageModule;
89
+ }
90
+
91
+ // Add any additional CSS files
92
+ if (cssFiles) {
93
+ cssFiles.forEach((css) => cssModules.set(typeof css === "string" ? css : css.path, css));
94
+ cssFiles = Array.from(cssModules.values());
95
+ }
96
+ const url =
97
+ typeof moduleBaseURL === "string" && moduleBaseURL !== ""
98
+ ? new URL(route, moduleBaseURL).href
99
+ : route;
100
+ const stream = createRscStream({
101
+ Html: Html,
102
+ CssCollector: CssCollector,
103
+ Page: PageModule[pageExportName as keyof typeof PageModule],
104
+ props: PropsModule[propsExportName as keyof typeof PropsModule],
105
+ moduleBase: moduleBase,
106
+ moduleRootPath: moduleRootPath,
107
+ moduleBasePath: moduleBasePath,
108
+ moduleBaseURL: moduleBaseURL,
109
+ logger: logger,
110
+ cssFiles: Array.from(cssModules.values()),
111
+ route,
112
+ url,
113
+ pipableStreamOptions: pipableStreamOptions,
114
+ htmlProps: {},
115
+ root: root,
116
+ loader: loader,
117
+ inlineCss: inlineCss,
118
+ });
119
+
120
+ if (!stream) {
121
+ return { type: "skip" as const };
122
+ }
123
+
124
+ const assets: HandlerAssets = {
125
+ css: cssFiles,
126
+ bootstrapModules: pipableStreamOptions?.bootstrapModules ?? [],
127
+ };
128
+ return {
129
+ type: "success",
130
+ controller,
131
+ stream,
132
+ assets,
133
+ route: route,
134
+ };
135
+ }
@@ -0,0 +1,109 @@
1
+ import * as React from "react";
2
+ // @ts-ignore
3
+ import { renderToPipeableStream } from "react-server-dom-esm/server.node";
4
+ import type { PipeableStreamOptions } from "../worker/types.js";
5
+ import type { Logger } from "vite";
6
+ import type {
7
+ CreateHandlerOptions,
8
+ CssCollectorProps,
9
+ CssContent,
10
+ InlineCssCollectorProps,
11
+ } from "../types.js";
12
+
13
+ export function createRscStream<InlineCSS extends boolean = true>({
14
+ Html,
15
+ Page,
16
+ props,
17
+ loader = (id) => import(id).then((m) => m.default),
18
+ moduleRootPath,
19
+ moduleBasePath,
20
+ moduleBaseURL,
21
+ logger,
22
+ cssFiles = [],
23
+ route,
24
+ url,
25
+ pipableStreamOptions,
26
+ htmlProps,
27
+ inlineCss = true as InlineCSS,
28
+ CssCollector,
29
+ root,
30
+ }: {
31
+ Html: CreateHandlerOptions["Html"];
32
+ Page: React.ComponentType<any>;
33
+ loader: (id: string) => Promise<any>;
34
+ props: any;
35
+ moduleBase: string;
36
+ moduleRootPath: string;
37
+ moduleBasePath: string;
38
+ moduleBaseURL: string;
39
+ logger: Logger;
40
+ route: string;
41
+ url: string;
42
+ pipableStreamOptions?: PipeableStreamOptions;
43
+ htmlProps?: any;
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
+ })) {
54
+ const htmlIsFragment = Html == React.Fragment;
55
+ if (!htmlIsFragment) {
56
+ if (!htmlProps) {
57
+ htmlProps = {};
58
+ }
59
+ if (!("moduleBaseURL" in htmlProps)) {
60
+ htmlProps["moduleBaseURL"] = moduleBaseURL;
61
+ }
62
+ if (!("moduleBasePath" in htmlProps)) {
63
+ htmlProps["moduleBasePath"] = moduleBasePath;
64
+ }
65
+ if (!("moduleRootPath" in htmlProps)) {
66
+ htmlProps["moduleRootPath"] = moduleRootPath;
67
+ }
68
+ if (!("url" in htmlProps)) {
69
+ htmlProps["url"] = url;
70
+ }
71
+ if (!("route" in htmlProps)) {
72
+ htmlProps["route"] = route;
73
+ }
74
+ if (!("pageProps" in htmlProps)) {
75
+ htmlProps["pageProps"] = props;
76
+ }
77
+ }
78
+ const withCss = React.createElement(
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,
91
+ React.createElement(Page, props)
92
+ );
93
+ // Otherwise wrap with Html component
94
+ const content = htmlIsFragment
95
+ ? withCss
96
+ : React.createElement(Html, htmlProps, withCss);
97
+ try {
98
+ return renderToPipeableStream(
99
+ content,
100
+ moduleBasePath,
101
+ pipableStreamOptions
102
+ );
103
+ } catch (error) {
104
+ logger.error(`Failed to create stream for ${route}.`, {
105
+ error: error as Error,
106
+ });
107
+ return null;
108
+ }
109
+ }
@@ -4,8 +4,7 @@ import type {
4
4
  OutputChunk,
5
5
  } from "rollup";
6
6
  import { createInputNormalizer } from "./inputNormalizer.js";
7
- import { join } from "path";
8
- import { DEFAULT_CONFIG, resolveOptions } from "../config/index.js";
7
+ import { DEFAULT_CONFIG } from "../config/index.js";
9
8
 
10
9
  interface BundleManifestEntry {
11
10
  file: string;
@@ -70,7 +69,7 @@ export function getBundleManifest({
70
69
  }
71
70
 
72
71
  // Normalize both paths, removing the root prefix
73
- const [normalizedId, sourcePath] = normalizer(moduleId);
72
+ let [normalizedId, sourcePath] = normalizer(moduleId);
74
73
 
75
74
  // For virtual modules, use a consistent naming scheme
76
75
  let finalFileName = fileName;
@@ -91,12 +90,22 @@ export function getBundleManifest({
91
90
 
92
91
  finalFileName = virtualModules.get(virtualKey)!;
93
92
  }
93
+ // handle preserveModulesRoot
94
+ if(normalizedId.startsWith('\x00')){
95
+ normalizedId = normalizedId.slice(1);
96
+ }
97
+ if(sourcePath.startsWith('/')){
98
+ sourcePath = sourcePath.slice(1);
99
+ }
100
+ if(moduleBase && preserveModulesRoot && normalizedId?.startsWith(moduleBase + '/')) {
101
+ normalizedId = normalizedId.slice(moduleBase.length + 1);
102
+ }
94
103
  const bundleManifestEntry = [
95
104
  sourcePath,
96
105
  {
97
106
  file: finalFileName,
98
- name: normalizedId.startsWith('\x00') ? normalizedId.replace('\x00', '') : normalizedId,
99
- src: sourcePath.startsWith('/') ? sourcePath.slice(1) : sourcePath,
107
+ name: normalizedId,
108
+ src: sourcePath,
100
109
  isEntry: chunk.isEntry,
101
110
  ...(chunk.imports?.length > 0 ? { imports: chunk.imports } : {}),
102
111
  ...(chunk.dynamicImports?.length > 0 ? { dynamicImports: chunk.dynamicImports } : {}),
@@ -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
+ );
@@ -1,4 +1,4 @@
1
- import { join, relative, resolve } from "node:path";
1
+ import { join } from "node:path";
2
2
  import type { PluginContext } from "rollup";
3
3
  import type { ResolvedUserConfig, ResolvedUserOptions } from "../../server.js";
4
4
  import type { Manifest } from "vite";
@@ -15,26 +15,29 @@ export interface BuildLoaderOptions {
15
15
 
16
16
  export function createBuildLoader({
17
17
  root,
18
- userConfig,
18
+ userConfig: _userConfig,
19
19
  userOptions,
20
- pluginContext,
20
+ pluginContext: _pluginContext,
21
21
  serverManifest,
22
22
  clientManifest,
23
23
  }: BuildLoaderOptions) {
24
24
  const normalizer = createInputNormalizer({
25
25
  root,
26
- preserveModulesRoot: undefined,
27
- removeExtension: false,
26
+ preserveModulesRoot: userOptions.build.preserveModulesRoot === true ? userOptions.moduleBase : undefined,
27
+ removeExtension: true,
28
28
  });
29
29
  return async function buildLoader(id: string) {
30
30
  const [key, value] = normalizer(id);
31
+ if(value !== id){
32
+ console.warn(`[vite-plugin-react-server] Mismatch in build loader for ${id} !== ${value} (${key})`);
33
+ }
31
34
  // Remove leading slash if present
32
35
  const distDir = userOptions.build.outDir;
33
36
  const manifests = [clientManifest, serverManifest];
34
37
  // Try to find the module in the manifest
35
38
  for (const n of [0, 1]) {
36
39
  const manifest = manifests[n];
37
- const manifestEntry = manifest[key]
40
+ const manifestEntry = manifest[value]
38
41
  if (!manifestEntry) {
39
42
  continue;
40
43
  }
@@ -20,10 +20,8 @@ export async function initialize(data: { port: MessagePort }) {
20
20
 
21
21
  // CSS file tracking per page
22
22
  const cssFilesByPage = new Map<string, Set<string>>();
23
- let currentPage: string | null = null;
24
23
 
25
24
  export function setCurrentPage(page: string | null) {
26
- currentPage = page;
27
25
  if (page && !cssFilesByPage.has(page)) {
28
26
  cssFilesByPage.set(page, new Set());
29
27
  }
@@ -117,7 +117,7 @@ function transformServerModule(
117
117
  program: any,
118
118
  url: string,
119
119
  sourceMap: any,
120
- loader: any,
120
+ _loader: any,
121
121
  port: MessagePort | undefined
122
122
  ) {
123
123
  const body = program.body; // This entry list needs to be in source location order.
@@ -934,7 +934,7 @@ export async function transformSource(
934
934
  const newSrc = await transformModuleIfNeeded(
935
935
  transformedSource,
936
936
  context.url,
937
- (url: string, ctx: any, defaultLoad: any) =>
937
+ (url: string) =>
938
938
  loadClientImport(url, defaultTransformSource),
939
939
  context.data?.port!
940
940
  );
@@ -1,10 +1,41 @@
1
1
  import type { Node } from "estree";
2
- import MagicString from "magic-string";
3
2
  import type { StreamPluginOptions } from "../types.js";
4
3
  import { DEFAULT_CONFIG } from "../config/defaults.js";
4
+ import { basename } from "path";
5
5
 
6
6
  const REACT_DIRECTIVES = new Set(["use client", "use server"]);
7
7
 
8
+ function createSourceMap(id: string, code: string, mappings: string) {
9
+ return {
10
+ version: 3,
11
+ file: basename(id),
12
+ sources: [id],
13
+ sourcesContent: [code],
14
+ names: [],
15
+ mappings,
16
+ sourceRoot: "",
17
+ };
18
+ }
19
+
20
+ function removeRanges(code: string, ranges: Array<{ start: number; end: number }>) {
21
+ // Sort ranges in reverse order to not affect positions
22
+ ranges.sort((a, b) => b.start - a.start);
23
+
24
+ let result = code;
25
+ for (const range of ranges) {
26
+ result = result.slice(0, range.start) + result.slice(range.end);
27
+ }
28
+ return result;
29
+ }
30
+
31
+ function countLines(str: string): number {
32
+ let count = 1;
33
+ for (let i = 0; i < str.length; i++) {
34
+ if (str[i] === '\n') count++;
35
+ }
36
+ return count;
37
+ }
38
+
8
39
  export function reactPreservePlugin(_options: StreamPluginOptions): import("vite").Plugin {
9
40
  const meta: Record<string, Set<string>> = {};
10
41
 
@@ -35,8 +66,10 @@ export function reactPreservePlugin(_options: StreamPluginOptions): import("vite
35
66
  return null;
36
67
  }
37
68
 
38
- const magicString = new MagicString(code);
69
+ const rangesToRemove: Array<{ start: number; end: number }> = [];
39
70
  let hasChanged = false;
71
+ let lineCount = 1;
72
+ let mappings = "AAAA"; // Initial mapping for first line
40
73
 
41
74
  // Only look at top-level directives
42
75
  for (const node of ast.body) {
@@ -55,13 +88,20 @@ export function reactPreservePlugin(_options: StreamPluginOptions): import("vite
55
88
  directive = node.expression.value;
56
89
  }
57
90
 
58
- if (directive) {
91
+ if (directive && "start" in node && "end" in node) {
59
92
  meta[id] ||= new Set<string>();
60
93
  meta[id].add(directive);
61
-
62
- if ("start" in node && "end" in node) {
63
- magicString.remove(node.start as number, node.end as number);
64
- hasChanged = true;
94
+ rangesToRemove.push({
95
+ start: node.start as number,
96
+ end: node.end as number
97
+ });
98
+ hasChanged = true;
99
+
100
+ // Add mapping for each line removed
101
+ const removedLines = code.slice(node.start as number, node.end as number).split('\n').length - 1;
102
+ for (let i = 0; i < removedLines; i++) {
103
+ mappings += ";AACA";
104
+ lineCount++;
65
105
  }
66
106
  }
67
107
  }
@@ -70,9 +110,12 @@ export function reactPreservePlugin(_options: StreamPluginOptions): import("vite
70
110
  return null;
71
111
  }
72
112
 
113
+ const newCode = removeRanges(code, rangesToRemove);
114
+ const sourceMap = createSourceMap(id, code, mappings);
115
+
73
116
  return {
74
- code: magicString.toString(),
75
- map: magicString.generateMap({ hires: true }),
117
+ code: newCode,
118
+ map: sourceMap,
76
119
  meta: {
77
120
  directives: Array.from(meta[id] || []),
78
121
  },
@@ -91,16 +134,20 @@ export function reactPreservePlugin(_options: StreamPluginOptions): import("vite
91
134
  }
92
135
 
93
136
  if (chunkDirectives.size) {
94
- const magicString = new MagicString(code);
95
- magicString.prepend(
96
- Array.from(chunkDirectives)
97
- .map((d) => `"${d}";`)
98
- .join("\n") + "\n"
99
- );
137
+ const directivesCode = Array.from(chunkDirectives)
138
+ .map((d) => `"${d}";`)
139
+ .join("\n") + "\n";
140
+
141
+ const newCode = directivesCode + code;
142
+
143
+ // Create source map for the prepended directives
144
+ const lineCount = countLines(directivesCode);
145
+ const mappings = "AAAA" + ";AACA".repeat(lineCount - 1);
146
+ const sourceMap = createSourceMap(chunk.fileName, code, mappings);
100
147
 
101
148
  return {
102
- code: magicString.toString(),
103
- map: magicString.generateMap({ hires: true }),
149
+ code: newCode,
150
+ map: sourceMap,
104
151
  };
105
152
  }
106
153
 
@@ -12,21 +12,18 @@ import { dirname, join } from "node:path";
12
12
  import { getBundleManifest } from "../helpers/getBundleManifest.js";
13
13
  import { checkFilesExist } from "../checkFilesExist.js";
14
14
  import { resolvePages } from "../config/resolvePages.js";
15
- import { tryManifest } from "../helpers/tryManifest.js";
16
15
  import { createInputNormalizer } from "../helpers/inputNormalizer.js";
17
16
  import { createWorker } from "../worker/createWorker.js";
18
17
  import type { Worker } from "node:worker_threads";
19
- import { getPluginRoot } from "../config/getPaths.js";
20
18
  import { DEFAULT_CONFIG } from "../config/defaults.js";
21
19
  import type {
22
20
  RscRenderMessage,
23
21
  RscWorkerMessage,
24
22
  RscWorkerResponse,
25
23
  } from "../worker/types.js";
26
- import { createLogger } from "../utils/logger.js";
27
- import { readFileSync } from "node:fs";
24
+ import { MIME_TYPES } from "../config/mimeTypes.js";
25
+
28
26
 
29
- const log = createLogger("react-client");
30
27
  let userOptions: ResolvedUserOptions;
31
28
  let userConfig: ResolvedUserConfig;
32
29
  let clientManifest: Manifest = {};
@@ -44,9 +41,6 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
44
41
  }
45
42
  userOptions = resolvedOptions.userOptions;
46
43
  root = userOptions.projectRoot;
47
- const rscWorkerPath = join(getPluginRoot(), DEFAULT_CONFIG.RSC_WORKER_PATH);
48
-
49
- log.info("RSC worker path:" + rscWorkerPath);
50
44
 
51
45
  return {
52
46
  name: "vite:react-client",
@@ -64,7 +58,7 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
64
58
  if (configEnv.command === "serve" && !configEnv.isPreview && !worker) {
65
59
  worker = await createWorker({
66
60
  projectRoot: root,
67
- workerPath: rscWorkerPath,
61
+ workerPath: userOptions.rscWorkerPath,
68
62
  reverseCondition: true,
69
63
  });
70
64
  }
@@ -106,7 +100,7 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
106
100
  resolvedConfig = config;
107
101
  },
108
102
 
109
- async generateBundle(options, bundle) {
103
+ async generateBundle(_options, bundle) {
110
104
  // Create manifest entries for each chunk
111
105
  clientManifest = getBundleManifest({
112
106
  pluginContext: this,
@@ -147,84 +141,23 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
147
141
  const [key, value] = normalize(req.url);
148
142
  const fileRoot = key.startsWith("node_modules")
149
143
  ? root
150
- : join(root, userOptions.build.outDir, userOptions.build.client);
151
- if (value.endsWith(".js")) {
152
- try {
153
- const stats = await stat(join(fileRoot, value));
154
- if (stats.isFile()) {
155
- const content = await readFile(join(fileRoot, value), "utf-8");
156
- res.setHeader("Content-Type", "application/javascript");
157
- res.end(content);
158
- return;
159
- } else {
160
- next();
161
- }
162
- } catch (error) {
163
- const { manifest: clientManifest } = tryManifest({
164
- root,
165
- outDir: join(userOptions.build.outDir, userOptions.build.client),
166
- });
167
- const { manifest: serverManifest } = tryManifest({
168
- root,
169
- outDir: join(userOptions.build.outDir, userOptions.build.server),
170
- });
171
- if (clientManifest && value in clientManifest) {
172
- res.setHeader("Content-Type", "application/javascript");
173
- res.end(clientManifest[value]);
174
- return;
175
- } else if (serverManifest && value in serverManifest) {
176
- res.setHeader("Content-Type", "application/javascript");
177
- res.end(serverManifest[value]);
178
- return;
179
- }
180
- const foundClient =
181
- clientManifest &&
182
- Object.entries(clientManifest).find(
183
- ([key, value]) =>
184
- value === key ||
185
- value === value.file ||
186
- value === value.src ||
187
- value === value.name
188
- );
189
- if (foundClient) {
190
- res.setHeader("Content-Type", "application/javascript");
191
- res.end(foundClient);
192
- return;
193
- }
194
- const foundServer =
195
- serverManifest &&
196
- Object.entries(serverManifest).find(
197
- ([key, value]) =>
198
- value === key ||
199
- value === value.file ||
200
- value === value.src ||
201
- value === value.name
202
- );
203
-
204
- if (foundServer) {
205
- res.setHeader("Content-Type", "application/javascript");
206
- res.end(foundServer);
207
- return;
208
- }
209
- next();
210
- }
211
- } else {
212
- let html = '';
213
- try {
214
- const last = value.split('/').pop();
215
- if(!last?.includes('.')) {
216
- const isDir = await stat(join(fileRoot, value));
217
- if (isDir.isDirectory()) {
218
- html = readFileSync(join(fileRoot, value, 'index.html'), 'utf-8');
219
- res.setHeader("Content-Type", "text/html");
220
- res.end(html);
221
- return;
222
- }
223
- }
224
- } catch (error) {
225
-
144
+ : join(root, userOptions.build.outDir, userOptions.build.static);
145
+ try {
146
+ const filePath = join(fileRoot, value);
147
+ const stats = await stat(filePath);
148
+
149
+ if (stats.isFile()) {
150
+ const ext = value.slice(value.lastIndexOf('.'));
151
+ const contentType = MIME_TYPES[ext] || 'application/octet-stream';
152
+ res.setHeader('Content-Type', contentType);
153
+ const content = await readFile(filePath);
154
+ res.end(content);
155
+ return;
226
156
  }
227
157
  next();
158
+ } catch (error) {
159
+ console.log("Error serving static file:", error);
160
+ next();
228
161
  }
229
162
  });
230
163
  },
@@ -234,13 +167,11 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
234
167
  loader = server.ssrLoadModule;
235
168
  }
236
169
  if (!worker) {
237
- log.info("Creating RSC worker...");
238
170
  worker = await createWorker({
239
171
  projectRoot: root,
240
- workerPath: rscWorkerPath,
172
+ workerPath: userOptions.rscWorkerPath,
241
173
  condition: "react-client",
242
174
  });
243
- log.info("RSC worker created");
244
175
  }
245
176
  const normalize = createInputNormalizer({
246
177
  root,
@@ -323,7 +254,6 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
323
254
 
324
255
  case "ERROR":
325
256
  clearTimeout(timeout);
326
- log.error("Render error", message);
327
257
  if (!hasError) {
328
258
  hasError = true;
329
259
  res.statusCode = 500;
@@ -371,13 +301,13 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
371
301
  userOptions.build.preserveModulesRoot === true
372
302
  ? userOptions.moduleBase
373
303
  : "",
374
- moduleBaseURL: ``,
375
- moduleBasePath: '/',
304
+ moduleBaseURL: userOptions.moduleBaseURL,
305
+ moduleBasePath: userOptions.moduleBasePath,
306
+ moduleBase: userOptions.moduleBase,
376
307
  pipableStreamOptions: userOptions.pipableStreamOptions,
377
308
  cssFiles: []
378
309
  } satisfies RscRenderMessage);
379
310
  } catch (error) {
380
- log.error("Middleware error:", error);
381
311
  res.statusCode = 500;
382
312
  res.end(error instanceof Error ? error.message : String(error));
383
313
  }