vite-plugin-react-server 0.3.0 → 0.3.4

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 (113) hide show
  1. package/README.md +73 -40
  2. package/dist/assertServerCondition.d.ts +2 -0
  3. package/dist/assertServerCondition.d.ts.map +1 -0
  4. package/dist/bin/patch.js +51 -0
  5. package/dist/bin/patch.js.map +1 -0
  6. package/dist/build/createBuildConfig.d.ts +7 -6
  7. package/dist/build/createBuildConfig.d.ts.map +1 -1
  8. package/dist/build/mergeInputs.d.ts +5 -0
  9. package/dist/build/mergeInputs.d.ts.map +1 -0
  10. package/dist/helpers/inputNormalizer.d.ts +6 -0
  11. package/dist/helpers/inputNormalizer.d.ts.map +1 -0
  12. package/dist/helpers/normalizedRelativePath.d.ts +3 -1
  13. package/dist/helpers/normalizedRelativePath.d.ts.map +1 -1
  14. package/dist/helpers/tryManifest.d.ts +10 -3
  15. package/dist/helpers/tryManifest.d.ts.map +1 -1
  16. package/dist/html/createPageLoader.d.ts.map +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/options.d.ts +13 -8
  19. package/dist/options.d.ts.map +1 -1
  20. package/dist/plugin.d.ts +2 -7
  21. package/dist/plugin.d.ts.map +1 -1
  22. package/dist/react-client/plugin.js +1 -1
  23. package/dist/react-server/plugin.d.ts.map +1 -1
  24. package/dist/react-server/plugin.js +108 -61
  25. package/dist/react-server/plugin.js.map +1 -1
  26. package/dist/scripts/check-react-version.js +34 -0
  27. package/dist/scripts/check-react-version.js.map +1 -0
  28. package/dist/src/build/createBuildConfig.js +44 -0
  29. package/dist/src/build/createBuildConfig.js.map +1 -0
  30. package/dist/src/build/mergeInputs.js +16 -0
  31. package/dist/src/build/mergeInputs.js.map +1 -0
  32. package/dist/src/checkFilesExist.js.map +1 -0
  33. package/dist/src/collect-css-manifest.js.map +1 -0
  34. package/dist/src/components.js.map +1 -0
  35. package/dist/src/getEnv.js.map +1 -0
  36. package/dist/src/helpers/inputNormalizer.js +11 -0
  37. package/dist/src/helpers/inputNormalizer.js.map +1 -0
  38. package/dist/src/helpers/normalizedRelativePath.js +34 -0
  39. package/dist/src/helpers/normalizedRelativePath.js.map +1 -0
  40. package/dist/src/helpers/tryManifest.js +27 -0
  41. package/dist/src/helpers/tryManifest.js.map +1 -0
  42. package/dist/{html → src/html}/createPageLoader.js +3 -1
  43. package/dist/src/html/createPageLoader.js.map +1 -0
  44. package/dist/{options.js → src/options.js} +80 -24
  45. package/dist/src/options.js.map +1 -0
  46. package/dist/src/react-server/createHandler.js.map +1 -0
  47. package/dist/src/react-server/createRscStream.js.map +1 -0
  48. package/dist/src/resolvePage.js.map +1 -0
  49. package/dist/src/resolveProps.js.map +1 -0
  50. package/dist/src/worker/createHtmlStream.js +62 -0
  51. package/dist/src/worker/createHtmlStream.js.map +1 -0
  52. package/dist/{worker → src/worker}/createWorker.js +9 -8
  53. package/dist/src/worker/createWorker.js.map +1 -0
  54. package/dist/src/worker/renderPages.js.map +1 -0
  55. package/dist/types.d.ts +7 -2
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/worker/createWorker.d.ts +8 -1
  58. package/dist/worker/createWorker.d.ts.map +1 -1
  59. package/dist/worker/loader.js +7 -0
  60. package/dist/worker/loader.js.map +1 -0
  61. package/dist/worker/worker.js +112 -0
  62. package/dist/worker/worker.js.map +1 -0
  63. package/package.json +109 -111
  64. package/patches/react-server-dom-esm+0.0.1.patch +13424 -0
  65. package/scripts/bump-version.mjs +68 -0
  66. package/scripts/check-react-version.mjs +48 -0
  67. package/src/assertServerCondition.ts +13 -0
  68. package/src/build/createBuildConfig.ts +27 -44
  69. package/src/build/mergeInputs.ts +42 -0
  70. package/src/helpers/inputNormalizer.ts +22 -0
  71. package/src/helpers/normalizedRelativePath.ts +25 -25
  72. package/src/helpers/tryManifest.ts +19 -5
  73. package/src/html/createPageLoader.ts +2 -0
  74. package/src/options.ts +119 -47
  75. package/src/plugin.ts +4 -30
  76. package/src/react-server/createSsrHandler.ts +1 -1
  77. package/src/react-server/plugin.ts +116 -56
  78. package/src/types.ts +19 -1
  79. package/src/worker/createWorker.ts +12 -7
  80. package/tsconfig.json +2 -0
  81. package/dist/build/createBuildConfig.js +0 -55
  82. package/dist/build/createBuildConfig.js.map +0 -1
  83. package/dist/checkFilesExist.js.map +0 -1
  84. package/dist/collect-css-manifest.js.map +0 -1
  85. package/dist/components.js.map +0 -1
  86. package/dist/getEnv.js.map +0 -1
  87. package/dist/helpers/normalizedRelativePath.js +0 -31
  88. package/dist/helpers/normalizedRelativePath.js.map +0 -1
  89. package/dist/html/createPageLoader.js.map +0 -1
  90. package/dist/options.js.map +0 -1
  91. package/dist/plugin.js +0 -31
  92. package/dist/plugin.js.map +0 -1
  93. package/dist/react-server/createHandler.js.map +0 -1
  94. package/dist/react-server/createRscStream.js.map +0 -1
  95. package/dist/resolvePage.js.map +0 -1
  96. package/dist/resolveProps.js.map +0 -1
  97. package/dist/transformer/index.js +0 -54
  98. package/dist/transformer/index.js.map +0 -1
  99. package/dist/transformer/preserveDirectives.js +0 -72
  100. package/dist/transformer/preserveDirectives.js.map +0 -1
  101. package/dist/transformer/transformer.js +0 -80
  102. package/dist/transformer/transformer.js.map +0 -1
  103. package/dist/worker/createWorker.js.map +0 -1
  104. package/dist/worker/renderPages.js.map +0 -1
  105. /package/dist/{checkFilesExist.js → src/checkFilesExist.js} +0 -0
  106. /package/dist/{collect-css-manifest.js → src/collect-css-manifest.js} +0 -0
  107. /package/dist/{components.js → src/components.js} +0 -0
  108. /package/dist/{getEnv.js → src/getEnv.js} +0 -0
  109. /package/dist/{react-server → src/react-server}/createHandler.js +0 -0
  110. /package/dist/{react-server → src/react-server}/createRscStream.js +0 -0
  111. /package/dist/{resolvePage.js → src/resolvePage.js} +0 -0
  112. /package/dist/{resolveProps.js → src/resolveProps.js} +0 -0
  113. /package/dist/{worker → src/worker}/renderPages.js +0 -0
