vite-plugin-react-server 0.3.0 → 0.3.3

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 (109) 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/src/build/createBuildConfig.js +44 -0
  27. package/dist/src/build/createBuildConfig.js.map +1 -0
  28. package/dist/src/build/mergeInputs.js +16 -0
  29. package/dist/src/build/mergeInputs.js.map +1 -0
  30. package/dist/src/checkFilesExist.js.map +1 -0
  31. package/dist/src/collect-css-manifest.js.map +1 -0
  32. package/dist/src/components.js.map +1 -0
  33. package/dist/src/getEnv.js.map +1 -0
  34. package/dist/src/helpers/inputNormalizer.js +11 -0
  35. package/dist/src/helpers/inputNormalizer.js.map +1 -0
  36. package/dist/src/helpers/normalizedRelativePath.js +34 -0
  37. package/dist/src/helpers/normalizedRelativePath.js.map +1 -0
  38. package/dist/src/helpers/tryManifest.js +27 -0
  39. package/dist/src/helpers/tryManifest.js.map +1 -0
  40. package/dist/{html → src/html}/createPageLoader.js +3 -1
  41. package/dist/src/html/createPageLoader.js.map +1 -0
  42. package/dist/{options.js → src/options.js} +80 -24
  43. package/dist/src/options.js.map +1 -0
  44. package/dist/src/react-server/createHandler.js.map +1 -0
  45. package/dist/src/react-server/createRscStream.js.map +1 -0
  46. package/dist/src/resolvePage.js.map +1 -0
  47. package/dist/src/resolveProps.js.map +1 -0
  48. package/dist/src/worker/createHtmlStream.js +62 -0
  49. package/dist/src/worker/createHtmlStream.js.map +1 -0
  50. package/dist/{worker → src/worker}/createWorker.js +9 -8
  51. package/dist/src/worker/createWorker.js.map +1 -0
  52. package/dist/src/worker/renderPages.js.map +1 -0
  53. package/dist/types.d.ts +7 -2
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/worker/createWorker.d.ts +8 -1
  56. package/dist/worker/createWorker.d.ts.map +1 -1
  57. package/dist/worker/loader.js +7 -0
  58. package/dist/worker/loader.js.map +1 -0
  59. package/dist/worker/worker.js +112 -0
  60. package/dist/worker/worker.js.map +1 -0
  61. package/package.json +108 -111
  62. package/patches/react-server-dom-esm+0.0.1.patch +14519 -0
  63. package/src/assertServerCondition.ts +13 -0
  64. package/src/build/createBuildConfig.ts +27 -44
  65. package/src/build/mergeInputs.ts +42 -0
  66. package/src/helpers/inputNormalizer.ts +22 -0
  67. package/src/helpers/normalizedRelativePath.ts +25 -25
  68. package/src/helpers/tryManifest.ts +19 -5
  69. package/src/html/createPageLoader.ts +2 -0
  70. package/src/options.ts +119 -47
  71. package/src/plugin.ts +4 -30
  72. package/src/react-server/createSsrHandler.ts +1 -1
  73. package/src/react-server/plugin.ts +116 -56
  74. package/src/types.ts +19 -1
  75. package/src/worker/createWorker.ts +12 -7
  76. package/tsconfig.json +2 -0
  77. package/dist/build/createBuildConfig.js +0 -55
  78. package/dist/build/createBuildConfig.js.map +0 -1
  79. package/dist/checkFilesExist.js.map +0 -1
  80. package/dist/collect-css-manifest.js.map +0 -1
  81. package/dist/components.js.map +0 -1
  82. package/dist/getEnv.js.map +0 -1
  83. package/dist/helpers/normalizedRelativePath.js +0 -31
  84. package/dist/helpers/normalizedRelativePath.js.map +0 -1
  85. package/dist/html/createPageLoader.js.map +0 -1
  86. package/dist/options.js.map +0 -1
  87. package/dist/plugin.js +0 -31
  88. package/dist/plugin.js.map +0 -1
  89. package/dist/react-server/createHandler.js.map +0 -1
  90. package/dist/react-server/createRscStream.js.map +0 -1
  91. package/dist/resolvePage.js.map +0 -1
  92. package/dist/resolveProps.js.map +0 -1
  93. package/dist/transformer/index.js +0 -54
  94. package/dist/transformer/index.js.map +0 -1
  95. package/dist/transformer/preserveDirectives.js +0 -72
  96. package/dist/transformer/preserveDirectives.js.map +0 -1
  97. package/dist/transformer/transformer.js +0 -80
  98. package/dist/transformer/transformer.js.map +0 -1
  99. package/dist/worker/createWorker.js.map +0 -1
  100. package/dist/worker/renderPages.js.map +0 -1
  101. /package/dist/{checkFilesExist.js → src/checkFilesExist.js} +0 -0
  102. /package/dist/{collect-css-manifest.js → src/collect-css-manifest.js} +0 -0
  103. /package/dist/{components.js → src/components.js} +0 -0
  104. /package/dist/{getEnv.js → src/getEnv.js} +0 -0
  105. /package/dist/{react-server → src/react-server}/createHandler.js +0 -0
  106. /package/dist/{react-server → src/react-server}/createRscStream.js +0 -0
  107. /package/dist/{resolvePage.js → src/resolvePage.js} +0 -0
  108. /package/dist/{resolveProps.js → src/resolveProps.js} +0 -0
  109. /package/dist/{worker → src/worker}/renderPages.js +0 -0
