vite-plugin-react-server 1.2.5 → 1.3.2

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 (54) hide show
  1. package/dist/package.json +8 -4
  2. package/dist/plugin/orchestrator/createPluginOrchestrator.client.d.ts.map +1 -1
  3. package/dist/plugin/orchestrator/createPluginOrchestrator.client.js +3 -0
  4. package/dist/plugin/orchestrator/createPluginOrchestrator.server.d.ts.map +1 -1
  5. package/dist/plugin/orchestrator/createPluginOrchestrator.server.js +3 -0
  6. package/dist/plugin/vendor/register-vendor.d.ts +2 -0
  7. package/dist/plugin/vendor/register-vendor.d.ts.map +1 -0
  8. package/dist/plugin/vendor/register-vendor.js +50 -0
  9. package/dist/plugin/vendor/vendor-alias.d.ts +12 -0
  10. package/dist/plugin/vendor/vendor-alias.d.ts.map +1 -0
  11. package/dist/plugin/vendor/vendor-alias.js +97 -0
  12. package/dist/plugin/vendor/vendor.client.d.ts +1 -1
  13. package/dist/plugin/vendor/vendor.client.d.ts.map +1 -1
  14. package/dist/plugin/vendor/vendor.client.js +19 -6
  15. package/dist/plugin/vendor/vendor.server.d.ts.map +1 -1
  16. package/dist/plugin/vendor/vendor.server.js +18 -5
  17. package/dist/plugin/vendor/vendor.static.d.ts.map +1 -1
  18. package/dist/plugin/vendor/vendor.static.js +18 -5
  19. package/dist/plugin/worker/createWorker.d.ts.map +1 -1
  20. package/dist/plugin/worker/createWorker.js +5 -2
  21. package/dist/tsconfig.tsbuildinfo +1 -1
  22. package/oss-experimental/react-server-dom-esm/LICENSE +21 -0
  23. package/oss-experimental/react-server-dom-esm/README.md +5 -0
  24. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js +2996 -0
  25. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.production.js +1612 -0
  26. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js +3124 -0
  27. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.node.production.js +1752 -0
  28. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +4213 -0
  29. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +2857 -0
  30. package/oss-experimental/react-server-dom-esm/client.browser.js +7 -0
  31. package/oss-experimental/react-server-dom-esm/client.js +3 -0
  32. package/oss-experimental/react-server-dom-esm/client.node.js +7 -0
  33. package/oss-experimental/react-server-dom-esm/esm/package.json +3 -0
  34. package/oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js +3969 -0
  35. package/oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-client.browser.production.js +2347 -0
  36. package/oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-node-loader.production.js +515 -0
  37. package/oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-server.js +13 -0
  38. package/oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-server.node.js +13 -0
  39. package/oss-experimental/react-server-dom-esm/index.js +12 -0
  40. package/oss-experimental/react-server-dom-esm/package.json +63 -0
  41. package/oss-experimental/react-server-dom-esm/server.js +6 -0
  42. package/oss-experimental/react-server-dom-esm/server.node.js +17 -0
  43. package/oss-experimental/react-server-dom-esm/static.js +6 -0
  44. package/oss-experimental/react-server-dom-esm/static.node.js +12 -0
  45. package/package.json +8 -4
  46. package/plugin/orchestrator/createPluginOrchestrator.client.ts +4 -0
  47. package/plugin/orchestrator/createPluginOrchestrator.server.ts +4 -0
  48. package/plugin/vendor/register-vendor.ts +51 -0
  49. package/plugin/vendor/vendor-alias.ts +112 -0
  50. package/plugin/vendor/vendor.client.ts +24 -9
  51. package/plugin/vendor/vendor.server.ts +23 -7
  52. package/plugin/vendor/vendor.static.ts +21 -7
  53. package/plugin/worker/createWorker.ts +4 -0
  54. package/scripts/build-oss-experimental.sh +161 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-react-server",
3
- "version": "1.2.5",
3
+ "version": "1.3.2",
4
4
  "description": "Vite plugin for React Server Components (RSC)",
5
5
  "type": "module",
6
6
  "main": "./dist/plugin/index.js",
@@ -14,7 +14,8 @@
14
14
  "virtual.d.ts",
