vite-plugin-react-server 1.3.5 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +32 -18
  2. package/dist/package.json +4 -2
  3. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  4. package/dist/plugin/config/resolveOptions.js +4 -2
  5. package/dist/plugin/dev-server/plugin.client.d.ts.map +1 -1
  6. package/dist/plugin/dev-server/plugin.client.js +13 -3
  7. package/dist/plugin/dev-server/plugin.server.d.ts.map +1 -1
  8. package/dist/plugin/dev-server/plugin.server.js +54 -4
  9. package/dist/plugin/react-static/plugin.server.d.ts.map +1 -1
  10. package/dist/plugin/react-static/plugin.server.js +9 -1
  11. package/dist/plugin/react-static/renderPagesBatched.d.ts.map +1 -1
  12. package/dist/plugin/react-static/renderPagesBatched.js +136 -36
  13. package/dist/plugin/react-static/types.d.ts +1 -0
  14. package/dist/plugin/react-static/types.d.ts.map +1 -1
  15. package/dist/plugin/types.d.ts +15 -0
  16. package/dist/plugin/types.d.ts.map +1 -1
  17. package/dist/plugin/utils/createReactFetcher.js +24 -2
  18. package/dist/plugin/utils/index.server.d.ts +0 -1
  19. package/dist/plugin/utils/index.server.d.ts.map +1 -1
  20. package/dist/plugin/utils/index.server.js +3 -4
  21. package/dist/plugin/utils/useRscHmr.js +10 -2
  22. package/dist/plugin/vendor/register-vendor.js +1 -1
  23. package/dist/plugin/vendor/vendor-alias.d.ts +5 -2
  24. package/dist/plugin/vendor/vendor-alias.d.ts.map +1 -1
  25. package/dist/plugin/vendor/vendor-alias.js +60 -26
  26. package/dist/plugin/vendor/vendor.server.d.ts.map +1 -1
  27. package/dist/plugin/vendor/vendor.server.js +2 -2
  28. package/dist/plugin/vendor/vendor.static.d.ts.map +1 -1
  29. package/dist/plugin/vendor/vendor.static.js +2 -2
  30. package/dist/tsconfig.tsbuildinfo +1 -1
  31. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js +1 -1
  32. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.production.js +1 -1
  33. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js +1 -1
  34. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.node.production.js +1 -1
  35. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +1 -1
  36. package/oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +1 -1
  37. package/oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js +1 -1
  38. package/oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-client.browser.production.js +1 -1
  39. package/oss-experimental/react-server-dom-esm/package.json +3 -3
  40. package/package.json +4 -2
  41. package/plugin/config/resolveOptions.ts +2 -0
  42. package/plugin/dev-server/plugin.client.ts +13 -2
  43. package/plugin/dev-server/plugin.server.ts +71 -4
  44. package/plugin/react-static/plugin.server.ts +11 -1
  45. package/plugin/react-static/renderPagesBatched.ts +148 -39
  46. package/plugin/react-static/types.ts +1 -0
  47. package/plugin/types.ts +15 -0
  48. package/plugin/utils/index.server.ts +3 -4
  49. package/plugin/vendor/register-vendor.ts +1 -1
  50. package/plugin/vendor/vendor-alias.ts +61 -39
  51. package/plugin/vendor/vendor.server.ts +3 -3
  52. package/plugin/vendor/vendor.static.ts +3 -2
@@ -1,7 +1,7 @@
1
1
  import type { Plugin } from "vite";
2
2
  import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import { existsSync } from "node:fs";
4
+ import { existsSync, lstatSync, readlinkSync, symlinkSync, unlinkSync } from "node:fs";
5
5
 
6
6
  // Find package root by walking up from current file until we find oss-experimental/
7
7
  // Works from both plugin/vendor/ (source) and dist/plugin/vendor/ (built)
@@ -23,12 +23,13 @@ const ossDir = join(pkgRoot, "oss-experimental");
23
23
  * install `react-server-dom-esm` separately or use patch-package.
24
24
  *
25
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.
26
+ * Server/static entries are CJS and must be loadable via native Node import()
27
+ * (not eval'd as ESM by Vite's module runner, which lacks require()).
28
+ *
29
+ * In dev mode, we ensure the vendored package is reachable from node_modules
30
+ * so Vite's module runner can externalize and natively import() CJS entries.
28
31
  */