package/src/options.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import path from "node:path";
2
2
  import type { ConfigEnv, ResolvedConfig, UserConfig } from "vite";
3
- import type { ResolvedUserOptions, StreamPluginOptions } from "./types.js";
3
+ import type { ResolvedUserConfig, ResolvedUserOptions, StreamPluginOptions } from "./types.js";
4
+ import type { InputOption } from "rollup";
4
5
  // Default configuration values
5
6
  export const DEFAULT_CONFIG = {
6
7
  FILE_REGEX: /\.(m|c)?(j|t)sx?$/,
@@ -14,9 +15,9 @@ export const DEFAULT_CONFIG = {
14
15
  CLIENT_ENTRY: "/src/client.tsx",
15
16
  PAGE_EXPORT: "Page",
16
17
  PROPS_EXPORT: "props",
17
- // relative from plugin root
18
- WORKER_PATH: "worker/worker.tsx",
19
- LOADER_PATH: "worker/loader.ts",
18
+ // Use package name paths instead of relative paths
19
+ WORKER_PATH: "vite-plugin-react-server/worker",
20
+ LOADER_PATH: "vite-plugin-react-server/loader",
20
21
  RSC_EXTENSION: ".rsc",
21
22
  HTML: ({ children }: { children: any }) => children,
22
23
  COLLECT_CSS: true,
@@ -33,6 +34,10 @@ export const DEFAULT_CONFIG = {
33
34
  client: "dist/client",
34
35
  server: "dist/server",
35
36
  },
37
+ AUTO_DISCOVER: {
38
+ pagePattern: "**/*.page.tsx",
39
+ propsPattern: "**/*.props.ts",
40
+ },
36
41
  } as const;
37
42
 
38
43
  export const resolveConfig = <T extends ResolvedConfig>(
@@ -51,7 +56,7 @@ export const resolveConfig = <T extends ResolvedConfig>(
51
56
 
52
57
  export const resolveUserConfig = (
53
58
  condition: "react-client" | "react-server",
54
- input: string[],
59
+ input: InputOption,
55
60
  config: UserConfig,
56
61
  configEnv: ConfigEnv,
57
62
  userOptions: ResolvedUserOptions
@@ -59,8 +64,7 @@ export const resolveUserConfig = (
59
64
  | { type: "error"; error: Error }
60
65
  | {
61
66
  type: "success";
62
- userConfig: Required<Pick<UserConfig, "root" | "build" | "mode">> &
63
- Omit<UserConfig, "root" | "build" | "mode">;
67
+ userConfig: ResolvedUserConfig;
64
68
  } => {
65
69
  const isReactServer = condition === "react-server";
66
70
  const isViteServer = configEnv.command === "serve";
@@ -74,14 +78,17 @@ export const resolveUserConfig = (
74
78
  ...config.build,
75
79
  rollupOptions: {
76
80
  ...config.build?.rollupOptions,
77
- input: input
78
- }
79
- }
80
- }
81
+ input: input,
82
+ },
83
+ },
84
+ };
81
85
  }
82
86
  }