@@ -0,0 +1,13 @@
1
+ function assertServerCondition<P extends typeof process>(p: P): asserts p is P & { env: { NODE_OPTIONS: string } } {
2
+ const nodeOptions = p.env['NODE_OPTIONS'];
3
+ if (!nodeOptions?.match(/--conditions[= ]react-server/)) {
4
+ if(!nodeOptions?.match(/--conditions/)) {
5
+ console.warn(`process.env['NODE_OPTIONS'] is missing \`--conditions\` flag, it should be like \`--conditions=react-server\` or \`--conditions react-server\`, but was ${JSON.stringify(process.env['NODE_OPTIONS'])}`);
6
+ }
7
+ if(!nodeOptions?.match(/react-server/)) {
8
+ throw new Error(`process.env['NODE_OPTIONS'] is missing \`react-server\` flag, it should be like \`--conditions=react-server\` or \`--conditions react-server\`, but was ${JSON.stringify(process.env['NODE_OPTIONS'])}`);
9
+ }
10
+ }
11
+ return undefined;
12
+ };
13
+ assertServerCondition(process);
@@ -1,62 +1,43 @@
1
- import { dirname, resolve } from "node:path";
2
- import { fileURLToPath } from "node:url";
3
1
  import type { InlineConfig } from "vite";
4
- import { DEFAULT_CONFIG } from "../options.js";
5
- import type { StreamPluginOptions } from "../types.js";
6
- const __dirname = dirname(fileURLToPath(import.meta.url));
2
+ import type { ResolvedUserConfig, ResolvedUserOptions } from "../types.js";
3
+ import type { InputOption } from "rollup";
4
+ import { mergeInputs } from "./mergeInputs.js";
5
+ import { createInputNormalizer } from "../helpers/inputNormalizer.js";
7
6
 
8
7
  type CreateBuildConfigOptions = {
8
+ input: InputOption;
9
+ userOptions: ResolvedUserOptions;
10
+ userConfig: ResolvedUserConfig;
9
11
  root: string;
10
- base: string;
11
- outDir: string;
12
- entries: string[];
13
- options?: StreamPluginOptions;
12
+ moduleBaseExceptions: string[];
14
13
  };
15
14
 
