rwsdk 1.0.0-alpha.1-test.20250911154541 → 1.0.0-alpha.10

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 (137) hide show
  1. package/dist/lib/e2e/browser.d.mts +10 -0
  2. package/dist/lib/e2e/browser.mjs +124 -0
  3. package/dist/lib/e2e/dev.d.mts +8 -0
  4. package/dist/lib/e2e/dev.mjs +232 -0
  5. package/dist/lib/e2e/environment.d.mts +14 -0
  6. package/dist/lib/e2e/environment.mjs +223 -0
  7. package/dist/lib/e2e/index.d.mts +7 -0
  8. package/dist/lib/e2e/index.mjs +7 -0
  9. package/dist/lib/e2e/release.d.mts +56 -0
  10. package/dist/lib/e2e/release.mjs +559 -0
  11. package/dist/lib/e2e/tarball.d.mts +13 -0
  12. package/dist/lib/e2e/tarball.mjs +99 -0
  13. package/dist/lib/e2e/testHarness.d.mts +123 -0
  14. package/dist/lib/e2e/testHarness.mjs +507 -0
  15. package/dist/lib/e2e/types.d.mts +32 -0
  16. package/dist/lib/getShortName.mjs +6 -1
  17. package/dist/lib/getShortName.test.d.mts +1 -0
  18. package/dist/lib/getShortName.test.mjs +25 -0
  19. package/dist/lib/hasPkgScript.d.mts +4 -1
  20. package/dist/lib/hasPkgScript.mjs +9 -6
  21. package/dist/lib/hasPkgScript.test.d.mts +1 -0
  22. package/dist/lib/hasPkgScript.test.mjs +33 -0
  23. package/dist/lib/jsonUtils.mjs +3 -0
  24. package/dist/lib/jsonUtils.test.d.mts +1 -0
  25. package/dist/lib/jsonUtils.test.mjs +90 -0
  26. package/dist/lib/normalizeModulePath.d.mts +5 -0
  27. package/dist/lib/normalizeModulePath.mjs +1 -1
  28. package/dist/lib/normalizeModulePath.test.d.mts +1 -0
  29. package/dist/lib/{normalizeModulePath.test.js → normalizeModulePath.test.mjs} +20 -1
  30. package/dist/lib/smokeTests/browser.mjs +3 -94
  31. package/dist/lib/smokeTests/development.mjs +2 -223
  32. package/dist/lib/smokeTests/environment.d.mts +4 -11
  33. package/dist/lib/smokeTests/environment.mjs +10 -158
  34. package/dist/lib/smokeTests/release.d.mts +2 -49
  35. package/dist/lib/smokeTests/release.mjs +3 -503
  36. package/dist/runtime/lib/injectHtmlAtMarker.d.ts +11 -0
  37. package/dist/runtime/lib/injectHtmlAtMarker.js +90 -0
  38. package/dist/runtime/lib/memoizeOnId.test.d.ts +1 -0
  39. package/dist/runtime/lib/memoizeOnId.test.js +49 -0
  40. package/dist/runtime/lib/realtime/protocol.test.d.ts +1 -0
  41. package/dist/runtime/lib/realtime/protocol.test.js +107 -0
  42. package/dist/runtime/lib/realtime/shared.test.d.ts +1 -0
  43. package/dist/runtime/lib/realtime/shared.test.js +18 -0
  44. package/dist/runtime/lib/realtime/validateUpgradeRequest.test.d.ts +1 -0
  45. package/dist/runtime/lib/realtime/validateUpgradeRequest.test.js +66 -0
  46. package/dist/runtime/lib/realtime/worker.d.ts +1 -1
  47. package/dist/runtime/lib/router.js +40 -22
  48. package/dist/runtime/lib/router.test.js +591 -2
  49. package/dist/runtime/lib/rwContext.d.ts +22 -0
  50. package/dist/runtime/lib/rwContext.js +1 -0
  51. package/dist/runtime/lib/turnstile/verifyTurnstileToken.d.ts +2 -1
  52. package/dist/runtime/lib/turnstile/verifyTurnstileToken.js +6 -6
  53. package/dist/runtime/lib/turnstile/verifyTurnstileToken.test.d.ts +1 -0
  54. package/dist/runtime/lib/turnstile/verifyTurnstileToken.test.js +49 -0
  55. package/dist/runtime/register/worker.d.ts +1 -1
  56. package/dist/runtime/register/worker.js +26 -21
  57. package/dist/runtime/render/assembleDocument.d.ts +6 -0
  58. package/dist/runtime/render/assembleDocument.js +22 -0
  59. package/dist/runtime/render/createThenableFromReadableStream.d.ts +1 -0
  60. package/dist/runtime/render/createThenableFromReadableStream.js +9 -0
  61. package/dist/runtime/render/normalizeActionResult.d.ts +1 -0
  62. package/dist/runtime/render/normalizeActionResult.js +43 -0
  63. package/dist/runtime/render/preloads.d.ts +2 -2
  64. package/dist/runtime/render/preloads.js +2 -3
  65. package/dist/runtime/render/{renderRscThenableToHtmlStream.d.ts → renderDocumentHtmlStream.d.ts} +3 -3
  66. package/dist/runtime/render/renderDocumentHtmlStream.js +39 -0
  67. package/dist/runtime/render/renderHtmlStream.d.ts +7 -0
  68. package/dist/runtime/render/renderHtmlStream.js +31 -0
  69. package/dist/runtime/render/renderToRscStream.d.ts +2 -3
  70. package/dist/runtime/render/renderToRscStream.js +2 -41
  71. package/dist/runtime/render/renderToStream.d.ts +2 -1
  72. package/dist/runtime/render/renderToStream.js +15 -8
  73. package/dist/runtime/render/stylesheets.d.ts +2 -2
  74. package/dist/runtime/render/stylesheets.js +2 -3
  75. package/dist/runtime/ssrBridge.d.ts +2 -1
  76. package/dist/runtime/ssrBridge.js +2 -1
  77. package/dist/runtime/worker.d.ts +1 -0
  78. package/dist/runtime/worker.js +11 -6
  79. package/dist/scripts/debug-sync.mjs +102 -133
  80. package/dist/vite/buildApp.d.mts +2 -1
  81. package/dist/vite/buildApp.mjs +9 -5
  82. package/dist/vite/checkIsUsingPrisma.d.mts +4 -0
  83. package/dist/vite/checkIsUsingPrisma.mjs +2 -2
  84. package/dist/vite/checkIsUsingPrisma.test.d.mts +1 -0
  85. package/dist/vite/checkIsUsingPrisma.test.mjs +30 -0
  86. package/dist/vite/configPlugin.mjs +35 -14
  87. package/dist/vite/createDirectiveLookupPlugin.d.mts +9 -0
  88. package/dist/vite/createDirectiveLookupPlugin.mjs +33 -29
  89. package/dist/vite/createDirectiveLookupPlugin.test.d.mts +1 -0
  90. package/dist/vite/createDirectiveLookupPlugin.test.mjs +40 -0
  91. package/dist/vite/directiveModulesDevPlugin.d.mts +4 -1
  92. package/dist/vite/directiveModulesDevPlugin.mjs +5 -4
  93. package/dist/vite/directiveModulesDevPlugin.test.d.mts +1 -0
  94. package/dist/vite/directiveModulesDevPlugin.test.mjs +59 -0
  95. package/dist/vite/directivesPlugin.d.mts +1 -0
  96. package/dist/vite/directivesPlugin.mjs +1 -1
  97. package/dist/vite/directivesPlugin.test.d.mts +1 -0
  98. package/dist/vite/directivesPlugin.test.mjs +24 -0
  99. package/dist/vite/ensureAliasArray.test.d.mts +1 -0
  100. package/dist/vite/ensureAliasArray.test.mjs +71 -0
  101. package/dist/vite/findSpecifiers.mjs +2 -1
  102. package/dist/vite/findSpecifiers.test.d.mts +1 -0
  103. package/dist/vite/findSpecifiers.test.mjs +202 -0
  104. package/dist/vite/findSsrSpecifiers.test.d.mts +1 -0
  105. package/dist/vite/findSsrSpecifiers.test.mjs +99 -0
  106. package/dist/vite/hasDirective.d.mts +6 -3
  107. package/dist/vite/hasDirective.mjs +43 -27
  108. package/dist/vite/hasDirective.test.d.mts +1 -0
  109. package/dist/vite/hasDirective.test.mjs +107 -0
  110. package/dist/vite/isJsFile.test.d.mts +1 -0
  111. package/dist/vite/isJsFile.test.mjs +38 -0
  112. package/dist/vite/{reactConditionsResolverPlugin.d.mts → knownDepsResolverPlugin.d.mts} +2 -2
  113. package/dist/vite/{reactConditionsResolverPlugin.mjs → knownDepsResolverPlugin.mjs} +28 -23
  114. package/dist/vite/linkerPlugin.d.mts +8 -0
  115. package/dist/vite/linkerPlugin.mjs +30 -22
  116. package/dist/vite/linkerPlugin.test.d.mts +1 -0
  117. package/dist/vite/linkerPlugin.test.mjs +41 -0
  118. package/dist/vite/miniflareHMRPlugin.d.mts +5 -0
  119. package/dist/vite/miniflareHMRPlugin.mjs +2 -2
  120. package/dist/vite/miniflareHMRPlugin.test.d.mts +1 -0
  121. package/dist/vite/miniflareHMRPlugin.test.mjs +42 -0
  122. package/dist/vite/redwoodPlugin.d.mts +7 -0
  123. package/dist/vite/redwoodPlugin.mjs +10 -5
  124. package/dist/vite/redwoodPlugin.test.d.mts +1 -0
  125. package/dist/vite/redwoodPlugin.test.mjs +34 -0
  126. package/dist/vite/runDirectivesScan.d.mts +21 -1
  127. package/dist/vite/runDirectivesScan.mjs +67 -52
  128. package/dist/vite/runDirectivesScan.test.d.mts +1 -0
  129. package/dist/vite/runDirectivesScan.test.mjs +73 -0
  130. package/dist/vite/ssrBridgePlugin.mjs +8 -1
  131. package/dist/vite/transformClientComponents.mjs +4 -3
  132. package/dist/vite/transformClientComponents.test.mjs +116 -58
  133. package/package.json +8 -4
  134. package/dist/runtime/render/renderRscThenableToHtmlStream.js +0 -54
  135. package/dist/runtime/render/transformRscToHtmlStream.d.ts +0 -8
  136. package/dist/runtime/render/transformRscToHtmlStream.js +0 -19
  137. /package/dist/lib/{normalizeModulePath.test.d.ts → e2e/types.mjs} +0 -0
