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
@@ -0,0 +1,68 @@
1
+ import fs from 'node:fs/promises'
2
+ import path from 'node:path'
3
+
4
+
5
+ /**
6
+ * Bumps the version of the package.
7
+ * @param {'major' | 'minor' | 'patch'} type - The type of version to bump.
8
+ */
9
+ async function bumpVersion(type) {
10
+ // Read package.json
11
+ const packageJson = JSON.parse(
12
+ await fs.readFile(path.resolve('package.json'), 'utf-8')
13
+ )
14
+ const packageLockJson = JSON.parse(
15
+ await fs.readFile(path.resolve('package-lock.json'), 'utf-8')
16
+ )
17
+
18
+ // Parse current version
19
+ const [major, minor, patch] = packageJson.version.split('.').map(Number)
20
+
21
+ // Calculate new version
22
+ /**
23
+ * The new version of the package.
24
+ * @type {string}
25
+ */
26
+ let newVersion
27
+ switch (type) {
28
+ case 'major':
29
+ newVersion = `${major + 1}.0.0`
30
+ break
31
+ case 'minor':
32
+ newVersion = `${major}.${minor + 1}.0`
33
+ break
34
+ case 'patch':
35
+ newVersion = `${major}.${minor}.${patch + 1}`
36
+ break
37
+ }
38
+
39
+ // Update both files
40
+ packageJson.version = newVersion
41
+ packageLockJson.version = newVersion
42
+ packageLockJson.packages[''].version = newVersion
43
+
44
+ // Write back
45
+ await fs.writeFile(
46
+ path.resolve('package.json'),
47
+ JSON.stringify(packageJson, null, 2) + '\n'
48
+ )
49
+ await fs.writeFile(
50
+ path.resolve('package-lock.json'),
51
+ JSON.stringify(packageLockJson, null, 2) + '\n'
52
+ )
53
+
54
+ console.log(`Version bumped to ${newVersion}`)
55
+ }
56
+
57
+ // Get version type from command line argument
58
+ /**
59
+ * The type of version to bump.
60
+ * @type {'major' | 'minor' | 'patch'}
61
+ */
62
+ const type = process.argv[2]
63
+ if (!type || !['major', 'minor', 'patch'].includes(type)) {
64
+ console.error('Please specify version type: major, minor, or patch')
65
+ process.exit(1)
66
+ }
67
+
68
+ bumpVersion(type).catch(console.error)
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs/promises'
3
+ import path from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
7
+
8
+ const PATCH_RECONCILER_VERSION = '19.1.0-experimental-b3a95caf-20250113'
9
+ const ALTERNATIVE_REACT_VERSION = '0.0.0-experimental-b3a95caf-20250113'
10
+ const STUB_ESM_VERSION = `0.0.1`
11
+ const PATCH_FILE = `react-server-dom-esm+${STUB_ESM_VERSION}.patch`
12
+
13
+ async function main() {
14
+ try {
15
+ // Read installed React version
16
+ const reactPkgPath = path.resolve(process.cwd(), 'node_modules/react/package.json')
17
+ const reactPkg = JSON.parse(await fs.readFile(reactPkgPath, 'utf-8'))
18
+ const installedVersion = reactPkg.version
19
+
20
+ // Get our patch file from our package
21
+ const ourPatchPath = path.resolve(__dirname, `../patches/${PATCH_FILE}`)
22
+ let patchContent = await fs.readFile(ourPatchPath, 'utf-8')
23
+
24
+ // Replace the version in the patch content
25
+ patchContent = patchContent.replace(
26
+ new RegExp(PATCH_RECONCILER_VERSION, 'g'),
27
+ installedVersion
28
+ ).replace(
29
+ new RegExp(ALTERNATIVE_REACT_VERSION, 'g'),
30
+ installedVersion
31
+ )
32
+
33
+ // Create patches dir in user's project
34
+ const userPatchesDir = path.resolve(process.cwd(), 'patches')
35
+ await fs.mkdir(userPatchesDir, { recursive: true })
36
+
37
+ // Write the patch file - use stub version for filename
38
+ const newFileName = `react-server-dom-esm+${STUB_ESM_VERSION}.patch`
39
+ const newPatchPath = path.resolve(userPatchesDir, newFileName)
40
+ await fs.writeFile(newPatchPath, patchContent)
41
+
42
+ console.log(`Updated patch to match React version ${installedVersion}`)
43
+ } catch (error) {
44
+
45
+ }
46
+ }
47
+
48
+ main()
@@ -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);