83
87
 
84
- if (typeof config.build?.assetsDir === 'string' && userOptions.assetsDir !== config.build?.assetsDir) {
88
+ if (
89
+ typeof config.build?.assetsDir === "string" &&
90
+ userOptions.assetsDir !== config.build?.assetsDir
91
+ ) {
85
92
  return {
86
93
  type: "error",
87
94
  error: new Error(
@@ -111,7 +118,7 @@ export const resolveUserConfig = (
111
118
  : "react-server condition was not set. Please use `NODE_OPTIONS='--conditions react-server' vite build --ssr`"
112
119
  ),
113
120
  };
114
- } else if (!configEnv.isSsrBuild && configEnv.command !== 'serve') {
121
+ } else if (!configEnv.isSsrBuild && configEnv.command !== "serve") {
115
122
  return {
116
123
  type: "error",
117
124
  error: new Error(
@@ -122,7 +129,16 @@ export const resolveUserConfig = (
122
129
  }
123
130
 
124
131
  const { root: configRoot, mode: configMode, ...configRest } = config;
125
- const { outDir: configOutDir, assetsDir: configAssetsDir, ssr: configSsr, manifest: configManifest, ssrManifest: configSsrManifest, target: configTarget, ...configBuildRest } = config.build ?? {};
132
+ const {
133
+ outDir: configOutDir,
134
+ assetsDir: configAssetsDir,
135
+ ssr: configSsr,
136
+ manifest: configManifest,
137
+ ssrManifest: configSsrManifest,
138
+ ssrEmitAssets: configSsrEmitAssets,
139
+ target: configTarget,
140
+ ...configBuildRest
141
+ } = config.build ?? {};
126
142
 
127
143
  return {
128
144
  type: "success",
@@ -135,6 +151,7 @@ export const resolveUserConfig = (
135
151
  ssr: configSsr ?? isReactServer,
136
152
  manifest: configManifest ?? true,
137
153
  ssrManifest: configSsrManifest ?? true,
154
+ ssrEmitAssets: configSsrEmitAssets ?? true,
138
155
  target: configTarget ?? "es2020",
139
156
  outDir:
140
157
  typeof configOutDir === "string"
@@ -146,7 +163,7 @@ export const resolveUserConfig = (
146
163
  typeof configAssetsDir === "string"
147
164
  ? configAssetsDir
148
165
  : isReactServer
149
- ? ''
166
+ ? ""
150
167
  : DEFAULT_CONFIG.CLIENT_ASSETS_DIR,
151
168
  },
152
169
  },
@@ -156,37 +173,63 @@ export const resolveUserConfig = (
156
173
  export const resolveOptions = (
157
174
  options: StreamPluginOptions
158
175
  ):
159
- | { type: "error"; error: Error }
160
176
  | {
161
177
  type: "success";
162
178
  userOptions: ResolvedUserOptions;
179
+ }
180
+ | {
181
+ type: "error";
182
+ error: Error;
163
183
  } => {
164
- const projectRoot = options.projectRoot ?? process.cwd();
184
+ const {
185
+ workerPath: optionsWorkerPath,
186
+ loaderPath: optionsLoaderPath,
187
+ projectRoot: optionsProjectRoot,
188
+ moduleBase: optionsModuleBase,
189
+ moduleBasePath: optionsModuleBasePath,
190
+ moduleBaseURL: optionsModuleBaseURL,
191
+ build: optionsBuild,
192
+ Page: optionsPage,
193
+ props: optionsProps,
194
+ Html: optionsHtml,
195
+ pageExportName: optionsPageExportName,
196
+ propsExportName: optionsPropsExportName,
197
+ collectCss: optionsCollectCss,
198
+ collectAssets: optionsCollectAssets,
199
+ assetsDir: optionsAssetsDir,
200
+ clientEntry: optionsClientEntry,
201
+ serverOutDir: optionsServerOutDir,
202
+ clientOutDir: optionsClientOutDir,
203
+ autoDiscover: optionsAutoDiscover,
204
+ moduleBaseExceptions: optionsModuleBaseExceptions,
205
+ ...restOptions
206
+ } = options;
207
+ const projectRoot = optionsProjectRoot ?? process.cwd();
165
208
  /** the module base can be assumed to not have a leading slash */
166
209
  const moduleBase =
167
- typeof options.moduleBase === "string"
168
- ? options.moduleBase.startsWith(path.sep)
169
- ? options.moduleBase.slice(path.sep.length)
170
- : options.moduleBase
210
+ typeof optionsModuleBase === "string"
211
+ ? optionsModuleBase.startsWith(path.sep)
212
+ ? optionsModuleBase.slice(path.sep.length)
213
+ : optionsModuleBase
171
214
  : DEFAULT_CONFIG.MODULE_BASE;
172
215
 
173
216
  if (
174
- typeof options.moduleBase === "string" &&
175
- options.moduleBase !== moduleBase
217
+ typeof optionsModuleBase === "string" &&
218
+ optionsModuleBase !== moduleBase
176
219
  ) {
177
220
  return {
178
221
  type: "error",
179
222
  error: new Error(
180
- `moduleBase ${options.moduleBase} is invalid, should be like ${moduleBase}`
223
+ `moduleBase ${optionsModuleBase} is invalid, should be like ${moduleBase}`
181
224
  ),
182
225
  };
183
226
  }
184
227
 
185
228
  const moduleBasePath =
186
- typeof options.moduleBasePath === "string"
187
- ? !options.moduleBasePath.startsWith(path.sep)
188
- ? `${path.sep}${options.moduleBasePath}`
189
- : options.moduleBasePath
229
+ typeof optionsModuleBasePath === "string"
230
+ ? !optionsModuleBasePath.startsWith(path.sep)
231
+ ? `${path.sep}${optionsModuleBasePath}`
232
+ : optionsModuleBasePath
190
233
  : `${path.sep}${moduleBase}`;
191
234
 
192
235
  if (!moduleBasePath.includes(moduleBase)) {
@@ -199,10 +242,10 @@ export const resolveOptions = (
199
242
  }
200
243
 
201
244
  const moduleBaseURL =
202
- typeof options.moduleBaseURL === "string"
203
- ? !options.moduleBaseURL.endsWith(moduleBasePath)
204
- ? path.join(options.moduleBaseURL, moduleBasePath)
205
- : options.moduleBaseURL
245
+ typeof optionsModuleBaseURL === "string"
246
+ ? !optionsModuleBaseURL.endsWith(moduleBasePath)
247
+ ? path.join(optionsModuleBaseURL, moduleBasePath)
248
+ : optionsModuleBaseURL
206
249
  : moduleBasePath;
207
250
 
208
251
  if (!moduleBaseURL.includes(moduleBasePath)) {
@@ -215,41 +258,70 @@ export const resolveOptions = (
215
258
  }
216
259
 
217
260
  if (
218
- typeof options.moduleBaseURL === "string" &&
219
- options.moduleBaseURL !== moduleBaseURL
261
+ typeof optionsModuleBaseURL === "string" &&
262
+ optionsModuleBaseURL !== moduleBaseURL
220
263
  ) {
221
264
  return {
222
265
  type: "error",
223
266
  error: new Error(
224
- `moduleBaseURL ${options.moduleBaseURL} is invalid, should be like ${moduleBaseURL}`
267
+ `moduleBaseURL ${optionsModuleBaseURL} is invalid, should be like ${moduleBaseURL}`
225
268
  ),
226
269
  };
227
270
  }
228
271
 
229
- const build = options.build
272
+ const build = optionsBuild
230
273
  ? {
231
- client: options.build.client ?? DEFAULT_CONFIG.BUILD.client,
232
- pages: options.build.pages ?? DEFAULT_CONFIG.BUILD.pages,
233
- server: options.build.server ?? DEFAULT_CONFIG.BUILD.server,
274
+ client: optionsBuild.client ?? DEFAULT_CONFIG.BUILD.client,
275
+ pages: optionsBuild.pages ?? DEFAULT_CONFIG.BUILD.pages,
276
+ server: optionsBuild.server ?? DEFAULT_CONFIG.BUILD.server,
234
277
  }
235
278
  : DEFAULT_CONFIG.BUILD;
236
279
 
280
+ const autoDiscover =
281
+ typeof optionsAutoDiscover === "object"
282
+ ? {
283
+ pagePattern:
284
+ typeof optionsAutoDiscover.pagePattern === "string"
285
+ ? optionsAutoDiscover.pagePattern
286
+ : DEFAULT_CONFIG.AUTO_DISCOVER.pagePattern,
287
+ propsPattern:
288
+ typeof optionsAutoDiscover.propsPattern === "string"
289
+ ? optionsAutoDiscover.propsPattern
290
+ : DEFAULT_CONFIG.AUTO_DISCOVER.propsPattern,
291
+ }
292
+ : DEFAULT_CONFIG.AUTO_DISCOVER;
293
+
294
+ const workerPath = typeof optionsWorkerPath === "string" ? optionsWorkerPath : DEFAULT_CONFIG.WORKER_PATH;
295
+ const loaderPath = typeof optionsLoaderPath === "string" ? optionsLoaderPath : DEFAULT_CONFIG.LOADER_PATH;
237
296
  return {
238
297
  type: "success",
239
298
  userOptions: {
299
+ ...DEFAULT_CONFIG,
300
+ ...restOptions,
240
301
  moduleBase,
241
302
  moduleBasePath,
242
303
  moduleBaseURL,
243
304
  build,
244
- Page: options.Page ?? DEFAULT_CONFIG.PAGE,
245
- props: options.props ?? DEFAULT_CONFIG.PROPS,
246
- Html: options.Html ?? DEFAULT_CONFIG.HTML,
247
- pageExportName: options.pageExportName ?? DEFAULT_CONFIG.PAGE_EXPORT,
248
- propsExportName: options.propsExportName ?? DEFAULT_CONFIG.PROPS_EXPORT,
249
- collectCss: options.collectCss ?? DEFAULT_CONFIG.COLLECT_CSS,
250
- collectAssets: options.collectAssets ?? DEFAULT_CONFIG.COLLECT_ASSETS,
305
+ Page: optionsPage ?? DEFAULT_CONFIG.PAGE,
306
+ props: optionsProps ?? DEFAULT_CONFIG.PROPS,
307
+ Html: optionsHtml ?? DEFAULT_CONFIG.HTML,
308
+ pageExportName: optionsPageExportName ?? DEFAULT_CONFIG.PAGE_EXPORT,
309
+ propsExportName: optionsPropsExportName ?? DEFAULT_CONFIG.PROPS_EXPORT,
310
+ collectCss: optionsCollectCss ?? DEFAULT_CONFIG.COLLECT_CSS,
311
+ collectAssets: optionsCollectAssets ?? DEFAULT_CONFIG.COLLECT_ASSETS,
251
312
  projectRoot: projectRoot,
252
- assetsDir: options.assetsDir ?? DEFAULT_CONFIG.CLIENT_ASSETS_DIR,
313
+ assetsDir: optionsAssetsDir ?? DEFAULT_CONFIG.CLIENT_ASSETS_DIR,
314
+ workerPath: workerPath,
315
+ loaderPath: loaderPath,
316
+ clientEntry: optionsClientEntry ?? DEFAULT_CONFIG.CLIENT_ENTRY,
317
+ serverOutDir: optionsServerOutDir ?? DEFAULT_CONFIG.BUILD.server,
318
+ clientOutDir: optionsClientOutDir ?? DEFAULT_CONFIG.BUILD.client,
319
+ autoDiscover: autoDiscover,
320
+ moduleBaseExceptions: [
321
+ workerPath,
322
+ loaderPath,
323
+ ...(optionsModuleBaseExceptions ?? []),
324
+ ],
253
325
  } satisfies ResolvedUserOptions,
254
326
  };
255
327
  };
package/src/plugin.ts CHANGED
@@ -1,31 +1,5 @@
1
- import { resolveOptions } from "./options.js";
2
- import { viteReactClientTransformPlugin } from "./transformer/index.js";
3
- import { preserveDirectives } from "./transformer/preserveDirectives.js";
4
- import type { StreamPluginOptions } from "./types.js";
1
+ import "./assertServerCondition.js";
2
+ export { reactStreamPlugin } from "./react-server/plugin.js";
5
3
 
6
- export const getCondition = (options: { env?: typeof process.env } = {}) => {
7
- const nodeOptions = options?.env?.['NODE_OPTIONS'] ?? process.env['NODE_OPTIONS'];
8
- return nodeOptions?.match(/--conditions=react-server/) ? "server" : "client";
9
- };
10
-
11
- export const reactStreamPlugin = async (options: StreamPluginOptions) => {
12
- const condition = getCondition();
13
- try {
14
- const resolvedOptions = resolveOptions(options);
15
- if (resolvedOptions.type === "error") {
16
- throw resolvedOptions.error;
17
- }
18
- options = resolvedOptions.userOptions;
19
- } catch (error) {
20
- throw new Error(
21
- `[vite:react-stream:${condition}] ${(error as Error).message}`
22
- );
23
- }
24
- return condition === "server"
25
- ? [
26
- (await import(`./react-server/plugin.js`)).reactStreamPlugin(options),
27
- viteReactClientTransformPlugin(),
28
- preserveDirectives(),
29
- ]
30
- : [(await import(`./react-client/plugin.js`)).reactStreamPlugin(options)];
31
- };
4
+ // the main plugin is version is the server version, if you want the client version, use the `vite-plugin-react-server/client` import
5
+ // this is because the workflow assumes main thread = react server condition
@@ -30,7 +30,7 @@ export function createSsrHandler(
30
30
  const worker = new Worker(
31
31
  options?.workerPath
32
32
  ? resolve(server.config.root, options?.workerPath)
33
- : resolve(__dirname, "..", DEFAULT_CONFIG.WORKER_PATH),
33
+ : DEFAULT_CONFIG.WORKER_PATH,
34
34
  {
35
35
  env: {
36
36
  NODE_OPTIONS: "--conditions ''",
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import type { ServerResponse } from "node:http";
3
- import { resolve as resolvePath } from "node:path";
3
+ import { join, relative, resolve, resolve as resolvePath } from "node:path";
4
4
  import { performance } from "node:perf_hooks";
5
5
  import { Worker } from "node:worker_threads";
6
6
  import type { Plugin as RollupPlugin } from "rollup";
@@ -21,15 +21,18 @@ import type { BuildTiming, ReactStreamPluginMeta } from "../types.js";
21
21
  import { type StreamPluginOptions } from "../types.js";
22
22
  import { createWorker } from "../worker/createWorker.js";
23
23
  import { createHandler } from "./createHandler.js";
24
+ import { tryManifest } from "../helpers/tryManifest.js";
25
+ import { createNormalizedRelativePath } from "../helpers/normalizedRelativePath.js";
24
26
 
25
- let pageSet: Set<string>;
26
- let pageMap: Map<string, string>;
27
+ let files: Awaited<ReturnType<typeof checkFilesExist>>;
28
+ let env: Awaited<ReturnType<typeof getEnv>>;
27
29
  let worker: Worker;
28
30
  let config: ResolvedConfig;
29
31
  let cssModules = new Set<string>();
30
32
  let clientComponents = new Map<string, string>();
31
33
  let define: Record<string, string>;
32
34
  let buildCssFiles = new Set<string>();
35
+ let root: string = process.cwd();
33
36
 
34
37
  interface BuildStats {
35
38
  htmlFiles: number;
@@ -127,7 +130,7 @@ export async function reactStreamPlugin(
127
130
  propsExportName: userOptions.propsExportName,
128
131
  moduleBase: userOptions.moduleBase,
129
132
  moduleBasePath: userOptions.moduleBasePath,
130
- projectRoot: server.config.root,
133
+ projectRoot: server.config.root ?? userOptions.projectRoot,
131
134
  },
132
135
  {
133
136
  cssFiles: Array.from(cssModules),
@@ -148,39 +151,70 @@ export async function reactStreamPlugin(
148
151
 
149
152
  async config(config, configEnv): Promise<UserConfig> {
150
153
  const resolvedPages = await resolvePages(userOptions.build.pages);
151
- if(resolvedPages.type === 'error') {
154
+ if (resolvedPages.type === "error") {
152
155
  throw resolvedPages.error;
153
156
  }
154
157
  const { pages } = resolvedPages;
158
+ env = getEnv(config, configEnv);
159
+ define = env.define;
160
+ files = await checkFilesExist(
161
+ pages,
162
+ userOptions,
163
+ config.root ?? userOptions.projectRoot
164
+ );
165
+ root = config.root ?? userOptions.projectRoot;
155
166
  const resolvedConfig = resolveUserConfig(
156
167
  "react-server",
157
- pages,
168
+ [...pages, userOptions.workerPath, userOptions.loaderPath],
158
169
  config,
159
170
  configEnv,
160
171
  userOptions
161
172
  );
162
- if(resolvedConfig.type === "error") {
173
+ if (resolvedConfig.type === "error") {
163
174
  throw resolvedConfig.error;
164
175
  }
165
176
  const { userConfig } = resolvedConfig;
177
+ console.log({
178
+ worker: userOptions.workerPath,
179
+ loader: userOptions.loaderPath,
180
+ });
181
+ const entriesClient = Object.fromEntries([
182
+ ...Array.from(files.pageMap.entries()).map(([key, value]) => [
183
+ key,
184
+ relative(root, value),
185
+ ]),
186
+ ...Array.from(files.propsMap.entries()).map(([key, value]) => [
187
+ key,
188
+ relative(root, value),
189
+ ]),
190
+ ]);
191
+ const entriesResolved = Object.fromEntries(
192
+ (Object.entries(entriesClient) as [string, string][]).map(
193
+ ([key, entry]) => {
194
+ if (typeof entry !== "string") {
195
+ return [key, entry];
196
+ }
166
197
 
167
- const envResult = getEnv(userConfig, configEnv);
168
- const files = await checkFilesExist(pages, userOptions, userConfig.root);
169
- pageSet = files.pageSet;
170
- pageMap = files.pageMap;
171
- define = envResult.define;
172
- const entries = Array.from(
173
- new Set([
174
- ...Array.from(files.pageSet.values()),
175
- ...Array.from(files.propsSet.values()),
176
- ]).values()
198
+ return [key, entry];
199
+ }
200
+ )
177
201
  );
202
+ const serverEntries = {
203
+ ...entriesResolved,
204
+ ["worker/worker"]: userOptions.workerPath,
205
+ ["worker/loader"]: userOptions.loaderPath,
206
+ };
178
207
 
179
208
  const buildConfig = createBuildConfig({
180
- root: config.root ?? process.cwd(),
181
- base: config.base ?? envResult.publicUrl,
182
- outDir: config.build?.outDir ?? "dist/server",
183
- entries,
209
+ input: serverEntries,
210
+ userConfig: userConfig,
211
+ userOptions: userOptions,
212
+ root,
213
+ moduleBaseExceptions: [
214
+ userOptions.workerPath,
215
+ userOptions.loaderPath,
216
+ ...userOptions.moduleBaseExceptions,
217
+ ],
184
218
  });
185
219
  return {
186
220
  ...buildConfig,
@@ -192,44 +226,70 @@ export async function reactStreamPlugin(
192
226
  timing.buildStart = performance.now();
193
227
  },
194
228
  async closeBundle() {
195
- if(!config) return;
229
+ if (!config) return;
196
230
  console.log("RSC CLOSE BUNDLE CALLED");
197
- if (!pageSet?.size) return;
231
+ if (!files.pageSet.size) return;
198
232
  timing.renderStart = performance.now();
199
233
 
200
234
  try {
201
- const manifest = JSON.parse(
202
- readFileSync(
203
- resolvePath(
204
- config.root,
205
- config.build.outDir,
206
- ".vite",
207
- "manifest.json"
208
- ),
209
- "utf-8"
210
- )
211
- ) as Manifest;
212
- const clientManifest = JSON.parse(
213
- readFileSync(
214
- resolvePath(
215
- config.root,
216
- userOptions.build.client,
217
- ".vite",
218
- "manifest.json"
219
- ),
220
- "utf-8"
221
- )
222
- ) as Manifest;
235
+ const resolvedServerManifest = tryManifest({
236
+ root,
237
+ outDir: userOptions.build.server,
238
+ ssrManifest: false,
239
+ });
240
+ if (resolvedServerManifest.type === "error") {
241
+ console.error(
242
+ "[vite-react-stream] Server Build failed, can not build without a server manifest. Please set `manifest: true` in your vite config.",
243
+ resolvedServerManifest.error
244
+ );
245
+ return;
246
+ }
247
+ const { manifest: serverManifest } = resolvedServerManifest;
248
+
249
+ // get worker path from server manifest
250
+ const workerPath =
251
+ serverManifest[userOptions.workerPath]?.file ??
252
+ serverManifest[relative(root, userOptions.workerPath)]?.file ??
253
+ serverManifest[
254
+ relative(
255
+ join(root, userOptions.build.server),
256
+ userOptions.workerPath
257
+ )
258
+ ]?.file;
259
+ if (!workerPath) {
260
+ console.log(serverManifest, userOptions.build.server);
261
+ throw new Error(
262
+ `Worker path not found in server manifest, tried: ${userOptions.workerPath}, ${relative(root, userOptions.workerPath)}, ${join(root, userOptions.build.server, userOptions.workerPath)}`
263
+ );
264
+ }
265
+ console.log("workerPath", workerPath);
266
+ // client
267
+ const resolvedClientManifest = tryManifest({
268
+ root,
269
+ outDir: userOptions.build.client,
270
+ ssrManifest: false,
271
+ });
272
+ if (resolvedClientManifest.type === "error") {
273
+ console.error(
274
+ "[vite-react-stream] Server Build failed, can not build without a client manifest. Make sure to run the client build before the server build and set `manifest: true` in your vite config.",
275
+ resolvedClientManifest.error
276
+ );
277
+ return;
278
+ }
279
+ const { manifest: clientManifest } = resolvedClientManifest;
280
+
223
281
  // Create a single worker for all routes
224
282
  if (!worker)
225
- worker = await createWorker(
226
- config.root,
227
- config.build.outDir,
228
- "worker.js",
229
- process.env["NODE_ENV"] === "development" ? "development" : "production"
230
- );
283
+ worker = await createWorker({
284
+ workerPath: join(root, userOptions.build.server, workerPath),
285
+ nodePath: process.env["NODE_PATH"] ?? resolve(root, "node_modules"),
286
+ mode:
287
+ process.env["NODE_ENV"] === "development"
288
+ ? "development"
289
+ : "production",
290
+ });
231
291
  // this is based on the user config - the routes should lead to a page and props but the rendering is agnostic of that
232
- const routes = Array.from(pageMap.keys());
292
+ const routes = Array.from(files.pageMap.keys());
233
293
  const indexEntry = clientManifest["index.html"];
234
294
  if (!indexEntry) {
235
295
  throw new Error("root /index.html not found");
@@ -250,19 +310,19 @@ export async function reactStreamPlugin(
250
310
  moduleBase: userOptions.moduleBase,
251
311
  moduleBasePath: userOptions.moduleBasePath,
252
312
  moduleBaseURL: userOptions.moduleBaseURL,
253
- projectRoot: config.root,
313
+ projectRoot: root,
254
314
  },
255
315
  worker: worker,
256
- manifest: clientManifest as Manifest,
316
+ manifest: clientManifest,
257
317
  loader: createPageLoader({
258
- manifest,
318
+ manifest: clientManifest,
259
319
  root: config.root,
260
320
  outDir: config.build.outDir,
261
321
  moduleBase: userOptions.moduleBase,
262
322
  alwaysRegisterServer: false,
263
323
  alwaysRegisterClient: false,
264
324
  registerServer: [],
265
- registerClient: Object.keys(clientManifest).filter(
325
+ registerClient: Object.keys(resolvedClientManifest).filter(
266
326
  (key) =>
267
327
  key.endsWith(".client.tsx") && clientManifest[key].isEntry
268
328
  ),
package/src/types.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import type {
2
2
  AliasOptions,
3
+ BuildOptions,
3
4
  Connect,
4
5
  Logger,
5
6
  Manifest,
6
7
  ModuleGraph,
8
+ UserConfig,
7
9
  ViteDevServer,
8
10
  } from "vite";
9
11
 
@@ -35,8 +37,23 @@ export type ResolvedUserOptions = Required<
35
37
  | "collectCss"
36
38
  | "collectAssets"
37
39
  | "assetsDir"
40
+ | "workerPath"
41
+ | "loaderPath"
42
+ | "clientEntry"
43
+ | "serverOutDir"
44
+ | "clientOutDir"
45
+ | "moduleBaseExceptions"
38
46
  >
39
- > & { build: NonNullable<Required<StreamPluginOptions["build"]>> };
47
+ > & {
48
+ build: NonNullable<Required<StreamPluginOptions["build"]>>;
49
+ autoDiscover: NonNullable<Required<StreamPluginOptions["autoDiscover"]>>;
50
+ };
51
+
52
+ export type ResolvedUserConfig = Required<Pick<UserConfig, "root" | "mode">> &
53
+ Omit<UserConfig, "root" | "mode" | "build"> & {
54
+ build: Required<Pick<BuildOptions, "target" | "outDir" | "assetsDir" | "ssr" | "ssrEmitAssets" | "ssrManifest" | "manifest">> &
55
+ Partial<Omit<BuildOptions, "target" | "outDir" | "assetsDir" | "ssr" | "ssrEmitAssets" | "ssrManifest" | "manifest">>;
56
+ };
40
57
 
41
58
  export interface StreamPluginOptions {
42
59
  projectRoot?: string;
@@ -70,6 +87,7 @@ export interface StreamPluginOptions {
70
87
  collectCss?: boolean;
71
88
  collectAssets?: boolean;
72
89
  build?: BuildConfig;
90
+ moduleBaseExceptions?: string[];
73
91
  }
74
92
 
75
93
  export interface CreateHandlerOptions<T = any> {
@@ -1,23 +1,28 @@
1
- import { resolve } from "node:path";
1
+ import { join } from "node:path";
2
2
  import { Worker } from "node:worker_threads";
3
3
 
4
+ type CreateWorkerOptions = {
5
+ workerPath: string;
6
+ nodePath: string;
7
+ mode: "production" | "development";
8
+ workerOptions?: WorkerOptions;
9
+ };
10
+
4
11
  export async function createWorker(
5
- projectRoot: string,
6
- outDir: string,
7
- fileName: string,
8
- mode: "production" | "development"
12
+ options: CreateWorkerOptions
9
13
  ) {
14
+ const { workerPath, nodePath, mode, workerOptions } = options;
10
15
  console.log("[Worker] Creating worker...");
11
- const workerPath = resolve(projectRoot, outDir, fileName);
12
16
  console.log("[Worker] Worker path:", workerPath);
13
17
 
14
18
  try {
15
19
  const worker = new Worker(workerPath, {
16
20
  env: {
17
21
  NODE_OPTIONS: "",
18
- NODE_PATH: resolve(projectRoot, "node_modules"),
19
22
  NODE_ENV: mode,
23
+ NODE_PATH: nodePath,
20
24
  },
25
+ ...workerOptions,
21
26
  });
22
27
  worker.setMaxListeners(1000);
23
28