@@ -6,27 +6,6 @@ import { existsSync } from "node:fs";
6
6
  import chokidar from "chokidar";
7
7
  import { lock } from "proper-lockfile";
8
8
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
- const getPackageManagerInfo = (targetDir) => {
10
- if (existsSync(path.join(targetDir, "bun.lock"))) {
11
- return { name: "bun", lockFile: "bun.lock", command: "add" };
12
- }
13
- const pnpmResult = {
14
- name: "pnpm",
15
- lockFile: "pnpm-lock.yaml",
16
- command: "add",
17
- };
18
- if (existsSync(path.join(targetDir, "yarn.lock"))) {
19
- return { name: "yarn", lockFile: "yarn.lock", command: "add" };
20
- }
21
- if (existsSync(path.join(targetDir, "pnpm-lock.yaml")) ||
22
- existsSync(path.join(targetDir, "node_modules", ".pnpm"))) {
23
- return pnpmResult;
24
- }
25
- if (existsSync(path.join(targetDir, "package-lock.json"))) {
26
- return { name: "npm", lockFile: "package-lock.json", command: "install" };
27
- }
28
- return pnpmResult;
29
- };
30
9
  const cleanupViteEntries = async (targetDir) => {
31
10
  const nodeModulesDir = path.join(targetDir, "node_modules");
32
11
  if (!existsSync(nodeModulesDir)) {
@@ -58,91 +37,6 @@ const cleanupViteEntries = async (targetDir) => {
58
37
  console.log(`Failed to cleanup vite cache entries: ${error}`);
59
38
  }
60
39
  };
61
- const performFullSync = async (sdkDir, targetDir) => {
62
- let tarballPath = "";
63
- let tarballName = "";
64
- // Clean up vite cache
65
- await cleanupViteEntries(targetDir);
66
- try {
67
- console.log("📦 Packing SDK...");
68
- const packResult = await $({ cwd: sdkDir }) `npm pack --json`;
69
- const json = JSON.parse(packResult.stdout || "[]");
70
- const packInfo = Array.isArray(json) ? json[0] : undefined;
71
- tarballName = (packInfo && (packInfo.filename || packInfo.name)) || "";
72
- if (!tarballName) {
73
- console.error("❌ Failed to get tarball name from npm pack.");
74
- return;
75
- }
76
- tarballPath = path.resolve(sdkDir, tarballName);
77
- console.log(`💿 Installing ${tarballName} in ${targetDir}...`);
78
- const pm = getPackageManagerInfo(targetDir);
79
- const packageJsonPath = path.join(targetDir, "package.json");
80
- const lockfilePath = path.join(targetDir, pm.lockFile);
81
- const originalPackageJson = await fs
82
- .readFile(packageJsonPath, "utf-8")
83
- .catch(() => null);
84
- const originalLockfile = await fs
85
- .readFile(lockfilePath, "utf-8")
86
- .catch(() => null);
87
- try {
88
- // For bun, we need to remove the existing dependency from package.json
89
- // before adding the tarball to avoid a dependency loop error.
90
- if (pm.name === "bun" && originalPackageJson) {
91
- try {
92
- const targetPackageJson = JSON.parse(originalPackageJson);
93
- let modified = false;
94
- if (targetPackageJson.dependencies?.rwsdk) {
95
- delete targetPackageJson.dependencies.rwsdk;
96
- modified = true;
97
- }
98
- if (targetPackageJson.devDependencies?.rwsdk) {
99
- delete targetPackageJson.devDependencies.rwsdk;
100
- modified = true;
101
- }
102
- if (modified) {
103
- console.log("Temporarily removing rwsdk from target package.json to prevent dependency loop with bun.");
104
- await fs.writeFile(packageJsonPath, JSON.stringify(targetPackageJson, null, 2));
105
- }
106
- }
107
- catch (e) {
108
- console.warn("Could not modify target package.json, proceeding anyway.");
109
- }
110
- }
111
- const cmd = pm.name;
112
- const args = [pm.command];
113
- if (pm.name === "yarn") {
114
- // For modern yarn, disable PnP to avoid resolution issues with local tarballs
115
- process.env.YARN_NODE_LINKER = "node-modules";
116
- args.push(`rwsdk@file:${tarballPath}`);
117
- }
118
- else {
119
- args.push(tarballPath);
120
- }
121
- await $(cmd, args, {
122
- cwd: targetDir,
123
- stdio: "inherit",
124
- });
125
- }
126
- finally {
127
- if (originalPackageJson) {
128
- console.log("Restoring package.json...");
129
- await fs.writeFile(packageJsonPath, originalPackageJson);
130
- }
131
- if (originalLockfile) {
132
- console.log(`Restoring ${pm.lockFile}...`);
133
- await fs.writeFile(lockfilePath, originalLockfile);
134
- }
135
- }
136
- }
137
- finally {
138
- if (tarballPath) {
139
- console.log("Removing tarball...");
140
- await fs.unlink(tarballPath).catch(() => {
141
- // ignore if deletion fails
142
- });
143
- }
144
- }
145
- };
146
40
  const syncFilesWithRsyncOrFs = async (sdkDir, destDir, filesEntries) => {
147
41
  const sources = filesEntries.map((p) => path.join(sdkDir, p));
148
42
  // Always include package.json in sync
@@ -191,45 +85,120 @@ const syncFilesWithRsyncOrFs = async (sdkDir, destDir, filesEntries) => {
191
85
  }
192
86
  }
193
87
  };
