rwsdk 0.2.0-alpha.9 → 0.2.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.
- package/dist/runtime/client/client.d.ts +10 -0
- package/dist/runtime/{client.js → client/client.js} +13 -10
- package/dist/runtime/client/navigation.d.ts +9 -0
- package/dist/runtime/client/navigation.js +88 -0
- package/dist/runtime/{clientNavigation.test.js → client/navigation.test.js} +1 -1
- package/dist/runtime/client/setWebpackRequire.d.ts +1 -0
- package/dist/runtime/client/setWebpackRequire.js +2 -0
- package/dist/runtime/{client.d.ts → client/types.d.ts} +4 -10
- package/dist/runtime/client/types.js +1 -0
- package/dist/runtime/entries/client.d.ts +2 -2
- package/dist/runtime/entries/client.js +2 -2
- package/dist/runtime/imports/client.d.ts +3 -3
- package/dist/runtime/imports/client.js +7 -6
- package/dist/runtime/imports/ssr.d.ts +3 -3
- package/dist/runtime/imports/ssr.js +3 -3
- package/dist/runtime/imports/worker.d.ts +3 -3
- package/dist/runtime/imports/worker.js +3 -3
- package/dist/runtime/lib/manifest.d.ts +11 -2
- package/dist/runtime/lib/manifest.js +1 -1
- package/dist/runtime/lib/memoizeOnId.d.ts +1 -0
- package/dist/runtime/lib/memoizeOnId.js +11 -0
- package/dist/runtime/lib/realtime/client.d.ts +1 -1
- package/dist/runtime/lib/realtime/client.js +1 -1
- package/dist/runtime/lib/router.d.ts +3 -3
- package/dist/runtime/lib/router.js +77 -33
- package/dist/runtime/register/ssr.d.ts +1 -1
- package/dist/runtime/register/ssr.js +2 -2
- package/dist/runtime/render/preloads.d.ts +6 -0
- package/dist/runtime/render/preloads.js +40 -0
- package/dist/runtime/render/renderRscThenableToHtmlStream.js +2 -1
- package/dist/runtime/render/stylesheets.js +1 -1
- package/dist/runtime/requestInfo/types.d.ts +3 -1
- package/dist/runtime/worker.js +1 -1
- package/dist/scripts/debug-sync.mjs +159 -33
- package/dist/scripts/worker-run.mjs +8 -3
- package/dist/vite/hasOwnReactVitePlugin.d.mts +3 -0
- package/dist/vite/hasOwnReactVitePlugin.mjs +14 -0
- package/dist/vite/miniflareHMRPlugin.mjs +17 -2
- package/dist/vite/reactConditionsResolverPlugin.d.mts +3 -4
- package/dist/vite/reactConditionsResolverPlugin.mjs +71 -48
- package/dist/vite/redwoodPlugin.d.mts +1 -0
- package/dist/vite/redwoodPlugin.mjs +9 -3
- package/dist/vite/transformJsxScriptTagsPlugin.mjs +106 -91
- package/dist/vite/transformJsxScriptTagsPlugin.test.mjs +341 -110
- package/package.json +22 -4
- /package/dist/runtime/{imports → client}/ClientOnly.d.ts +0 -0
- /package/dist/runtime/{imports → client}/ClientOnly.js +0 -0
- /package/dist/runtime/{clientNavigation.test.d.ts → client/navigation.test.d.ts} +0 -0
package/dist/runtime/worker.js
CHANGED
|
@@ -7,6 +7,9 @@ import chokidar from "chokidar";
|
|
|
7
7
|
import { lock } from "proper-lockfile";
|
|
8
8
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
const getPackageManagerInfo = (targetDir) => {
|
|
10
|
+
if (existsSync(path.join(targetDir, "bun.lock"))) {
|
|
11
|
+
return { name: "bun", lockFile: "bun.lock", command: "add" };
|
|
12
|
+
}
|
|
10
13
|
const pnpmResult = {
|
|
11
14
|
name: "pnpm",
|
|
12
15
|
lockFile: "pnpm-lock.yaml",
|
|
@@ -24,15 +27,67 @@ const getPackageManagerInfo = (targetDir) => {
|
|
|
24
27
|
}
|
|
25
28
|
return pnpmResult;
|
|
26
29
|
};
|
|
30
|
+
const cleanupViteEntries = async (targetDir) => {
|
|
31
|
+
const nodeModulesDir = path.join(targetDir, "node_modules");
|
|
32
|
+
if (!existsSync(nodeModulesDir)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const entries = await fs.readdir(nodeModulesDir);
|
|
37
|
+
const viteEntries = entries.filter((entry) => entry.startsWith(".vite"));
|
|
38
|
+
for (const entry of viteEntries) {
|
|
39
|
+
const entryPath = path.join(nodeModulesDir, entry);
|
|
40
|
+
try {
|
|
41
|
+
const stat = await fs.lstat(entryPath);
|
|
42
|
+
if (!stat.isSymbolicLink()) {
|
|
43
|
+
console.log(`Removing vite cache entry: ${entry}`);
|
|
44
|
+
await fs.rm(entryPath, { recursive: true, force: true });
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log(`Skipping symlinked vite cache entry: ${entry}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// If we can't stat it, try to remove it
|
|
52
|
+
console.log(`Removing vite cache entry: ${entry}`);
|
|
53
|
+
await fs.rm(entryPath, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.log(`Failed to cleanup vite cache entries: ${error}`);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
27
61
|
const performFullSync = async (sdkDir, targetDir) => {
|
|
28
62
|
const sdkPackageJsonPath = path.join(sdkDir, "package.json");
|
|
29
63
|
let originalSdkPackageJson = null;
|
|
30
64
|
let tarballPath = "";
|
|
31
65
|
let tarballName = "";
|
|
66
|
+
// Clean up vite cache
|
|
67
|
+
await cleanupViteEntries(targetDir);
|
|
32
68
|
try {
|
|
69
|
+
try {
|
|
70
|
+
originalSdkPackageJson = await fs.readFile(sdkPackageJsonPath, "utf-8");
|
|
71
|
+
const packageJson = JSON.parse(originalSdkPackageJson);
|
|
72
|
+
const originalVersion = packageJson.version;
|
|
73
|
+
const timestamp = new Date()
|
|
74
|
+
.toISOString()
|
|
75
|
+
.replace(/[-:T.]/g, "")
|
|
76
|
+
.slice(0, 14);
|
|
77
|
+
const newVersion = `${originalVersion}+build.${timestamp}`;
|
|
78
|
+
console.log(`Temporarily setting version to ${newVersion}`);
|
|
79
|
+
packageJson.version = newVersion;
|
|
80
|
+
await fs.writeFile(sdkPackageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
console.warn("Could not modify package.json version, proceeding without it.");
|
|
84
|
+
originalSdkPackageJson = null; // don't restore if we failed to modify
|
|
85
|
+
}
|
|
33
86
|
console.log("📦 Packing SDK...");
|
|
34
|
-
const packResult = await $({ cwd: sdkDir }) `npm pack`;
|
|
35
|
-
|
|
87
|
+
const packResult = await $({ cwd: sdkDir }) `npm pack --json`;
|
|
88
|
+
const json = JSON.parse(packResult.stdout || "[]");
|
|
89
|
+
const packInfo = Array.isArray(json) ? json[0] : undefined;
|
|
90
|
+
tarballName = (packInfo && (packInfo.filename || packInfo.name)) || "";
|
|
36
91
|
if (!tarballName) {
|
|
37
92
|
console.error("❌ Failed to get tarball name from npm pack.");
|
|
38
93
|
return;
|
|
@@ -49,6 +104,29 @@ const performFullSync = async (sdkDir, targetDir) => {
|
|
|
49
104
|
.readFile(lockfilePath, "utf-8")
|
|
50
105
|
.catch(() => null);
|
|
51
106
|
try {
|
|
107
|
+
// For bun, we need to remove the existing dependency from package.json
|
|
108
|
+
// before adding the tarball to avoid a dependency loop error.
|
|
109
|
+
if (pm.name === "bun" && originalPackageJson) {
|
|
110
|
+
try {
|
|
111
|
+
const targetPackageJson = JSON.parse(originalPackageJson);
|
|
112
|
+
let modified = false;
|
|
113
|
+
if (targetPackageJson.dependencies?.rwsdk) {
|
|
114
|
+
delete targetPackageJson.dependencies.rwsdk;
|
|
115
|
+
modified = true;
|
|
116
|
+
}
|
|
117
|
+
if (targetPackageJson.devDependencies?.rwsdk) {
|
|
118
|
+
delete targetPackageJson.devDependencies.rwsdk;
|
|
119
|
+
modified = true;
|
|
120
|
+
}
|
|
121
|
+
if (modified) {
|
|
122
|
+
console.log("Temporarily removing rwsdk from target package.json to prevent dependency loop with bun.");
|
|
123
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(targetPackageJson, null, 2));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
console.warn("Could not modify target package.json, proceeding anyway.");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
52
130
|
const cmd = pm.name;
|
|
53
131
|
const args = [pm.command];
|
|
54
132
|
if (pm.name === "yarn") {
|
|
@@ -86,19 +164,63 @@ const performFullSync = async (sdkDir, targetDir) => {
|
|
|
86
164
|
}
|
|
87
165
|
}
|
|
88
166
|
};
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
167
|
+
const syncFilesWithRsyncOrFs = async (sdkDir, destDir, filesEntries) => {
|
|
168
|
+
const sources = filesEntries.map((p) => path.join(sdkDir, p));
|
|
169
|
+
// Always include package.json in sync
|
|
170
|
+
const pkgJsonPath = path.join(sdkDir, "package.json");
|
|
171
|
+
sources.push(pkgJsonPath);
|
|
172
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
173
|
+
// Try rsync across all sources in one shot
|
|
174
|
+
try {
|
|
175
|
+
if (sources.length > 0) {
|
|
176
|
+
const rsyncArgs = [
|
|
177
|
+
"-a",
|
|
178
|
+
"--delete",
|
|
179
|
+
"--omit-dir-times",
|
|
180
|
+
"--no-perms",
|
|
181
|
+
"--no-owner",
|
|
182
|
+
"--no-group",
|
|
183
|
+
...sources,
|
|
184
|
+
destDir + path.sep,
|
|
185
|
+
];
|
|
186
|
+
await $({ stdio: "inherit" })("rsync", rsyncArgs);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// fall through to fs fallback
|
|
192
|
+
}
|
|
193
|
+
console.log("Rsync failed, falling back to fs");
|
|
194
|
+
// Fallback: destructive copy using Node fs to mirror content
|
|
195
|
+
await fs.rm(destDir, { recursive: true, force: true });
|
|
196
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
197
|
+
for (const src of sources) {
|
|
198
|
+
const rel = path.relative(sdkDir, src);
|
|
199
|
+
const dst = path.join(destDir, rel);
|
|
200
|
+
await fs.mkdir(path.dirname(dst), { recursive: true });
|
|
201
|
+
try {
|
|
202
|
+
const stat = await fs.lstat(src);
|
|
203
|
+
if (stat.isDirectory()) {
|
|
204
|
+
await fs.cp(src, dst, { recursive: true, force: true });
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
await fs.copyFile(src, dst);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
await fs.cp(src, dst, { recursive: true, force: true }).catch(() => { });
|
|
98
212
|
}
|
|
99
213
|
}
|
|
100
|
-
|
|
101
|
-
|
|
214
|
+
};
|
|
215
|
+
const performFastSync = async (sdkDir, targetDir) => {
|
|
216
|
+
console.log("⚡️ No dependency changes, performing fast sync...");
|
|
217
|
+
// Clean up vite cache
|
|
218
|
+
await cleanupViteEntries(targetDir);
|
|
219
|
+
const nodeModulesPkgDir = path.join(targetDir, "node_modules", "rwsdk");
|
|
220
|
+
// Copy directories/files declared in package.json#files (plus package.json)
|
|
221
|
+
const filesToSync = JSON.parse(await fs.readFile(path.join(sdkDir, "package.json"), "utf-8"))
|
|
222
|
+
.files || [];
|
|
223
|
+
await syncFilesWithRsyncOrFs(sdkDir, nodeModulesPkgDir, filesToSync);
|
|
102
224
|
};
|
|
103
225
|
const areDependenciesEqual = (deps1, deps2) => {
|
|
104
226
|
// Simple string comparison for this use case is sufficient
|
|
@@ -120,13 +242,8 @@ const performSync = async (sdkDir, targetDir) => {
|
|
|
120
242
|
if (existsSync(installedSdkPackageJsonPath)) {
|
|
121
243
|
const sdkPackageJsonContent = await fs.readFile(sdkPackageJsonPath, "utf-8");
|
|
122
244
|
const installedSdkPackageJsonContent = await fs.readFile(installedSdkPackageJsonPath, "utf-8");
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (areDependenciesEqual(sdkPkg.dependencies, installedPkg.dependencies) &&
|
|
126
|
-
areDependenciesEqual(sdkPkg.devDependencies, installedPkg.devDependencies) &&
|
|
127
|
-
areDependenciesEqual(sdkPkg.peerDependencies, installedPkg.peerDependencies)) {
|
|
128
|
-
packageJsonChanged = false;
|
|
129
|
-
}
|
|
245
|
+
packageJsonChanged =
|
|
246
|
+
sdkPackageJsonContent !== installedSdkPackageJsonContent;
|
|
130
247
|
}
|
|
131
248
|
if (packageJsonChanged) {
|
|
132
249
|
console.log("📦 package.json changed, performing full sync...");
|
|
@@ -198,20 +315,19 @@ export const debugSync = async (opts) => {
|
|
|
198
315
|
cwd: sdkDir,
|
|
199
316
|
});
|
|
200
317
|
let syncing = false;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (syncing || filePath.endsWith(".tgz")) {
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
if (expectingFileChanges && process.env.RWSDK_FORCE_FULL_SYNC) {
|
|
209
|
-
expectingFileChanges = false;
|
|
318
|
+
let pendingResync = false;
|
|
319
|
+
const triggerResync = async (reason) => {
|
|
320
|
+
if (syncing) {
|
|
321
|
+
pendingResync = true;
|
|
210
322
|
return;
|
|
211
323
|
}
|
|
212
324
|
syncing = true;
|
|
213
|
-
|
|
214
|
-
|
|
325
|
+
if (reason) {
|
|
326
|
+
console.log(`\nDetected change, re-syncing... (file: ${reason})`);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
console.log(`\nDetected change, re-syncing...`);
|
|
330
|
+
}
|
|
215
331
|
if (childProc && !childProc.killed) {
|
|
216
332
|
console.log("Stopping running process...");
|
|
217
333
|
childProc.kill();
|
|
@@ -220,7 +336,6 @@ export const debugSync = async (opts) => {
|
|
|
220
336
|
});
|
|
221
337
|
}
|
|
222
338
|
try {
|
|
223
|
-
watcher.unwatch(filesToWatch);
|
|
224
339
|
await performSync(sdkDir, targetDir);
|
|
225
340
|
runWatchedCommand();
|
|
226
341
|
}
|
|
@@ -230,8 +345,19 @@ export const debugSync = async (opts) => {
|
|
|
230
345
|
}
|
|
231
346
|
finally {
|
|
232
347
|
syncing = false;
|
|
233
|
-
watcher.add(filesToWatch);
|
|
234
348
|
}
|
|
349
|
+
if (pendingResync) {
|
|
350
|
+
pendingResync = false;
|
|
351
|
+
// Coalesce any rapid additional events into a single follow-up sync
|
|
352
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
353
|
+
return triggerResync();
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
watcher.on("all", async (_event, filePath) => {
|
|
357
|
+
if (filePath.endsWith(".tgz")) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
await triggerResync(filePath);
|
|
235
361
|
});
|
|
236
362
|
const cleanup = async () => {
|
|
237
363
|
console.log("\nCleaning up...");
|
|
@@ -16,13 +16,18 @@ export const runWorkerScript = async (relativeScriptPath) => {
|
|
|
16
16
|
console.error("Error: Script path is required");
|
|
17
17
|
console.log("\nUsage:");
|
|
18
18
|
console.log(" npm run worker:run <script-path>");
|
|
19
|
-
console.log("\
|
|
20
|
-
console.log("
|
|
19
|
+
console.log("\nOptions:");
|
|
20
|
+
console.log(" RWSDK_WRANGLER_CONFIG Environment variable for config path");
|
|
21
|
+
console.log("\nExamples:");
|
|
22
|
+
console.log(" npm run worker:run src/scripts/seed.ts");
|
|
23
|
+
console.log(" RWSDK_WRANGLER_CONFIG=custom.toml npm run worker:run src/scripts/seed.ts\n");
|
|
21
24
|
process.exit(1);
|
|
22
25
|
}
|
|
23
26
|
const scriptPath = resolve(process.cwd(), relativeScriptPath);
|
|
24
27
|
debug("Running worker script: %s", scriptPath);
|
|
25
|
-
const workerConfigPath =
|
|
28
|
+
const workerConfigPath = process.env.RWSDK_WRANGLER_CONFIG
|
|
29
|
+
? resolve(process.cwd(), process.env.RWSDK_WRANGLER_CONFIG)
|
|
30
|
+
: await findWranglerConfig(process.cwd());
|
|
26
31
|
debug("Using wrangler config: %s", workerConfigPath);
|
|
27
32
|
const workerConfig = unstable_readConfig({
|
|
28
33
|
config: workerConfigPath,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { readFile } from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
export async function hasOwnReactVitePlugin({ rootProjectDir, }) {
|
|
4
|
+
const packageJsonPath = path.join(rootProjectDir, "package.json");
|
|
5
|
+
try {
|
|
6
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8"));
|
|
7
|
+
return !!(packageJson.dependencies?.["@vitejs/plugin-react"] ||
|
|
8
|
+
packageJson.devDependencies?.["@vitejs/plugin-react"]);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
console.error("Error reading package.json:", error);
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -66,6 +66,9 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
66
66
|
};
|
|
67
67
|
},
|
|
68
68
|
async hotUpdate(ctx) {
|
|
69
|
+
if (ctx.file.includes(".wrangler")) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
69
72
|
if (hasErrored) {
|
|
70
73
|
const shortName = getShortName(ctx.file, ctx.server.config.root);
|
|
71
74
|
this.environment.logger.info(`${colors.cyan(`attempting to recover from error`)}: update to ${colors.dim(shortName)}`, {
|
|
@@ -77,6 +80,7 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
77
80
|
type: "full-reload",
|
|
78
81
|
path: "*",
|
|
79
82
|
});
|
|
83
|
+
log("hmr: Full reload after error");
|
|
80
84
|
return [];
|
|
81
85
|
}
|
|
82
86
|
const { clientFiles, serverFiles, viteEnvironment: { name: environment }, workerEntryPathname: entry, } = givenOptions;
|
|
@@ -84,6 +88,7 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
84
88
|
log(`Hot update: (env=${this.environment.name}) ${ctx.file}\nModule graph:\n\n${dumpFullModuleGraph(ctx.server, this.environment.name)}`);
|
|
85
89
|
}
|
|
86
90
|
if (!isJsFile(ctx.file) && !ctx.file.endsWith(".css")) {
|
|
91
|
+
log(`hmr: not a js file, skipping`);
|
|
87
92
|
return;
|
|
88
93
|
}
|
|
89
94
|
if (this.environment.name === "ssr") {
|
|
@@ -94,14 +99,17 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
94
99
|
server: ctx.server,
|
|
95
100
|
});
|
|
96
101
|
if (!isUseClientUpdate) {
|
|
102
|
+
log("hmr: not a use client update, short circuiting");
|
|
97
103
|
return [];
|
|
98
104
|
}
|
|
99
105
|
invalidateModule(ctx.server, "ssr", ctx.file);
|
|
100
106
|
invalidateModule(ctx.server, environment, VIRTUAL_SSR_PREFIX +
|
|
101
107
|
normalizeModulePath(ctx.file, givenOptions.rootDir));
|
|
108
|
+
log("hmr: invalidated ssr module");
|
|
102
109
|
return [];
|
|
103
110
|
}
|
|
104
111
|
if (!["client", environment].includes(this.environment.name)) {
|
|
112
|
+
log(`hmr: incorrect env, skipping (env=${this.environment.name}, worker env=${environment})`);
|
|
105
113
|
return [];
|
|
106
114
|
}
|
|
107
115
|
const hasClientDirective = await hasDirective(ctx.file, "use client");
|
|
@@ -165,8 +173,10 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
165
173
|
server: ctx.server,
|
|
166
174
|
});
|
|
167
175
|
if (!isUseClientUpdate && !ctx.file.endsWith(".css")) {
|
|
176
|
+
log("hmr: not a use client update and not css, short circuiting");
|
|
168
177
|
return [];
|
|
169
178
|
}
|
|
179
|
+
log("hmr: returning client modules for hmr");
|
|
170
180
|
return ctx.modules;
|
|
171
181
|
}
|
|
172
182
|
// The worker needs an update, and the hot check is for the worker environment
|
|
@@ -184,8 +194,12 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
184
194
|
if (m) {
|
|
185
195
|
invalidateModule(ctx.server, environment, m);
|
|
186
196
|
}
|
|
187
|
-
|
|
188
|
-
normalizeModulePath(ctx.file, givenOptions.rootDir)
|
|
197
|
+
let virtualSSRModuleId = VIRTUAL_SSR_PREFIX +
|
|
198
|
+
normalizeModulePath(ctx.file, givenOptions.rootDir);
|
|
199
|
+
if (ctx.file.endsWith(".css")) {
|
|
200
|
+
virtualSSRModuleId += ".js";
|
|
201
|
+
}
|
|
202
|
+
const virtualSSRModule = ctx.server.environments[environment].moduleGraph.idToModuleMap.get(virtualSSRModuleId);
|
|
189
203
|
if (virtualSSRModule) {
|
|
190
204
|
invalidateModule(ctx.server, environment, virtualSSRModule);
|
|
191
205
|
}
|
|
@@ -196,6 +210,7 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
196
210
|
file: ctx.file,
|
|
197
211
|
},
|
|
198
212
|
});
|
|
213
|
+
log("hmr: sent rsc update");
|
|
199
214
|
return [];
|
|
200
215
|
}
|
|
201
216
|
},
|
|
@@ -10,7 +10,6 @@ export declare const ENV_RESOLVERS: {
|
|
|
10
10
|
worker: enhancedResolve.ResolveFunction;
|
|
11
11
|
client: enhancedResolve.ResolveFunction;
|
|
12
12
|
};
|
|
13
|
-
export declare const
|
|
14
|
-
|
|
15
|
-
};
|
|
16
|
-
export declare const reactConditionsResolverPlugin: () => Plugin[];
|
|
13
|
+
export declare const reactConditionsResolverPlugin: ({ projectRootDir, }: {
|
|
14
|
+
projectRootDir: string;
|
|
15
|
+
}) => Plugin[];
|
|
@@ -3,6 +3,7 @@ import { ROOT_DIR } from "../lib/constants.mjs";
|
|
|
3
3
|
import enhancedResolve from "enhanced-resolve";
|
|
4
4
|
import { ensureAliasArray } from "./ensureAliasArray.mjs";
|
|
5
5
|
const log = debug("rwsdk:vite:react-conditions-resolver-plugin");
|
|
6
|
+
const REACT_PREFIXES = ["react", "react-dom", "react-server-dom-webpack"];
|
|
6
7
|
export const ENV_REACT_IMPORTS = {
|
|
7
8
|
worker: [
|
|
8
9
|
"react",
|
|
@@ -41,28 +42,41 @@ export const ENV_RESOLVERS = {
|
|
|
41
42
|
conditionNames: ["browser", "default"],
|
|
42
43
|
}),
|
|
43
44
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
function resolveReactImport(id, envName, projectRootDir, isReactImportKnown = false) {
|
|
46
|
+
if (!isReactImportKnown) {
|
|
47
|
+
const isReactImport = REACT_PREFIXES.some((prefix) => id === prefix || id.startsWith(`${prefix}/`));
|
|
48
|
+
if (!isReactImport) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
let resolved;
|
|
53
|
+
try {
|
|
54
|
+
resolved = ENV_RESOLVERS[envName](projectRootDir, id) || undefined;
|
|
55
|
+
process.env.VERBOSE &&
|
|
56
|
+
log("Successfully resolved %s to %s for env=%s from project root", id, resolved, envName);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
54
59
|
process.env.VERBOSE &&
|
|
55
|
-
log("
|
|
56
|
-
let resolved = false;
|
|
60
|
+
log("Failed to resolve %s for env=%s from project root, trying ROOT_DIR", id, envName);
|
|
57
61
|
try {
|
|
58
|
-
resolved = ENV_RESOLVERS[
|
|
62
|
+
resolved = ENV_RESOLVERS[envName](ROOT_DIR, id) || undefined;
|
|
59
63
|
process.env.VERBOSE &&
|
|
60
|
-
log("Successfully resolved %s to %s for env=%s",
|
|
64
|
+
log("Successfully resolved %s to %s for env=%s from rwsdk root", id, resolved, envName);
|
|
61
65
|
}
|
|
62
66
|
catch {
|
|
63
67
|
process.env.VERBOSE &&
|
|
64
|
-
log("Failed to resolve %s for env=%s",
|
|
68
|
+
log("Failed to resolve %s for env=%s", id, envName);
|
|
65
69
|
}
|
|
70
|
+
}
|
|
71
|
+
return resolved;
|
|
72
|
+
}
|
|
73
|
+
function resolveEnvImportMappings(env, projectRootDir) {
|
|
74
|
+
process.env.VERBOSE &&
|
|
75
|
+
log("Resolving environment import mappings for env=%s", env);
|
|
76
|
+
const mappings = new Map();
|
|
77
|
+
const reactImports = ENV_REACT_IMPORTS[env];
|
|
78
|
+
for (const importRequest of reactImports) {
|
|
79
|
+
const resolved = resolveReactImport(importRequest, env, projectRootDir, true);
|
|
66
80
|
if (resolved) {
|
|
67
81
|
mappings.set(importRequest, resolved);
|
|
68
82
|
log("Added mapping for %s -> %s in env=%s", importRequest, resolved, env);
|
|
@@ -71,39 +85,45 @@ function resolveEnvImportMappings(env) {
|
|
|
71
85
|
log("Environment import mappings complete for env=%s: %d mappings", env, mappings.size);
|
|
72
86
|
return mappings;
|
|
73
87
|
}
|
|
74
|
-
|
|
75
|
-
const mappings = ENV_IMPORT_MAPPINGS[envName];
|
|
76
|
-
if (!mappings) {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
return {
|
|
80
|
-
name: `rwsdk:react-conditions-resolver-esbuild-${envName}`,
|
|
81
|
-
setup(build) {
|
|
82
|
-
build.onResolve({ filter: /.*/ }, (args) => {
|
|
83
|
-
process.env.VERBOSE &&
|
|
84
|
-
log("ESBuild resolving %s for env=%s, args=%O", args.path, envName, args);
|
|
85
|
-
const resolved = mappings.get(args.path);
|
|
86
|
-
if (resolved && args.importer !== "") {
|
|
87
|
-
process.env.VERBOSE &&
|
|
88
|
-
log("ESBuild resolving %s -> %s for env=%s", args.path, resolved, envName);
|
|
89
|
-
if (args.path === "react-server-dom-webpack/client.edge") {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
path: resolved,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
process.env.VERBOSE &&
|
|
98
|
-
log("ESBuild no resolution found for %s for env=%s", args.path, envName);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
export const reactConditionsResolverPlugin = () => {
|
|
88
|
+
export const reactConditionsResolverPlugin = ({ projectRootDir, }) => {
|
|
105
89
|
log("Initializing react conditions resolver plugin");
|
|
106
90
|
let isBuild = false;
|
|
91
|
+
const ENV_IMPORT_MAPPINGS = Object.fromEntries(Object.keys(ENV_RESOLVERS).map((env) => [
|
|
92
|
+
env,
|
|
93
|
+
resolveEnvImportMappings(env, projectRootDir),
|
|
94
|
+
]));
|
|
95
|
+
function createEsbuildResolverPlugin(envName, mappings) {
|
|
96
|
+
if (!mappings) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
name: `rwsdk:react-conditions-resolver-esbuild-${envName}`,
|
|
101
|
+
setup(build) {
|
|
102
|
+
build.onResolve({ filter: /.*/ }, (args) => {
|
|
103
|
+
process.env.VERBOSE &&
|
|
104
|
+
log("ESBuild resolving %s for env=%s, args=%O", args.path, envName, args);
|
|
105
|
+
let resolved = mappings.get(args.path);
|
|
106
|
+
if (!resolved) {
|
|
107
|
+
resolved = resolveReactImport(args.path, envName, projectRootDir);
|
|
108
|
+
}
|
|
109
|
+
if (resolved && args.importer !== "") {
|
|
110
|
+
process.env.VERBOSE &&
|
|
111
|
+
log("ESBuild resolving %s -> %s for env=%s", args.path, resolved, envName);
|
|
112
|
+
if (args.path === "react-server-dom-webpack/client.edge") {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
path: resolved,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
process.env.VERBOSE &&
|
|
121
|
+
log("ESBuild no resolution found for %s for env=%s", args.path, envName);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
107
127
|
return [
|
|
108
128
|
{
|
|
109
129
|
name: "rwsdk:react-conditions-resolver:config",
|
|
@@ -125,7 +145,7 @@ export const reactConditionsResolverPlugin = () => {
|
|
|
125
145
|
config.environments[envName] = {};
|
|
126
146
|
}
|
|
127
147
|
const envConfig = config.environments[envName];
|
|
128
|
-
const esbuildPlugin = createEsbuildResolverPlugin(envName);
|
|
148
|
+
const esbuildPlugin = createEsbuildResolverPlugin(envName, mappings);
|
|
129
149
|
if (esbuildPlugin && mappings) {
|
|
130
150
|
envConfig.optimizeDeps ??= {};
|
|
131
151
|
envConfig.optimizeDeps.esbuildOptions ??= {};
|
|
@@ -166,7 +186,10 @@ export const reactConditionsResolverPlugin = () => {
|
|
|
166
186
|
log("No mappings found for environment: %s", envName);
|
|
167
187
|
return;
|
|
168
188
|
}
|
|
169
|
-
|
|
189
|
+
let resolved = mappings.get(id);
|
|
190
|
+
if (!resolved) {
|
|
191
|
+
resolved = resolveReactImport(id, envName, projectRootDir);
|
|
192
|
+
}
|
|
170
193
|
if (resolved) {
|
|
171
194
|
log("Resolved %s -> %s for env=%s", id, resolved, envName);
|
|
172
195
|
return resolved;
|
|
@@ -3,6 +3,7 @@ import { unstable_readConfig } from "wrangler";
|
|
|
3
3
|
import { cloudflare } from "@cloudflare/vite-plugin";
|
|
4
4
|
import { devServerConstantPlugin } from "./devServerConstant.mjs";
|
|
5
5
|
import { hasOwnCloudflareVitePlugin } from "./hasOwnCloudflareVitePlugin.mjs";
|
|
6
|
+
import { hasOwnReactVitePlugin } from "./hasOwnReactVitePlugin.mjs";
|
|
6
7
|
import reactPlugin from "@vitejs/plugin-react";
|
|
7
8
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
8
9
|
import { transformJsxScriptTagsPlugin } from "./transformJsxScriptTagsPlugin.mjs";
|
|
@@ -32,7 +33,10 @@ const determineWorkerEntryPathname = async (projectRootDir, workerConfigPath, op
|
|
|
32
33
|
};
|
|
33
34
|
export const redwoodPlugin = async (options = {}) => {
|
|
34
35
|
const projectRootDir = process.cwd();
|
|
35
|
-
const workerConfigPath = options.configPath ??
|
|
36
|
+
const workerConfigPath = options.configPath ??
|
|
37
|
+
(process.env.RWSDK_WRANGLER_CONFIG
|
|
38
|
+
? resolve(projectRootDir, process.env.RWSDK_WRANGLER_CONFIG)
|
|
39
|
+
: await findWranglerConfig(projectRootDir));
|
|
36
40
|
const workerEntryPathname = await determineWorkerEntryPathname(projectRootDir, workerConfigPath, options);
|
|
37
41
|
const clientEntryPathnames = (Array.isArray(options.entry?.client)
|
|
38
42
|
? options.entry.client
|
|
@@ -41,6 +45,8 @@ export const redwoodPlugin = async (options = {}) => {
|
|
|
41
45
|
const serverFiles = new Set();
|
|
42
46
|
const shouldIncludeCloudflarePlugin = options.includeCloudflarePlugin ??
|
|
43
47
|
!(await hasOwnCloudflareVitePlugin({ rootProjectDir: projectRootDir }));
|
|
48
|
+
const shouldIncludeReactPlugin = options.includeReactPlugin ??
|
|
49
|
+
!(await hasOwnReactVitePlugin({ rootProjectDir: projectRootDir }));
|
|
44
50
|
// context(justinvdm, 31 Mar 2025): We assume that if there is no .wrangler directory,
|
|
45
51
|
// then this is fresh install, and we run `npm run dev:init` here.
|
|
46
52
|
if (process.env.RWSDK_WORKER_RUN !== "1" &&
|
|
@@ -68,7 +74,7 @@ export const redwoodPlugin = async (options = {}) => {
|
|
|
68
74
|
serverFiles,
|
|
69
75
|
projectRootDir,
|
|
70
76
|
}),
|
|
71
|
-
reactConditionsResolverPlugin(),
|
|
77
|
+
reactConditionsResolverPlugin({ projectRootDir }),
|
|
72
78
|
tsconfigPaths({ root: projectRootDir }),
|
|
73
79
|
shouldIncludeCloudflarePlugin
|
|
74
80
|
? cloudflare({
|
|
@@ -83,7 +89,7 @@ export const redwoodPlugin = async (options = {}) => {
|
|
|
83
89
|
viteEnvironment: { name: "worker" },
|
|
84
90
|
workerEntryPathname,
|
|
85
91
|
}),
|
|
86
|
-
reactPlugin(),
|
|
92
|
+
shouldIncludeReactPlugin ? reactPlugin() : [],
|
|
87
93
|
directivesPlugin({
|
|
88
94
|
projectRootDir,
|
|
89
95
|
clientFiles,
|