29
32
  export function vitePluginVendorAlias(): Plugin {
30
- let isBuild = false;
31
-
32
33
  return {
33
34
  name: "vite-plugin-react-server:vendor-alias",
34
35
  enforce: "pre",
@@ -36,17 +37,16 @@ export function vitePluginVendorAlias(): Plugin {
36
37
  config(_config, env) {
37
38
  const pkg = join(ossDir, "react-server-dom-esm");
38
39
  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.
40
+
42
41
  return {
43
42
  resolve: {
44
43
  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")
44
+ // Browser client → ESM for Rollup tree-shaking
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
50
  },
51
51
  ],
52
52
  },
@@ -54,42 +54,67 @@ export function vitePluginVendorAlias(): Plugin {
54
54
  },
55
55
 
56
56
  configResolved(config) {
57
- isBuild = config.command === "build";
57
+ // Allow serving vendored files when the plugin is linked or in a monorepo.
58
+ // Must be done in configResolved to append to the resolved allow list
59
+ // (setting in config hook can override Vite's defaults).
60
+ if (config.command === "serve" && config.server?.fs?.allow) {
61
+ if (!config.server.fs.allow.includes(pkgRoot)) {
62
+ config.server.fs.allow.push(pkgRoot);
63
+ }
64
+ }
65
+
66
+ // Ensure vendored package is reachable via Node resolution in ALL Vite
67
+ // contexts (dev server, vitest, SSR workers, custom scripts).
68
+ // Vite's module runner resolves bare imports via Node — not plugin hooks —
69
+ // so the package must be in node_modules for CJS entries to work.
70
+ ensureVendoredPackageLinked(config.root);
58
71
  },
59
72
 
60
73
  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
- }
74
+ if (!source.startsWith("react-server-dom-esm")) return;
75
+ if (source === "react-server-dom-esm/client.browser") return;
70
76
 
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 };
77
+ // Server/static entries: mark external so the runner/bundler uses native
78
+ // import() rather than eval(). The resolved path points into the vendored
79
+ // copy (reachable via symlink in dev, directly in build).
80
+ if (isServerEntry(source)) {
81
+ return { id: resolveVendored(source), external: true };
76
82
  }
77
83
 
78
- // For all other entries (client.node, client, index), resolve to vendored path
79
84
  return resolveVendored(source);
80
85
  },
81
86
  };
82
87
  }
83
88
 
89
+ /**
90
+ * Ensure `node_modules/react-server-dom-esm` links to the vendored copy.
91
+ * Only creates a symlink if no real install exists. Safe to call multiple times.
92
+ */
93
+ function ensureVendoredPackageLinked(root?: string): void {
94
+ const pkg = join(ossDir, "react-server-dom-esm");
95
+ const target = join(root ?? process.cwd(), "node_modules", "react-server-dom-esm");
96
+ try {
97
+ const stat = (() => { try { return lstatSync(target); } catch { return null; } })();
98
+ if (stat?.isSymbolicLink()) {
99
+ // Update symlink if it points elsewhere
100
+ if (readlinkSync(target) !== pkg) {
101
+ unlinkSync(target);
102
+ symlinkSync(pkg, target, "junction");
103
+ }
104
+ } else if (!stat) {
105
+ // No existing file — create symlink
106
+ symlinkSync(pkg, target, "junction");
107
+ }
108
+ // If a real directory/file exists (user installed it), leave it alone
109
+ } catch {
110
+ // Non-fatal: symlink creation can fail on some systems
111
+ }
112
+ }
113
+
84
114
  function isServerEntry(source: string): boolean {
85
- return (
86
- source.includes("/server") ||
87
- source.includes("/static")
88
- );
115
+ return source.includes("/server") || source.includes("/static");
89
116
  }
90
117
 
91
- // Explicit subpath → file mapping. Server entries always resolve to .node
92
- // variants to bypass the react-server condition guard in server.js.
93
118
  const subpathMap: Record<string, string> = {
94
119
  "react-server-dom-esm": "index.js",
95
120
  "react-server-dom-esm/client": "client.js",
@@ -103,10 +128,7 @@ const subpathMap: Record<string, string> = {
103
128
 
104
129
  function resolveVendored(source: string): string {
105
130
  const file = subpathMap[source];
106
- if (file) {
107
- return join(ossDir, "react-server-dom-esm", file);
108
- }
109
- // Fallback for unknown subpaths
131
+ if (file) return join(ossDir, "react-server-dom-esm", file);
110
132
  const subpath = source.replace("react-server-dom-esm", "");
111
133
  return join(ossDir, "react-server-dom-esm", subpath || "index.js");
112
134
  }
@@ -14,10 +14,10 @@ function findPkgRoot(): string {
14
14
  }
15
15
  const ossDir = join(findPkgRoot(), "oss-experimental");
16
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)
17
+ // Load react-server-dom-esm/server from vendored copy
18
+ // The vendored package.json exports map defaults to server.node.js
19
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");
20
+ const ReactDOMServer = vendorRequire("react-server-dom-esm/server") as typeof import("react-server-dom-esm/server.node");
21
21
 
22
22
  // React still comes from the consumer's project
23
23
  const projectRoot = process.env["npm_config_local_prefix"] || process.cwd();
@@ -14,9 +14,10 @@ function findPkgRoot(): string {
14
14
  }
15
15
  const ossDir = join(findPkgRoot(), "oss-experimental");
16
16
 
17
- // Load react-server-dom-esm/static.node directly from vendored copy
17
+ // Load react-server-dom-esm/static from vendored copy
18
+ // The vendored package.json exports map defaults to static.node.js
18
19
  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");
20
+ const ReactDOMServer = vendorRequire("react-server-dom-esm/static") as typeof import("react-server-dom-esm/static.node");
20
21
 
21
22
  // React still comes from the consumer's project
22
23
  const projectRoot = process.env["npm_config_local_prefix"] || process.cwd();