15
15
  "README.md",
16
16
  "LICENSE",
17
- "tsconfig.json"
17
+ "tsconfig.json",
18
+ "oss-experimental/react-server-dom-esm"
18
19
  ],
19
20
  "exports": {
20
21
  ".": "./dist/plugin/index.js",
@@ -218,9 +219,10 @@
218
219
  "experimental:copy": "cp -r ./oss-experimental/* ./node_modules/",
219
220
  "experimental:patch": "npx patch-package react-server-dom-esm react react-dom --exclude 'nothing'",
220
221
  "experimental:move-patches": "mv patches/* ./scripts/",
222
+ "experimental:build-oss": "bash scripts/build-oss-experimental.sh",
223
+ "experimental:build-oss-full": "bash scripts/build-oss-experimental.sh --full",
221
224
  "experimental:setup": "rm -rf patches/* && npm run experimental:clean-install && npm run experimental:copy && npm run experimental:patch && npm run experimental:move-patches",
222
225
  "experimental:patch-react": "npm run experimental:clean-install && node scripts/check-react-version.mjs && node bin/patch.mjs",
223
- "postinstall": "patch-package",
224
226
  "test-parse": "node -e \"const acorn = require('acorn'); const ast = acorn.parse('export async function test() {}', { sourceType: 'module', ecmaVersion: 'latest' }); console.log(JSON.stringify(ast, null, 2));\"",
225
227
  "precoverage": "npm run build",
226
228
  "coverage": "npm run test:coverage"
@@ -248,7 +250,6 @@
248
250
  "peerDependencies": {
249
251
  "react": ">=0.0.0-experimental-0",
250
252
  "react-dom": ">=0.0.0-experimental-0",
251
- "react-server-dom-esm": "^0.0.1",
252
253
  "vite": "*"
253
254
  },
254
255
  "peerDependenciesMeta": {
@@ -260,6 +261,9 @@
260
261
  },
261
262
  "vite": {
262
263
  "optional": false
264
+ },
265
+ "react-server-dom-esm": {
266
+ "optional": true
263
267
  }
264
268
  },