15
+
16
16
  export function createBuildConfig({
17
17
  root,
18
- base,
19
- outDir,
20
- entries,
21
- options,
18
+ input,
19
+ userOptions,
20
+ userConfig,
21
+ moduleBaseExceptions
22
22
  }: CreateBuildConfigOptions) {
23
- // Transform entries into proper input format with unique keys
24
- const entryInputs = Object.fromEntries(
25
- entries.map((entry) => {
26
- // Get the path relative to root
27
- const relativePath = entry.replace(root + "/", "");
28
- // Create a unique key based on the full path
29
- const key = relativePath.replace(/\.[^/.]+$/, ""); // Remove extension
30
-
31
- return [key, entry];
32
- })
33
- );
34
-
35
- const workerPath = options?.workerPath
36
- ? resolve(root, options.workerPath)
37
- : resolve(__dirname, "..", DEFAULT_CONFIG.WORKER_PATH);
23
+ const { output, input: inputConfig, ...restRollupOptions } =
24
+ userConfig.build.rollupOptions ?? {};
38
25
 
39
- const loaderPath = options?.loaderPath
40
- ? resolve(root, options.loaderPath)
41
- : resolve(__dirname, "..", DEFAULT_CONFIG.LOADER_PATH);
26
+ let mergedInputs = mergeInputs(input, inputConfig);
42
27
 
28
+ let inputNormalizer = createInputNormalizer({
29
+ root,
30
+ });
31
+ if(typeof mergedInputs === 'object' && mergedInputs != null) {
32
+ mergedInputs = Object.fromEntries(Object.entries(mergedInputs).map(inputNormalizer));
33
+ }
43
34
  const config: InlineConfig = {
44
35
  configFile: false,
45
- root,
46
- base,
36
+ ...userConfig,
47
37
  build: {
48
- target: "node18",
49
- ssr: true,
50
- ssrEmitAssets: false,
51
- manifest: true,
52
- ssrManifest: true,
53
- outDir,
38
+ ...userConfig.build,
54
39
  rollupOptions: {
55
- input: {
56
- ...entryInputs,
57
- worker: workerPath,
58
- loader: loaderPath,
59
- },
40
+ input: mergedInputs,
60
41
  output: {
61
42
  format: "esm",
62
43
  preserveModules: true,
@@ -65,7 +46,9 @@ export function createBuildConfig({
65
46
  entryFileNames: "[name].js",
66
47
  chunkFileNames: "[name].js",
67
48
  assetFileNames: "[name][extname]",
49
+ ...output,
68
50
  },
51
+ ...restRollupOptions,
69
52
  },
70
53
  },
71
54
  };
@@ -0,0 +1,42 @@
1
+ import type { InputOption } from "rollup";
2
+
3
+ export const mergeAsArray = (entries: InputOption) => {
4
+ return Array.isArray(entries)
5
+ ? entries
6
+ : typeof entries === "object" && entries != null
7
+ ? Object.values(entries)
8
+ : typeof entries === "string"
9
+ ? [entries]
10
+ : [];
11
+ };
12
+ export const mergeAsObject = (entries: InputOption) => {
13
+ return Array.isArray(entries)
14
+ ? Object.fromEntries(entries.map((entry) => [entry, entry]))
15
+ : typeof entries === "object" && entries != null
16
+ ? entries
17
+ : typeof entries === "string"
18
+ ? { [entries]: entries }
19
+ : {};
20
+ };
21
+
22
+ export const mergeInputs = (
23
+ input: InputOption,
24
+ input2: InputOption | undefined
25
+ ) => {
26
+ if (!input2) return input;
27
+ return Array.isArray(input)
28
+ ? [...input, ...mergeAsArray(input2)]
29
+ : typeof input === "string"
30
+ ? [input, ...mergeAsArray(input2)]
31
+ : input != null && typeof input2 === "object" && input2 != null
32
+ ? { ...input, ...mergeAsObject(input2) }
33
+ : input != null
34
+ ? input
35
+ : Array.isArray(input2)
36
+ ? input2
37
+ : typeof input2 === "object" && input2 != null
38
+ ? input2
39
+ : typeof input2 === "string"
40
+ ? input2
41
+ : [];
42
+ };
@@ -0,0 +1,22 @@
1
+ import { relative } from "node:path";
2
+
3
+ type NormalizedInputOptions = {
4
+ // will automatically remove this part
5
+ root?: string;
6
+ };
7
+
8
+ export const createInputNormalizer =
9
+ (
10
+ {
11
+ root = process.cwd(),
12
+ }: NormalizedInputOptions = {} as NormalizedInputOptions
13
+ ) =>
14
+ ([key, path]: [string, string]) =>
15
+ [
16
+ key,
17
+ path.startsWith(root)
18
+ ? relative(root, path)
19
+ : path.startsWith("/")
20
+ ? path
21
+ : `/${path}`,
22
+ ];
@@ -4,56 +4,56 @@ type NormalizedRelativePathOptions = {
4
4
  // will automatically remove this part
5
5
  root: string;
6
6
  // will automatically see this as a optional extra part of the rootDir that will be removed
7
- outDir: string | string[];
7
+ outDir: string;
8
8
  // will ensure it always starts with this path, if it does not it will be added
9
9
  moduleBase: string;
10
10
  // will ensure it never starts with a leading /, which in some cases is needed (vite entry), other cases it is not for example from project root /
11
11
  noLeadingSlash: boolean;
12
+ // will ensure it never ends with a trailing /
13
+ noTrailingSlash: boolean;
14
+ // allowed exception to moduleBase rules
15
+ moduleBaseExceptions: string[];
12
16
  };
13
17
 
14
18
  export const createNormalizedRelativePath = (
15
19
  options: NormalizedRelativePathOptions = {
16
20
  root: process.cwd(),
17
- outDir: ["dist", "build"],
21
+ outDir: "dist",
18
22
  moduleBase: "src",
19
23
  noLeadingSlash: false,
24
+ noTrailingSlash: false,
25
+ moduleBaseExceptions: [],
20
26
  }
21
27
  ) => {
22
- const base =
28
+ let base =
23
29
  options.noLeadingSlash && options.moduleBase.startsWith("/")
24
30
  ? options.moduleBase.slice(1)
25
31
  : options.moduleBase;
26
- const removeOutDir = Array.isArray(options.outDir)
27
- ? (path: string) =>
28
- (options.outDir as string[])
29
- .map((dir) => path.startsWith(dir))
30
- .some((v) => v)
31
- ? path.slice(options.outDir[0].length)
32
- : path
33
- : (path: string) =>
34
- (options.outDir as string) === path
35
- ? path.slice(options.outDir.length)
36
- : path;
32
+ if (options.noTrailingSlash && base.endsWith("/")) {
33
+ base = base.slice(0, -1);
34
+ }
35
+ const removeOutDir = (path: string) =>
36
+ (options.outDir as string) === path
37
+ ? path.slice(options.outDir.length)
38
+ : path;
37
39
 
38
40
  const removeRoot = (path: string) => {
39
- const normalized = normalizePath(path);
40
- const relative = normalized.startsWith(options.root)
41
- ? normalized.slice(options.root.length)
42
- : normalized;
41
+ const relative = path.startsWith(options.root)
42
+ ? path.slice(options.root.length)
43
+ : path;
43
44
  return relative;
44
45
  };
45
46
 
46
47
  const ensureModuleBase = (path: string) => {
48
+ let transformed = path;
47
49
  if (options.noLeadingSlash && path.startsWith("/")) {
48
- return path.slice(1);
50
+ transformed = path.slice(1);
49
51
  }
50
- if (!path.startsWith(base)) {
51
- throw new Error(
52
- `Path ${path} does not start with module base ${base}, this will not work down the line.`
53
- );
52
+ if (options.noTrailingSlash && transformed.endsWith("/")) {
53
+ transformed = transformed.slice(0, -1);
54
54
  }
55
- return path;
55
+ return transformed;
56
56
  };
57
57
 
58
- return (path: string) => ensureModuleBase(removeOutDir(removeRoot(path)));
58
+ return (path: string) => ensureModuleBase(removeOutDir(removeRoot(normalizePath(path))));
59
59
  };
@@ -1,13 +1,20 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
+ import type { Manifest } from "vite";
3
4
 
4
- type TryManifestOptions = {
5
+ type TryManifestOptions<SSR extends boolean> = {
5
6
  root: string;
6
7
  outDir: string;
7
- ssrManifest: boolean;
8
+ ssrManifest: SSR;
8
9
  };
9
10
 
10
- export function tryManifest(options: TryManifestOptions) {
11
+ export function tryManifest<SSR extends boolean>(options: TryManifestOptions<SSR>): {
12
+ type: "success";
13
+ manifest: SSR extends true ? Record<string, string[]> : Manifest;
14
+ } | {
15
+ type: "error";
16
+ error: Error;
17
+ } {
11
18
  const manifestPath = resolve(
12
19
  options.root,
13
20
  options.outDir,
@@ -15,9 +22,16 @@ export function tryManifest(options: TryManifestOptions) {
15
22
  options.ssrManifest ? "ssr-manifest.json" : "manifest.json"
16
23
  );
17
24
  try {
18
- return JSON.parse(readFileSync(manifestPath, "utf-8"));
25
+ const result= JSON.parse(readFileSync(manifestPath, "utf-8"));
26
+ return {
27
+ type: "success",
28
+ manifest: result,
29
+ }
19
30
  } catch (e) {
20
31
  console.log("No manifest found", manifestPath);
21
- return null;
32
+ return {
33
+ type: "error",
34
+ error: e as Error,
35
+ }
22
36
  }
23
37
  }
@@ -71,6 +71,8 @@ export const createPageLoader = ({
71
71
  outDir,
72
72
  moduleBase,
73
73
  noLeadingSlash: true,
74
+ noTrailingSlash: true,
75
+ moduleBaseExceptions: [],
74
76
  });
75
77
  return async (id: string) => {
76
78
  const normalizedId = pathNormalizer(id);
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 ''",