194
- const performFastSync = async (sdkDir, targetDir) => {
195
- console.log("⚡️ No dependency changes, performing fast sync...");
196
- // Clean up vite cache
197
- await cleanupViteEntries(targetDir);
198
- const nodeModulesPkgDir = path.join(targetDir, "node_modules", "rwsdk");
199
- // Copy directories/files declared in package.json#files (plus package.json)
200
- const filesToSync = JSON.parse(await fs.readFile(path.join(sdkDir, "package.json"), "utf-8"))
201
- .files || [];
202
- await syncFilesWithRsyncOrFs(sdkDir, nodeModulesPkgDir, filesToSync);
88
+ const findUp = async (names, startDir) => {
89
+ let dir = startDir;
90
+ while (dir !== path.dirname(dir)) {
91
+ for (const name of names) {
92
+ const filePath = path.join(dir, name);
93
+ if (existsSync(filePath)) {
94
+ return dir;
95
+ }
96
+ }
97
+ dir = path.dirname(dir);
98
+ }
99
+ return undefined;
100
+ };
101
+ const getMonorepoRoot = async (startDir) => {
102
+ try {
103
+ // `pnpm root` is the most reliable way to find the workspace root node_modules
104
+ const { stdout } = await $({
105
+ cwd: startDir,
106
+ }) `pnpm root`;
107
+ // pnpm root returns the node_modules path, so we go up one level
108
+ return path.resolve(stdout, "..");
109
+ }
110
+ catch (e) {
111
+ console.warn(`Could not determine pnpm root from ${startDir}. Falling back to file search.`);
112
+ const root = await findUp(["pnpm-workspace.yaml"], startDir);
113
+ if (root) {
114
+ return root;
115
+ }
116
+ }
117
+ console.warn("Could not find pnpm monorepo root. Using parent directory of target as fallback.");
118
+ return path.resolve(startDir, "..");
203
119
  };
204
120
  const areDependenciesEqual = (deps1, deps2) => {
205
121
  // Simple string comparison for this use case is sufficient
206
122
  return JSON.stringify(deps1 ?? {}) === JSON.stringify(deps2 ?? {});
207
123
  };
124
+ const performFullSync = async (sdkDir, targetDir, monorepoRoot) => {
125
+ console.log("📦 Performing full sync with tarball...");
126
+ let tarballPath = "";
127
+ const projectName = path.basename(targetDir);
128
+ const rwsyncDir = path.join(monorepoRoot, "node_modules", `.rwsync_${projectName}`);
129
+ try {
130
+ // 1. Pack the SDK
131
+ const packResult = await $({ cwd: sdkDir }) `npm pack --json`;
132
+ const json = JSON.parse(packResult.stdout || "[]");
133
+ const packInfo = Array.isArray(json) ? json[0] : undefined;
134
+ const tarballName = (packInfo && (packInfo.filename || packInfo.name)) || "";
135
+ if (!tarballName) {
136
+ throw new Error("Failed to get tarball name from npm pack.");
137
+ }
138
+ tarballPath = path.resolve(sdkDir, tarballName);
139
+ // 2. Prepare isolated install directory
140
+ console.log(`Preparing isolated install directory at ${rwsyncDir}`);
141
+ await fs.rm(rwsyncDir, { recursive: true, force: true });
142
+ await fs.mkdir(rwsyncDir, { recursive: true });
143
+ await fs.writeFile(path.join(rwsyncDir, "package.json"), JSON.stringify({ name: `rwsync-env-${projectName}` }, null, 2));
144
+ // 3. Perform isolated install
145
+ console.log(`Installing ${tarballName} in isolation...`);
146
+ await $("pnpm", ["add", tarballPath], {
147
+ cwd: rwsyncDir,
148
+ stdio: "inherit",
149
+ });
150
+ // 4. Create symlink
151
+ const symlinkSource = path.join(rwsyncDir, "node_modules", "rwsdk");
152
+ const symlinkTarget = path.join(targetDir, "node_modules", "rwsdk");
153
+ console.log(`Symlinking ${symlinkTarget} -> ${symlinkSource}`);
154
+ await fs.rm(symlinkTarget, { recursive: true, force: true });
155
+ await fs.mkdir(path.dirname(symlinkTarget), { recursive: true });
156
+ await fs.symlink(symlinkSource, symlinkTarget, "dir");
157
+ }
158
+ finally {
159
+ if (tarballPath) {
160
+ console.log("Removing tarball...");
161
+ await fs.unlink(tarballPath).catch(() => { });
162
+ }
163
+ }
164
+ };
165
+ const performFastSync = async (sdkDir, targetDir, monorepoRoot) => {
166
+ console.log("⚡️ Performing fast sync with rsync...");
167
+ const projectName = path.basename(targetDir);
168
+ const rwsyncDir = path.join(monorepoRoot, "node_modules", `.rwsync_${projectName}`);
169
+ const syncDestDir = path.join(rwsyncDir, "node_modules", "rwsdk");
170
+ // Copy directories/files declared in package.json#files (plus package.json)
171
+ const filesToSync = JSON.parse(await fs.readFile(path.join(sdkDir, "package.json"), "utf-8"))
172
+ .files || [];
173
+ await syncFilesWithRsyncOrFs(sdkDir, syncDestDir, filesToSync);
174
+ };
208
175
  const performSync = async (sdkDir, targetDir) => {
209
176
  console.log("🏗️ Rebuilding SDK...");
210
177
  await $ `pnpm build`;
211
- const forceFullSync = Boolean(process.env.RWSDK_FORCE_FULL_SYNC);
212
- if (forceFullSync) {
213
- console.log("🏃 Force full sync mode is enabled.");
214
- await performFullSync(sdkDir, targetDir);
215
- console.log(" Done syncing");
216
- return;
178
+ // Clean up vite cache in the target project
179
+ await cleanupViteEntries(targetDir);
180
+ const monorepoRoot = await getMonorepoRoot(targetDir);
181
+ const projectName = path.basename(targetDir);
182
+ const installedSdkPackageJsonPath = path.join(monorepoRoot, "node_modules", `.rwsync_${projectName}`, "node_modules", "rwsdk", "package.json");
183
+ let needsFullSync = false;
184
+ if (!existsSync(installedSdkPackageJsonPath)) {
185
+ console.log("No previous sync found, performing full sync.");
186
+ needsFullSync = true;
217
187
  }
218
- const sdkPackageJsonPath = path.join(sdkDir, "package.json");
219
- const installedSdkPackageJsonPath = path.join(targetDir, "node_modules/rwsdk/package.json");
220
- let packageJsonChanged = true;
221
- if (existsSync(installedSdkPackageJsonPath)) {
222
- const sdkPackageJsonContent = await fs.readFile(sdkPackageJsonPath, "utf-8");
223
- const installedSdkPackageJsonContent = await fs.readFile(installedSdkPackageJsonPath, "utf-8");
224
- packageJsonChanged =
225
- sdkPackageJsonContent !== installedSdkPackageJsonContent;
188
+ else {
189
+ const sdkPackageJson = JSON.parse(await fs.readFile(path.join(sdkDir, "package.json"), "utf-8"));
190
+ const installedSdkPackageJson = JSON.parse(await fs.readFile(installedSdkPackageJsonPath, "utf-8"));
191
+ if (!areDependenciesEqual(sdkPackageJson.dependencies, installedSdkPackageJson.dependencies) ||
192
+ !areDependenciesEqual(sdkPackageJson.devDependencies, installedSdkPackageJson.devDependencies)) {
193
+ console.log("Dependency changes detected, performing full sync.");
194
+ needsFullSync = true;
195
+ }
226
196
  }
227
- if (packageJsonChanged) {
228
- console.log("📦 package.json changed, performing full sync...");
229
- await performFullSync(sdkDir, targetDir);
197
+ if (needsFullSync) {
198
+ await performFullSync(sdkDir, targetDir, monorepoRoot);
230
199
  }
231
200
  else {
232
- await performFastSync(sdkDir, targetDir);
201
+ await performFastSync(sdkDir, targetDir, monorepoRoot);
233
202
  }
234
203
  console.log("✅ Done syncing");
235
204
  };
@@ -6,10 +6,11 @@ import type { ViteBuilder } from "vite";
6
6
  *
7
7
  * @see docs/architecture/productionBuildProcess.md
8
8
  */
9
- export declare function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, }: {
9
+ export declare function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, workerEntryPathname, }: {
10
10
  builder: ViteBuilder;
11
11
  clientEntryPoints: Set<string>;
12
12
  clientFiles: Set<string>;
13
13
  serverFiles: Set<string>;
14
14
  projectRootDir: string;
15
+ workerEntryPathname: string;
15
16
  }): Promise<void>;
@@ -9,13 +9,14 @@ const log = debug("rwsdk:vite:build-app");
9
9
  *
10
10
  * @see docs/architecture/productionBuildProcess.md
11
11
  */
12
- export async function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, }) {
12
+ export async function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, workerEntryPathname, }) {
13
13
  const workerEnv = builder.environments.worker;
14
14
  await runDirectivesScan({
15
15
  rootConfig: builder.config,
16
16
  environments: builder.environments,
17
17
  clientFiles,
18
18
  serverFiles,
19
+ entries: [workerEntryPathname],
19
20
  });
20
21
  console.log("Building worker to discover used client components...");
21
22
  process.env.RWSDK_BUILD_PASS = "worker";
@@ -42,11 +43,14 @@ export async function buildApp({ builder, clientEntryPoints, clientFiles, server
42
43
  // Re-configure the worker environment for the linking pass
43
44
  const workerConfig = workerEnv.config;
44
45
  workerConfig.build.emptyOutDir = false;
46
+ // context(justinvdm, 22 Sep 2025): This is a workaround to satisfy the
47
+ // Cloudflare plugin's expectation of an entry chunk named `index`. The plugin
48
+ // now manages the worker build, so we no longer set rollup options
49
+ // directly. Instead, we re-point the original entry to the intermediate
50
+ // worker bundle from the first pass. This allows the linker pass to re-use
51
+ // the same plugin-driven configuration while bundling the final worker.
45
52
  workerConfig.build.rollupOptions.input = {
46
- worker: resolve(projectRootDir, "dist", "worker", "worker.js"),
47
- };
48
- workerConfig.build.rollupOptions.output = {
49
- entryFileNames: "worker.js",
53
+ index: resolve(projectRootDir, "dist", "worker", "index.js"),
50
54
  };
51
55
  await builder.build(workerEnv);
52
56
  console.log("Build complete!");
@@ -1,6 +1,10 @@
1
1
  export type PrismaCheckResult = {
2
2
  isUsingPrisma: boolean;
3
3
  };
4
+ export declare const isUsingPrisma: ({ projectRootDir, resolver, }: {
5
+ projectRootDir: string;
6
+ resolver?: (path: string, request: string) => string | false;
7
+ }) => boolean;
4
8
  export declare const checkPrismaStatus: ({ projectRootDir, }: {
5
9
  projectRootDir: string;
6
10
  }) => PrismaCheckResult;
@@ -1,7 +1,7 @@
1
1
  import enhancedResolve from "enhanced-resolve";
2
- const isUsingPrisma = ({ projectRootDir }) => {
2
+ export const isUsingPrisma = ({ projectRootDir, resolver = enhancedResolve.sync, }) => {
3
3
  try {
4
- const prismaClientPath = enhancedResolve.sync(projectRootDir, "@prisma/client");
4
+ const prismaClientPath = resolver(projectRootDir, "@prisma/client");
5
5
  if (!prismaClientPath) {
6
6
  return false;
7
7
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { isUsingPrisma } from "./checkIsUsingPrisma.mjs";
3
+ describe("isUsingPrisma", () => {
4
+ it("should return true if prisma client is resolved", () => {
5
+ const resolver = () => "/path/to/prisma/client";
6
+ const result = isUsingPrisma({
7
+ projectRootDir: "/test/project",
8
+ resolver: resolver,
9
+ });
10
+ expect(result).toBe(true);
11
+ });
12
+ it("should return false if prisma client is not resolved", () => {
13
+ const resolver = () => false;
14
+ const result = isUsingPrisma({
15
+ projectRootDir: "/test/project",
16
+ resolver: resolver,
17
+ });
18
+ expect(result).toBe(false);
19
+ });
20
+ it("should return false if resolver throws", () => {
21
+ const resolver = () => {
22
+ throw new Error("Module not found");
23
+ };
24
+ const result = isUsingPrisma({
25
+ projectRootDir: "/test/project",
26
+ resolver: resolver,
27
+ });
28
+ expect(result).toBe(false);
29
+ });
30
+ });
@@ -1,13 +1,11 @@
1
1
  import path, { resolve } from "node:path";
2
2
  import enhancedResolve from "enhanced-resolve";
3
- import debug from "debug";
4
3
  import { INTERMEDIATE_SSR_BRIDGE_PATH } from "../lib/constants.mjs";
5
4
  import { buildApp } from "./buildApp.mjs";
6
5
  import { externalModules } from "./constants.mjs";
7
- const log = debug("rwsdk:vite:config");
8
6
  export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clientFiles, serverFiles, clientEntryPoints, }) => ({
9
7
  name: "rwsdk:config",
10
- config: async (_) => {
8
+ config: async (_, { command }) => {
11
9
  const mode = process.env.NODE_ENV;
12
10
  const workerConfig = {
13
11
  resolve: {
@@ -33,7 +31,15 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
33
31
  },
34
32
  optimizeDeps: {
35
33
  noDiscovery: false,
36
- include: ["rwsdk/worker"],
34
+ include: [
35
+ "rwsdk/worker",
36
+ "rwsdk/router",
37
+ "rwsdk/auth",
38
+ "rwsdk/db",
39
+ "rwsdk/__ssr_bridge",
40
+ "rwsdk/realtime/worker",
41
+ "rwsdk/realtime/durableObject",
42
+ ],
37
43
  exclude: [],
38
44
  entries: [workerEntryPathname],
39
45
  esbuildOptions: {
@@ -49,14 +55,6 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
49
55
  emitAssets: true,
50
56
  emptyOutDir: false,
51
57
  ssr: true,
52
- rollupOptions: {
53
- output: {
54
- inlineDynamicImports: true,
55
- },
56
- input: {
57
- worker: workerEntryPathname,
58
- },
59
- },
60
58
  },
61
59
  };
62
60
  const baseConfig = {
@@ -88,7 +86,7 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
88
86
  },
89
87
  optimizeDeps: {
90
88
  noDiscovery: false,
91
- include: ["rwsdk/client"],
89
+ include: ["rwsdk/client", "rwsdk/realtime/client"],
92
90
  entries: [],
93
91
  esbuildOptions: {
94
92
  jsx: "automatic",
@@ -115,7 +113,7 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
115
113
  noDiscovery: false,
116
114
  entries: [workerEntryPathname],
117
115
  exclude: externalModules,
118
- include: ["rwsdk/__ssr", "rwsdk/__ssr_bridge"],
116
+ include: ["rwsdk/__ssr", "rwsdk/__ssr_bridge", "rwsdk/client"],
119
117
  esbuildOptions: {
120
118
  jsx: "automatic",
121
119
  jsxImportSource: "react",
@@ -136,8 +134,30 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
136
134
  outDir: path.dirname(INTERMEDIATE_SSR_BRIDGE_PATH),
137
135
  rollupOptions: {
138
136
  output: {
137
+ // context(justinvdm, 15 Sep 2025): The SSR bundle is a
138
+ // pre-compiled artifact. When the linker pass bundles it into
139
+ // the intermediate worker bundle (another pre-compiled
140
+ // artifact), Rollup merges their top-level scopes. Since both
141
+ // may have identical minified identifiers (e.g., `l0`), this
142
+ // causes a redeclaration error. To solve this, we wrap the SSR
143
+ // bundle in an exporting IIFE. This creates a scope boundary,
144
+ // preventing symbol collisions while producing a valid,
145
+ // tree-shakeable ES module. The inline plugin below removes the
146
+ // original `export` statement from the bundle to prevent syntax
147
+ // errors.
139
148
  inlineDynamicImports: true,
149
+ banner: `export const { renderHtmlStream, ssrLoadModule, ssrWebpackRequire, ssrGetModuleExport, createThenableFromReadableStream } = (function() {`,
150
+ footer: `return { renderHtmlStream, ssrLoadModule, ssrWebpackRequire, ssrGetModuleExport, createThenableFromReadableStream };\n})();`,
140
151
  },
152
+ plugins: [
153
+ {
154
+ name: "rwsdk:ssr-bridge-exports",
155
+ renderChunk(code) {
156
+ // Remove the original export statement as it's now handled by the banner/footer
157
+ return code.replace(/export\s*{[^}]+};?/, "");
158
+ },
159
+ },
160
+ ],
141
161
  },
142
162
  },
143
163
  },
@@ -154,6 +174,7 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
154
174
  clientEntryPoints,
155
175
  clientFiles,
156
176
  serverFiles,
177
+ workerEntryPathname,
157
178
  });
158
179
  },
159
180
  },
@@ -1,4 +1,13 @@
1
1
  import { Plugin } from "vite";
2
+ export declare function generateLookupMap({ files, isDev, kind, exportName, }: {
3
+ files: Set<string>;
4
+ isDev: boolean;
5
+ kind: "client" | "server";
6
+ exportName: string;
7
+ }): {
8
+ code: string;
9
+ map: import("magic-string").SourceMap;
10
+ };
2
11
  interface DirectiveLookupConfig {
3
12
  kind: "client" | "server";
4
13
  directive: "use client" | "use server";
@@ -2,6 +2,33 @@ import MagicString from "magic-string";
2
2
  import path from "path";
3
3
  import debug from "debug";
4
4
  import { VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, } from "../lib/constants.mjs";
5
+ export function generateLookupMap({ files, isDev, kind, exportName, }) {
6
+ const s = new MagicString(`
7
+ export const ${exportName} = {
8
+ ${Array.from(files)
9
+ .map((file) => {
10
+ if (file.includes("node_modules") && isDev) {
11
+ const barrelPath = kind === "client"
12
+ ? VENDOR_CLIENT_BARREL_EXPORT_PATH
13
+ : VENDOR_SERVER_BARREL_EXPORT_PATH;
14
+ return `
15
+ "${file}": () => import("${barrelPath}").then(m => m.default["${file}"]),
16
+ `;
17
+ }
18
+ else {
19
+ return `
20
+ "${file}": () => import("${file}"),
21
+ `;
22
+ }
23
+ })
24
+ .join("")}
25
+ };
26
+ `);
27
+ return {
28
+ code: s.toString(),
29
+ map: s.generateMap(),
30
+ };
31
+ }
5
32
  export const createDirectiveLookupPlugin = async ({ projectRootDir, files, config, }) => {
6
33
  const debugNamespace = `rwsdk:vite:${config.pluginName}`;
7
34
  const log = debug(debugNamespace);
@@ -121,35 +148,12 @@ export const createDirectiveLookupPlugin = async ({ projectRootDir, files, confi
121
148
  log("Loading %s module with %d files", config.virtualModuleName, files.size);
122
149
  const environment = this.environment?.name || "client";
123
150
  log("Current environment: %s, isDev: %s", environment, isDev);
124
- const s = new MagicString(`
125
- export const ${config.exportName} = {
126
- ${Array.from(files)
127
- .map((file) => {
128
- if (file.includes("node_modules") && isDev) {
129
- const barrelPath = config.kind === "client"
130
- ? VENDOR_CLIENT_BARREL_EXPORT_PATH
131
- : VENDOR_SERVER_BARREL_EXPORT_PATH;
132
- return `
133
- "${file}": () => import("${barrelPath}").then(m => m.default["${file}"]),
134
- `;
135
- }
136
- else {
137
- return `
138
- "${file}": () => import("${file}"),
139
- `;
140
- }
141
- })
142
- .join("")}
143
- };
144
- `);
145
- const code = s.toString();
146
- const map = s.generateMap();
147
- log("Generated virtual module code length: %d", code.length);
148
- process.env.VERBOSE && log("Generated virtual module code: %s", code);
149
- return {
150
- code,
151
- map,
152
- };
151
+ return generateLookupMap({
152
+ files,
153
+ isDev,
154
+ kind: config.kind,
155
+ exportName: config.exportName,
156
+ });
153
157
  }
154
158
  },
155
159
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { generateLookupMap } from "./createDirectiveLookupPlugin.mjs";
3
+ import { VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, } from "../lib/constants.mjs";
4
+ describe("generateLookupMap", () => {
5
+ const files = new Set([
6
+ "src/app.js",
7
+ "node_modules/lib-a/index.js",
8
+ "src/component.tsx",
9
+ ]);
10
+ it("should generate correct map for client in dev", () => {
11
+ const result = generateLookupMap({
12
+ files,
13
+ isDev: true,
14
+ kind: "client",
15
+ exportName: "clientLookup",
16
+ });
17
+ expect(result.code).toContain("export const clientLookup = {");
18
+ expect(result.code).toContain(`"src/app.js": () => import("src/app.js")`);
19
+ expect(result.code).toContain(`"node_modules/lib-a/index.js": () => import("${VENDOR_CLIENT_BARREL_EXPORT_PATH}").then(m => m.default["node_modules/lib-a/index.js"])`);
20
+ });
21
+ it("should generate correct map for server in dev", () => {
22
+ const result = generateLookupMap({
23
+ files,
24
+ isDev: true,
25
+ kind: "server",
26
+ exportName: "serverLookup",
27
+ });
28
+ expect(result.code).toContain("export const serverLookup = {");
29
+ expect(result.code).toContain(`"node_modules/lib-a/index.js": () => import("${VENDOR_SERVER_BARREL_EXPORT_PATH}").then(m => m.default["node_modules/lib-a/index.js"])`);
30
+ });
31
+ it("should generate correct map for prod (isDev: false)", () => {
32
+ const result = generateLookupMap({
33
+ files,
34
+ isDev: false,
35
+ kind: "client",
36
+ exportName: "clientLookup",
37
+ });
38
+ expect(result.code).toContain(`"node_modules/lib-a/index.js": () => import("node_modules/lib-a/index.js")`);
39
+ });
40
+ });
@@ -1,6 +1,9 @@
1
1
  import { Plugin } from "vite";
2
- export declare const directiveModulesDevPlugin: ({ clientFiles, serverFiles, projectRootDir, }: {
2
+ export declare const generateVendorBarrelContent: (files: Set<string>, projectRootDir: string) => string;
3
+ export declare const generateAppBarrelContent: (files: Set<string>, projectRootDir: string) => string;
4
+ export declare const directiveModulesDevPlugin: ({ clientFiles, serverFiles, projectRootDir, workerEntryPathname, }: {
3
5
  clientFiles: Set<string>;
4
6
  serverFiles: Set<string>;
5
7
  projectRootDir: string;
8
+ workerEntryPathname: string;
6
9
  }) => Plugin;