265
269
  "devDependencies": {
@@ -5,6 +5,7 @@ import { vitePluginReactDevServer } from "../dev-server/plugin.client.js";
5
5
  import { reactStaticPlugin } from "../react-static/plugin.client.js";
6
6
  import { createTransformerPlugin } from "../transformer/createTransformerPlugin.js";
7
7
  import { virtualRscHmrPlugin } from "../dev-server/virtualRscHmrPlugin.js";
8
+ import { vitePluginVendorAlias } from "../vendor/vendor-alias.js";
8
9
 
9
10
  // Client-first orchestrator - includes client SSG plugin for reverse paradigm
10
11
  export const createPluginOrchestrator = (
@@ -15,6 +16,9 @@ export const createPluginOrchestrator = (
15
16
 
16
17
  const plugins: Plugin[] = [];
17
18
 
19
+ // Alias react-server-dom-esm to our vendored copy
20
+ plugins.push(vitePluginVendorAlias());
21
+
18
22
  // Virtual module for RSC HMR utilities (works in both dev and build)
19
23
  plugins.push(virtualRscHmrPlugin());
20
24
 
@@ -5,6 +5,7 @@ import { vitePluginReactDevServer } from "../dev-server/plugin.server.js";
5
5
  import { reactStaticPlugin } from "../react-static/plugin.server.js";
6
6
  import { createTransformerPlugin } from "../transformer/createTransformerPlugin.js";
7
7
  import { virtualRscHmrPlugin } from "../dev-server/virtualRscHmrPlugin.js";
8
+ import { vitePluginVendorAlias } from "../vendor/vendor-alias.js";
8
9
 
9
10
  // Server-first orchestrator - only imports server plugins
10
11
  export const createPluginOrchestrator = (
@@ -21,6 +22,9 @@ export const createPluginOrchestrator = (
21
22
 
22
23
  const plugins: Plugin[] = [];
23
24
 
25
+ // Alias react-server-dom-esm to our vendored copy
26
+ plugins.push(vitePluginVendorAlias());
27
+
24
28
  // Virtual module for RSC HMR utilities (works in both dev and build)
25
29
  plugins.push(virtualRscHmrPlugin());
26
30
 
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Node.js module resolution hook that redirects `react-server-dom-esm/*`
3
+ * to the vendored copy at runtime. Used by the RSC worker via --import.
4
+ *
5
+ * Server entries use ESM wrappers (in esm/) that re-export from CJS
6
+ * so Node's ESM loader can provide named exports.
7
+ */
8
+ import { register } from "node:module";
9
+ import { dirname, join } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ import { existsSync } from "node:fs";
12
+
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ function findPkgRoot(): string {
15
+ let dir = __dirname;
16
+ for (let i = 0; i < 5; i++) {
17
+ if (existsSync(join(dir, "oss-experimental", "react-server-dom-esm"))) return dir;
18
+ dir = dirname(dir);
19
+ }
20
+ return dirname(dirname(__dirname));
21
+ }
22
+ const ossDir = join(findPkgRoot(), "oss-experimental", "react-server-dom-esm");
23
+
24
+ register("data:text/javascript," + encodeURIComponent(`
25
+ const ossDir = ${JSON.stringify(ossDir)};
26
+ const { join } = await import("node:path");
27
+ const { pathToFileURL } = await import("node:url");
28
+
29
+ // Map bare specifiers to vendored files. Server entries use ESM wrappers
30
+ // that re-export from CJS for proper named export support.
31
+ const subpathMap = {
32
+ "react-server-dom-esm": join(ossDir, "index.js"),
33
+ "react-server-dom-esm/client": join(ossDir, "client.js"),
34
+ "react-server-dom-esm/client.browser": join(ossDir, "esm", "react-server-dom-esm-client.browser.production.js"),
35
+ "react-server-dom-esm/client.node": join(ossDir, "client.node.js"),
36
+ "react-server-dom-esm/server": join(ossDir, "esm", "react-server-dom-esm-server.node.js"),
37
+ "react-server-dom-esm/server.node": join(ossDir, "esm", "react-server-dom-esm-server.node.js"),
38
+ "react-server-dom-esm/static": join(ossDir, "static.js"),
39
+ "react-server-dom-esm/static.node": join(ossDir, "static.node.js"),
40
+ };
41
+
42
+ export async function resolve(specifier, context, nextResolve) {
43
+ if (specifier in subpathMap) {
44
+ return {
45
+ shortCircuit: true,
46
+ url: pathToFileURL(subpathMap[specifier]).href,
47
+ };
48
+ }
49
+ return nextResolve(specifier, context);
50
+ }
51
+ `), import.meta.url);
@@ -0,0 +1,112 @@
1
+ import type { Plugin } from "vite";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { existsSync } from "node:fs";
5
+
6
+ // Find package root by walking up from current file until we find oss-experimental/
7
+ // Works from both plugin/vendor/ (source) and dist/plugin/vendor/ (built)
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ function findPkgRoot(): string {
10
+ let dir = __dirname;
11
+ for (let i = 0; i < 5; i++) {
12
+ if (existsSync(join(dir, "oss-experimental", "react-server-dom-esm"))) return dir;
13
+ dir = dirname(dir);
14
+ }
15
+ return dirname(dirname(__dirname)); // fallback
16
+ }
17
+ const pkgRoot = findPkgRoot();
18
+ const ossDir = join(pkgRoot, "oss-experimental");
19
+
20
+ /**
21
+ * Vite plugin that aliases `react-server-dom-esm/*` imports to the vendored
22
+ * copy shipped with this plugin. This eliminates the need for consumers to
23
+ * install `react-server-dom-esm` separately or use patch-package.
24
+ *
25
+ * Browser client entries use true ESM files for Rollup tree-shaking.
26
+ * Server/static entries are marked external during builds — they're CJS
27
+ * modules loaded at runtime via createRequire in vendor.*.ts files.
28
+ */
29
+ export function vitePluginVendorAlias(): Plugin {
30
+ let isBuild = false;
31
+
32
+ return {
33
+ name: "vite-plugin-react-server:vendor-alias",
34
+ enforce: "pre",
35
+
36
+ config(_config, env) {
37
+ const pkg = join(ossDir, "react-server-dom-esm");
38
+ const isProd = env.mode === "production";
39
+
40
+ // Only alias browser client to ESM for Rollup tree-shaking.
41
+ // Server/static are handled by resolveId with external:true.
42
+ return {
43
+ resolve: {
44
+ alias: [
45
+ {
46
+ find: "react-server-dom-esm/client.browser",
47
+ replacement: join(pkg, "esm", isProd
48
+ ? "react-server-dom-esm-client.browser.production.js"
49
+ : "react-server-dom-esm-client.browser.development.js")
50
+ },
51
+ ],
52
+ },
53
+ };
54
+ },
55
+
56
+ configResolved(config) {
57
+ isBuild = config.command === "build";
58
+ },
59
+
60
+ resolveId(source) {
61
+ // Only handle react-server-dom-esm specifiers (not already aliased paths)
62
+ if (!source.startsWith("react-server-dom-esm")) {
63
+ return;
64
+ }
65
+
66
+ // Skip client.browser — handled by config alias above
67
+ if (source === "react-server-dom-esm/client.browser") {
68
+ return;
69
+ }
70
+
71
+ // For server/static entries during build: mark external with resolved path.
72
+ // At runtime, vendor.*.ts uses createRequire to load from this path.
73
+ if (isBuild && isServerEntry(source)) {
74
+ const resolved = resolveVendored(source);
75
+ return { id: resolved, external: true };
76
+ }
77
+
78
+ // For all other entries (client.node, client, index), resolve to vendored path
79
+ return resolveVendored(source);
80
+ },
81
+ };
82
+ }
83
+
84
+ function isServerEntry(source: string): boolean {
85
+ return (
86
+ source.includes("/server") ||
87
+ source.includes("/static")
88
+ );
89
+ }
90
+
91
+ // Explicit subpath → file mapping. Server entries always resolve to .node
92
+ // variants to bypass the react-server condition guard in server.js.
93
+ const subpathMap: Record<string, string> = {
94
+ "react-server-dom-esm": "index.js",
95
+ "react-server-dom-esm/client": "client.js",
96
+ "react-server-dom-esm/client.browser": "client.browser.js",
97
+ "react-server-dom-esm/client.node": "client.node.js",
98
+ "react-server-dom-esm/server": "server.node.js",
99
+ "react-server-dom-esm/server.node": "server.node.js",
100
+ "react-server-dom-esm/static": "static.node.js",
101
+ "react-server-dom-esm/static.node": "static.node.js",
102
+ };
103
+
104
+ function resolveVendored(source: string): string {
105
+ const file = subpathMap[source];
106
+ if (file) {
107
+ return join(ossDir, "react-server-dom-esm", file);
108
+ }
109
+ // Fallback for unknown subpaths
110
+ const subpath = source.replace("react-server-dom-esm", "");
111
+ return join(ossDir, "react-server-dom-esm", subpath || "index.js");
112
+ }
@@ -1,15 +1,30 @@
1
1
  import { createRequire } from "node:module";
2
- import { join } from "node:path";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { existsSync } from "node:fs";
3
5
  import { assertNonReactServer } from "../config/getCondition.js";
4
6
 
5
7
  assertNonReactServer();
6
8
 
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ function findPkgRoot(): string {
11
+ let dir = __dirname;
12
+ for (let i = 0; i < 5; i++) {
13
+ if (existsSync(join(dir, "oss-experimental", "react-server-dom-esm"))) return dir;
14
+ dir = dirname(dir);
15
+ }
16
+ return dirname(dirname(__dirname));
17
+ }
18
+ const ossDir = join(findPkgRoot(), "oss-experimental");
19
+
20
+ // Load react-server-dom-esm/client.node directly from vendored copy
21
+ const vendorRequire = createRequire(join(ossDir, "react-server-dom-esm", "package.json"));
22
+ const ReactDOMClient = vendorRequire(join(ossDir, "react-server-dom-esm", "client.node.js")) as typeof import("react-server-dom-esm/client.node");
23
+
24
+ // React and react-dom still come from the consumer's project
7
25
  const projectRoot = process.env["npm_config_local_prefix"] || process.cwd();
8
- const nodeRequire = createRequire(join(projectRoot, "package.json"));
9
-
10
- // Import ReactDOM from the project's node_modules
11
- const ReactDOMServer = nodeRequire("react-dom/server") as typeof import("react-dom/server");
12
- const ReactDOMClient = nodeRequire("react-server-dom-esm/client.node") as typeof import("react-server-dom-esm/client.node");
13
- const React = nodeRequire("react") as typeof import("react");
14
-
15
- export { ReactDOMServer, React, ReactDOMClient };
26
+ const projectRequire = createRequire(join(projectRoot, "package.json"));
27
+ const ReactDOMServer = projectRequire("react-dom/server") as typeof import("react-dom/server");
28
+ const React = projectRequire("react") as typeof import("react");
29
+
30
+ export { ReactDOMServer, React, ReactDOMClient };
@@ -1,13 +1,29 @@
1
1
  import { createRequire } from "node:module";
2
- import { join } from "node:path";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { existsSync } from "node:fs";
3
5
 
4
- const projectRoot = process.env["npm_config_local_prefix"] || process.cwd();
5
- const nodeRequire = createRequire(join(projectRoot, "package.json"));
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ function findPkgRoot(): string {
8
+ let dir = __dirname;
9
+ for (let i = 0; i < 5; i++) {
10
+ if (existsSync(join(dir, "oss-experimental", "react-server-dom-esm"))) return dir;
11
+ dir = dirname(dir);
12
+ }
13
+ return dirname(dirname(__dirname));
14
+ }
15
+ const ossDir = join(findPkgRoot(), "oss-experimental");
16
+
17
+ // Load react-server-dom-esm/server.node directly from vendored copy
18
+ // Use server.node.js (not server.js which is a react-server condition guard)
19
+ const vendorRequire = createRequire(join(ossDir, "react-server-dom-esm", "package.json"));
20
+ const ReactDOMServer = vendorRequire(join(ossDir, "react-server-dom-esm", "server.node.js")) as typeof import("react-server-dom-esm/server.node");
6
21
 
7
- // Import ReactDOM from the project's node_modules
8
- const ReactDOMServer = nodeRequire("react-server-dom-esm/server.node") as typeof import("react-server-dom-esm/server.node");
9
- const React = nodeRequire("react") as typeof import("react");
22
+ // React still comes from the consumer's project
23
+ const projectRoot = process.env["npm_config_local_prefix"] || process.cwd();
24
+ const projectRequire = createRequire(join(projectRoot, "package.json"));
25
+ const React = projectRequire("react") as typeof import("react");
10
26
 
11
27
  export { ReactDOMServer, React };
12
28
  export type * from "react-server-dom-esm/server.node";
13
- export type React = typeof import("react");
29
+ export type React = typeof import("react");
@@ -1,12 +1,26 @@
1
1
  import { createRequire } from "node:module";
2
- import { join } from "node:path";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { existsSync } from "node:fs";
3
5
 
4
- const projectRoot = process.env["npm_config_local_prefix"] || process.cwd();
5
- const nodeRequire = createRequire(join(projectRoot, "package.json"));
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ function findPkgRoot(): string {
8
+ let dir = __dirname;
9
+ for (let i = 0; i < 5; i++) {
10
+ if (existsSync(join(dir, "oss-experimental", "react-server-dom-esm"))) return dir;
11
+ dir = dirname(dir);
12
+ }
13
+ return dirname(dirname(__dirname));
14
+ }
15
+ const ossDir = join(findPkgRoot(), "oss-experimental");
16
+
17
+ // Load react-server-dom-esm/static.node directly from vendored copy
18
+ const vendorRequire = createRequire(join(ossDir, "react-server-dom-esm", "package.json"));
19
+ const ReactDOMServer = vendorRequire(join(ossDir, "react-server-dom-esm", "static.node.js")) as typeof import("react-server-dom-esm/static.node");
6
20
 
7
- // Import ReactDOM from the project's node_modules for static pre-rendering
8
- // This includes unstable_prerenderToNodeStream for build-time stream creation
9
- const ReactDOMServer = nodeRequire("react-server-dom-esm/static.node") as typeof import("react-server-dom-esm/static.node");
10
- const React = nodeRequire("react") as typeof import("react");
21
+ // React still comes from the consumer's project
22
+ const projectRoot = process.env["npm_config_local_prefix"] || process.cwd();
23
+ const projectRequire = createRequire(join(projectRoot, "package.json"));
24
+ const React = projectRequire("react") as typeof import("react");
11
25
 
12
26
  export { ReactDOMServer, React };
@@ -255,10 +255,14 @@ Current condition: ${currentCondition}, Reverse condition: ${reverseCondition}`
255
255
  }
256
256
  return out;
257
257
  };
258
+ // Register vendor resolution hook so the worker can find react-server-dom-esm
259
+ const vendorRegisterPath = new URL("../vendor/register-vendor.js", import.meta.url).href;
258
260
  const computedExecArgv = [
259
261
  ...stripConditionsFromArgv(process.execArgv || []),
260
262
  "--conditions",
261
263
  reverseCondition,
264
+ "--import",
265
+ vendorRegisterPath,
262
266
  ];
263
267
 
264
268
  // Always log the condition setup for debugging
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Build react-server-dom-esm from React source for the oss-experimental/ folder.
5
+ #
6
+ # Usage:
7
+ # ./scripts/build-oss-experimental.sh [--react-dir PATH] [--full]
8
+ #
9
+ # Prerequisites:
10
+ # - yarn (React repo uses yarn workspaces)
11
+ # - Node.js 18+
12
+ # - java (for Google Closure Compiler, used by React's build)
13
+ #
14
+ # This script:
15
+ # 1. Clones facebook/react into ../react (or uses existing checkout)
16
+ # 2. Installs dependencies with yarn
17
+ # 3. Builds react-server-dom-esm (targeted) or full experimental channel
18
+ # 4. Runs packaging to create the publishable output
19
+ # 5. Copies results into oss-experimental/
20
+
21
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
22
+ PLUGIN_DIR="$(dirname "$SCRIPT_DIR")"
23
+ REACT_DIR="${REACT_DIR:-$(dirname "$PLUGIN_DIR")/react}"
24
+ OSS_DIR="$PLUGIN_DIR/oss-experimental"
25
+ FULL_BUILD=false
26
+
27
+ # Parse args
28
+ while [[ $# -gt 0 ]]; do
29
+ case "$1" in
30
+ --react-dir) REACT_DIR="$2"; shift 2 ;;
31
+ --full) FULL_BUILD=true; shift ;;
32
+ --help|-h)
33
+ echo "Usage: $0 [--react-dir PATH] [--full]"
34
+ echo ""
35
+ echo "Build react-server-dom-esm from React source."
36
+ echo ""
37
+ echo "Options:"
38
+ echo " --react-dir PATH Path to React checkout (default: ../react)"
39
+ echo " --full Build ALL packages (slow, ~15 min)"
40
+ echo " Default: targeted build of react-server-dom-esm only (~2 min)"
41
+ exit 0
42
+ ;;
43
+ *) echo "Unknown option: $1"; exit 1 ;;
44
+ esac
45
+ done
46
+
47
+ echo "Plugin dir: $PLUGIN_DIR"
48
+ echo "React dir: $REACT_DIR"
49
+ echo "Output dir: $OSS_DIR"
50
+ echo "Full build: $FULL_BUILD"
51
+ echo ""
52
+
53
+ # Step 1: Clone or update React
54
+ if [ ! -d "$REACT_DIR" ]; then
55
+ echo "==> Cloning facebook/react (shallow)..."
56
+ git clone --depth 1 https://github.com/facebook/react.git "$REACT_DIR"
57
+ else
58
+ echo "==> Using existing React checkout at $REACT_DIR"
59
+ echo " Branch: $(cd "$REACT_DIR" && git branch --show-current 2>/dev/null || echo 'detached')"
60
+ echo " Commit: $(cd "$REACT_DIR" && git rev-parse --short HEAD)"
61
+ echo ""
62
+ read -p " Pull latest? [y/N] " -n 1 -r
63
+ echo
64
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
65
+ (cd "$REACT_DIR" && git pull)
66
+ fi
67
+ fi
68
+
69
+ # Step 2: Install dependencies
70
+ echo ""
71
+ echo "==> Installing React dependencies (yarn)..."
72
+ cd "$REACT_DIR"
73
+
74
+ if ! command -v yarn &>/dev/null; then
75
+ echo "ERROR: yarn is required but not installed."
76
+ echo "Install with: npm install -g yarn"
77
+ exit 1
78
+ fi
79
+
80
+ yarn install --frozen-lockfile 2>&1 | tail -5
81
+
82
+ # Step 3: Build
83
+ echo ""
84
+ if [ "$FULL_BUILD" = true ]; then
85
+ echo "==> Building full React experimental channel (this takes ~15 min)..."
86
+ RELEASE_CHANNEL=experimental node scripts/rollup/build-all-release-channels.js \
87
+ --releaseChannel experimental 2>&1 | tail -20
88
+ else
89
+ echo "==> Building react-server-dom-esm (targeted, ~2 min)..."
90
+ echo " (Use --full to build all packages)"
91
+ echo ""
92
+
93
+ # React's build.js accepts bundle names as positional args to filter.
94
+ # We need react-server-dom-esm but it imports from shared React internals,
95
+ # so we also need to build the core 'react' package first.
96
+ #
97
+ # RELEASE_CHANNEL=experimental ensures __EXPERIMENTAL__ is true.
98
+ RELEASE_CHANNEL=experimental node scripts/rollup/build.js \
99
+ react react-server-dom-esm 2>&1 | tail -30
100
+
101
+ # Run packaging step to create the final publishable package structure
102
+ # (copies files into build/oss-experimental/)
103
+ echo ""
104
+ echo "==> Running packaging..."
105
+ RELEASE_CHANNEL=experimental node scripts/rollup/build-all-release-channels.js \
106
+ --releaseChannel experimental --unsafe-partial 2>&1 | tail -20
107
+ fi
108
+
109
+ # Step 4: Copy to oss-experimental/
110
+ echo ""
111
+ echo "==> Copying packages to oss-experimental/..."
112
+
113
+ BUILD_BASE="$REACT_DIR/build/oss-experimental"
114
+
115
+ if [ ! -d "$BUILD_BASE" ]; then
116
+ echo "ERROR: Build output not found at $BUILD_BASE"
117
+ echo ""
118
+ echo "If the targeted build didn't create the packaging output,"
119
+ echo "try running with --full flag."
120
+ exit 1
121
+ fi
122
+
123
+ mkdir -p "$OSS_DIR"
124
+
125
+ # Always copy react-server-dom-esm (the one we need)
126
+ for pkg in react-server-dom-esm react react-dom; do
127
+ BUILD_PKG="$BUILD_BASE/$pkg"
128
+ if [ -d "$BUILD_PKG" ]; then
129
+ rm -rf "$OSS_DIR/$pkg"
130
+ cp -r "$BUILD_PKG" "$OSS_DIR/$pkg"
131
+ echo " ✓ $pkg"
132
+ else
133
+ echo " ✗ $pkg (not found in build output)"
134
+ fi
135
+ done
136
+
137
+ # If full build, copy everything
138
+ if [ "$FULL_BUILD" = true ]; then
139
+ for pkg in "$BUILD_BASE"/*/; do
140
+ pkg_name=$(basename "$pkg")
141
+ if [[ "$pkg_name" != "react" && "$pkg_name" != "react-dom" && "$pkg_name" != "react-server-dom-esm" ]]; then
142
+ rm -rf "$OSS_DIR/$pkg_name"
143
+ cp -r "$pkg" "$OSS_DIR/$pkg_name"
144
+ echo " ✓ $pkg_name"
145
+ fi
146
+ done
147
+ fi
148
+
149
+ # Report version
150
+ VERSION=$(python3 -c "import json; print(json.load(open('$OSS_DIR/react-server-dom-esm/package.json'))['version'])" 2>/dev/null || echo "unknown")
151
+ echo ""
152
+ echo "==> Done! react-server-dom-esm version: $VERSION"
153
+ echo " Output: $OSS_DIR/"
154
+ echo ""
155
+ echo "Next steps:"
156
+ echo " 1. Update TEMPLATE_VERSION in bin/patch.mjs to:"
157
+ echo " $VERSION"
158
+ echo " 2. Regenerate patches:"
159
+ echo " npm run experimental:setup"
160
+ echo " 3. Test:"
161
+ echo " npm run experimental:patch-react"