rwsdk 1.3.1 → 1.3.3
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/__intermediate_builds/__vendor_client_barrel.dev-virtual.d.ts +2 -0
- package/dist/__intermediate_builds/__vendor_client_barrel.dev-virtual.js +5 -0
- package/dist/__intermediate_builds/__vendor_server_barrel.dev-virtual.d.ts +2 -0
- package/dist/__intermediate_builds/__vendor_server_barrel.dev-virtual.js +5 -0
- package/dist/lib/constants.mjs +8 -2
- package/dist/lib/e2e/testHarness.mjs +14 -0
- package/dist/vite/barrelPaths.d.mts +14 -0
- package/dist/vite/barrelPaths.mjs +16 -0
- package/dist/vite/configPlugin.mjs +14 -0
- package/dist/vite/directiveModulesDevPlugin.mjs +87 -26
- package/dist/vite/miniflareHMRPlugin.mjs +67 -0
- package/dist/vite/redwoodPlugin.mjs +1 -0
- package/dist/vite/ssrBridgePlugin.mjs +15 -1
- package/package.json +3 -3
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// This file is intentionally a placeholder. In dev, directiveModulesDevPlugin
|
|
2
|
+
// intercepts the `rwsdk/__vendor_client_barrel` specifier and serves generated
|
|
3
|
+
// content from in-memory temp barrels. This export exists only so the
|
|
4
|
+
// `optimizeDeps.include` entry has a resolvable fallback path.
|
|
5
|
+
export default {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// This file is intentionally a placeholder. In dev, directiveModulesDevPlugin
|
|
2
|
+
// intercepts the `rwsdk/__vendor_server_barrel` specifier and serves generated
|
|
3
|
+
// content from in-memory temp barrels. This export exists only so the
|
|
4
|
+
// `optimizeDeps.include` entry has a resolvable fallback path.
|
|
5
|
+
export default {};
|
package/dist/lib/constants.mjs
CHANGED
|
@@ -7,8 +7,14 @@ export const SRC_DIR = resolve(ROOT_DIR, "src");
|
|
|
7
7
|
export const DIST_DIR = resolve(ROOT_DIR, "dist");
|
|
8
8
|
export const VITE_DIR = resolve(ROOT_DIR, "src", "vite");
|
|
9
9
|
export const INTERMEDIATES_OUTPUT_DIR = resolve(DIST_DIR, "__intermediate_builds");
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
// Intentionally named `.dev-virtual.js`: these files are never written during
|
|
11
|
+
// the SDK build. In dev, directiveModulesDevPlugin intercepts the matching
|
|
12
|
+
// `rwsdk/__vendor_*_barrel` specifiers and serves generated content from
|
|
13
|
+
// in-memory temp barrels. The package.json exports point here only as a
|
|
14
|
+
// fallback marker/placeholder for cases where the dev plugin has not set temp
|
|
15
|
+
// barrel paths.
|
|
16
|
+
export const VENDOR_CLIENT_BARREL_PATH = resolve(INTERMEDIATES_OUTPUT_DIR, "__vendor_client_barrel.dev-virtual.js");
|
|
17
|
+
export const VENDOR_SERVER_BARREL_PATH = resolve(INTERMEDIATES_OUTPUT_DIR, "__vendor_server_barrel.dev-virtual.js");
|
|
12
18
|
export const VENDOR_CLIENT_BARREL_EXPORT_PATH = "rwsdk/__vendor_client_barrel";
|
|
13
19
|
export const VENDOR_SERVER_BARREL_EXPORT_PATH = "rwsdk/__vendor_server_barrel";
|
|
14
20
|
export const RW_STATE_EXPORT_PATH = "rwsdk/__state";
|
|
@@ -196,6 +196,20 @@ export function createDevServer() {
|
|
|
196
196
|
if (SKIP_DEV_SERVER_TESTS) {
|
|
197
197
|
throw new Error("Dev server tests are skipped via RWSDK_SKIP_DEV=1");
|
|
198
198
|
}
|
|
199
|
+
// Reuse the global dev server when it is for the same project directory.
|
|
200
|
+
// This avoids spawning multiple Vite/Cloudflare dev servers in the same
|
|
201
|
+
// project (which compete for the same inspector port, etc.).
|
|
202
|
+
if (globalDevInstance && globalDevInstance.projectDir === projectDir) {
|
|
203
|
+
instance = globalDevInstance;
|
|
204
|
+
return instance;
|
|
205
|
+
}
|
|
206
|
+
if (globalDevInstancePromise) {
|
|
207
|
+
const globalInstance = await globalDevInstancePromise;
|
|
208
|
+
if (globalInstance && globalInstance.projectDir === projectDir) {
|
|
209
|
+
instance = globalInstance;
|
|
210
|
+
return instance;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
199
213
|
const devResult = await pollValue(() => runDevServer(packageManager, projectDir), {
|
|
200
214
|
timeout: DEV_SERVER_TIMEOUT,
|
|
201
215
|
minTries: DEV_SERVER_MIN_TRIES,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporary paths for the generated vendor barrels in development.
|
|
3
|
+
*
|
|
4
|
+
* In dev, `directiveModulesDevPlugin` generates these paths in a temp directory
|
|
5
|
+
* (outside of node_modules) and provides barrel content to Vite's optimizer
|
|
6
|
+
* in-memory. The lookup plugins read these paths so the lookup map imports the
|
|
7
|
+
* same temp files the optimizer is configured to pre-bundle.
|
|
8
|
+
*/
|
|
9
|
+
export declare const setVendorBarrelPaths: ({ client, server, }: {
|
|
10
|
+
client: string;
|
|
11
|
+
server: string;
|
|
12
|
+
}) => void;
|
|
13
|
+
export declare const getVendorClientBarrelPath: () => string | undefined;
|
|
14
|
+
export declare const getVendorServerBarrelPath: () => string | undefined;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporary paths for the generated vendor barrels in development.
|
|
3
|
+
*
|
|
4
|
+
* In dev, `directiveModulesDevPlugin` generates these paths in a temp directory
|
|
5
|
+
* (outside of node_modules) and provides barrel content to Vite's optimizer
|
|
6
|
+
* in-memory. The lookup plugins read these paths so the lookup map imports the
|
|
7
|
+
* same temp files the optimizer is configured to pre-bundle.
|
|
8
|
+
*/
|
|
9
|
+
let vendorClientBarrelPath;
|
|
10
|
+
let vendorServerBarrelPath;
|
|
11
|
+
export const setVendorBarrelPaths = ({ client, server, }) => {
|
|
12
|
+
vendorClientBarrelPath = client;
|
|
13
|
+
vendorServerBarrelPath = server;
|
|
14
|
+
};
|
|
15
|
+
export const getVendorClientBarrelPath = () => vendorClientBarrelPath;
|
|
16
|
+
export const getVendorServerBarrelPath = () => vendorServerBarrelPath;
|
|
@@ -6,6 +6,7 @@ import { externalModules } from "./constants.mjs";
|
|
|
6
6
|
import { ssrBridgeWrapPlugin } from "./ssrBridgeWrapPlugin.mjs";
|
|
7
7
|
export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clientFiles, serverFiles, clientEntryPoints, esbuildOptions, }) => ({
|
|
8
8
|
name: "rwsdk:config",
|
|
9
|
+
enforce: "pre",
|
|
9
10
|
config: async (config, { command }) => {
|
|
10
11
|
const mode = process.env.NODE_ENV;
|
|
11
12
|
// context(justinvdm, 2026-05-06): Only set a sourcemap default if the user
|
|
@@ -101,6 +102,7 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
|
|
|
101
102
|
"rwsdk/realtime/client",
|
|
102
103
|
"rwsdk/router",
|
|
103
104
|
"rwsdk/turnstile",
|
|
105
|
+
"rwsdk/use-synced-state/client",
|
|
104
106
|
],
|
|
105
107
|
entries: [],
|
|
106
108
|
esbuildOptions: {
|
|
@@ -139,6 +141,7 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
|
|
|
139
141
|
"rwsdk/worker",
|
|
140
142
|
"rwsdk/realtime/durableObject",
|
|
141
143
|
"rwsdk/realtime/worker",
|
|
144
|
+
"rwsdk/use-synced-state/client",
|
|
142
145
|
],
|
|
143
146
|
esbuildOptions: {
|
|
144
147
|
jsx: "automatic",
|
|
@@ -200,4 +203,15 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
|
|
|
200
203
|
};
|
|
201
204
|
return baseConfig;
|
|
202
205
|
},
|
|
206
|
+
configResolved(config) {
|
|
207
|
+
// context(chrisvdm, 2025-09-20): Vitest and some Vite defaults set
|
|
208
|
+
// `resolve.external` to Node built-ins for non-client environments. The
|
|
209
|
+
// Cloudflare Vite plugin rejects any `resolve.external` value on Worker
|
|
210
|
+
// environments. We clear it here after Vite has resolved the environment
|
|
211
|
+
// configs but before the Cloudflare plugin validates them. `noExternal: true`
|
|
212
|
+
// in the worker config ensures builtins are bundled rather than externalized.
|
|
213
|
+
if (config.environments.worker?.resolve) {
|
|
214
|
+
config.environments.worker.resolve.external = [];
|
|
215
|
+
}
|
|
216
|
+
},
|
|
203
217
|
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { mkdirSync, mkdtempSync, realpathSync, writeFileSync } from "node:fs";
|
|
2
2
|
import os from "os";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import {
|
|
4
|
+
import { VENDOR_CLIENT_BARREL_PATH as SDK_VENDOR_CLIENT_BARREL_PATH, VENDOR_SERVER_BARREL_PATH as SDK_VENDOR_SERVER_BARREL_PATH, VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, } from "../lib/constants.mjs";
|
|
5
5
|
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { setVendorBarrelPaths } from "./barrelPaths.mjs";
|
|
7
|
+
import { runDirectivesScan, } from "./runDirectivesScan.mjs";
|
|
7
8
|
export const generateVendorBarrelContent = (files, projectRootDir) => {
|
|
8
9
|
const imports = [...files]
|
|
9
10
|
.filter((file) => file.includes("node_modules"))
|
|
@@ -31,13 +32,32 @@ export const generateAppBarrelContent = (files, projectRootDir) => {
|
|
|
31
32
|
.join("\n");
|
|
32
33
|
};
|
|
33
34
|
export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRootDir, workerEntryPathname, esbuildOptions, }) => {
|
|
34
|
-
const { promise: scanPromise, resolve: resolveScanPromise } = Promise.withResolvers();
|
|
35
|
-
const tempDir = mkdtempSync(path.join(os.tmpdir(), "rwsdk-"));
|
|
35
|
+
const { promise: scanPromise, resolve: resolveScanPromise, reject: rejectScanPromise, } = Promise.withResolvers();
|
|
36
|
+
const tempDir = mkdtempSync(path.join(realpathSync(os.tmpdir()), "rwsdk-"));
|
|
36
37
|
const APP_CLIENT_BARREL_PATH = path.join(tempDir, "app-client-barrel.js");
|
|
37
38
|
const APP_SERVER_BARREL_PATH = path.join(tempDir, "app-server-barrel.js");
|
|
39
|
+
const VENDOR_CLIENT_BARREL_PATH = path.join(tempDir, "vendor-client-barrel.js");
|
|
40
|
+
const VENDOR_SERVER_BARREL_PATH = path.join(tempDir, "vendor-server-barrel.js");
|
|
41
|
+
setVendorBarrelPaths({
|
|
42
|
+
client: VENDOR_CLIENT_BARREL_PATH,
|
|
43
|
+
server: VENDOR_SERVER_BARREL_PATH,
|
|
44
|
+
});
|
|
38
45
|
return {
|
|
39
46
|
name: "rwsdk:directive-modules-dev",
|
|
40
47
|
enforce: "pre",
|
|
48
|
+
load(id) {
|
|
49
|
+
const isClientBarrel = id === VENDOR_CLIENT_BARREL_EXPORT_PATH ||
|
|
50
|
+
id === SDK_VENDOR_CLIENT_BARREL_PATH;
|
|
51
|
+
const isServerBarrel = id === VENDOR_SERVER_BARREL_EXPORT_PATH ||
|
|
52
|
+
id === SDK_VENDOR_SERVER_BARREL_PATH;
|
|
53
|
+
if (isClientBarrel) {
|
|
54
|
+
return generateVendorBarrelContent(clientFiles, projectRootDir);
|
|
55
|
+
}
|
|
56
|
+
if (isServerBarrel) {
|
|
57
|
+
return generateVendorBarrelContent(serverFiles, projectRootDir);
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
},
|
|
41
61
|
configureServer(server) {
|
|
42
62
|
// context(justinvdm, 19 Nov 2025): We must run this hook before the
|
|
43
63
|
// Cloudflare plugin's `configureServer` hook. The Cloudflare plugin makes
|
|
@@ -57,19 +77,14 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
|
|
|
57
77
|
serverFiles,
|
|
58
78
|
entries: [workerEntryPathname],
|
|
59
79
|
esbuildOptions,
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// because app barrels require special handling to prevent Vite from
|
|
65
|
-
// marking application code as `external: true`. Vendor barrels do not
|
|
66
|
-
// have this requirement and a simpler, direct-write approach is more
|
|
67
|
-
// stable.
|
|
68
|
-
const vendorClientBarrelContent = generateVendorBarrelContent(clientFiles, projectRootDir);
|
|
69
|
-
writeFileSync(VENDOR_CLIENT_BARREL_PATH, vendorClientBarrelContent);
|
|
70
|
-
const vendorServerBarrelContent = generateVendorBarrelContent(serverFiles, projectRootDir);
|
|
71
|
-
writeFileSync(VENDOR_SERVER_BARREL_PATH, vendorServerBarrelContent);
|
|
80
|
+
})
|
|
81
|
+
.then(() => {
|
|
82
|
+
writeFileSync(VENDOR_CLIENT_BARREL_PATH, generateVendorBarrelContent(clientFiles, projectRootDir));
|
|
83
|
+
writeFileSync(VENDOR_SERVER_BARREL_PATH, generateVendorBarrelContent(serverFiles, projectRootDir));
|
|
72
84
|
resolveScanPromise();
|
|
85
|
+
})
|
|
86
|
+
.catch((error) => {
|
|
87
|
+
rejectScanPromise(error);
|
|
73
88
|
});
|
|
74
89
|
server.middlewares.use(async (_req, _res, next) => {
|
|
75
90
|
await scanPromise;
|
|
@@ -78,6 +93,7 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
|
|
|
78
93
|
},
|
|
79
94
|
configResolved(config) {
|
|
80
95
|
if (config.command !== "serve") {
|
|
96
|
+
resolveScanPromise();
|
|
81
97
|
return;
|
|
82
98
|
}
|
|
83
99
|
mkdirSync(path.dirname(APP_CLIENT_BARREL_PATH), { recursive: true });
|
|
@@ -91,8 +107,9 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
|
|
|
91
107
|
for (const [envName, env] of Object.entries(config.environments || {})) {
|
|
92
108
|
env.optimizeDeps ??= {};
|
|
93
109
|
env.optimizeDeps.include ??= [];
|
|
94
|
-
const entries = (env.optimizeDeps.entries = castArray(env.optimizeDeps.entries ?? []));
|
|
95
110
|
env.optimizeDeps.include.push(VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH);
|
|
111
|
+
const entries = (env.optimizeDeps.entries = castArray(env.optimizeDeps.entries ?? []));
|
|
112
|
+
entries.push(VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH);
|
|
96
113
|
if (envName === "client" || envName === "ssr") {
|
|
97
114
|
entries.push(APP_CLIENT_BARREL_PATH);
|
|
98
115
|
}
|
|
@@ -108,17 +125,43 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
|
|
|
108
125
|
APP_CLIENT_BARREL_PATH,
|
|
109
126
|
APP_SERVER_BARREL_PATH,
|
|
110
127
|
];
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
128
|
+
const vendorBarrelPaths = [
|
|
129
|
+
VENDOR_CLIENT_BARREL_PATH,
|
|
130
|
+
VENDOR_SERVER_BARREL_PATH,
|
|
131
|
+
];
|
|
132
|
+
const barrelPaths = [...appBarrelPaths, ...vendorBarrelPaths];
|
|
133
|
+
const escapeRegExp = (s) => s.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
134
|
+
const barrelFilter = new RegExp(`(${barrelPaths.map(escapeRegExp).join("|")})$`);
|
|
114
135
|
build.onResolve({ filter: /.*/ }, async (args) => {
|
|
115
136
|
// Block all resolutions until the scan is complete.
|
|
116
137
|
await scanPromise;
|
|
117
|
-
// Handle
|
|
118
|
-
|
|
138
|
+
// Handle stable vendor barrel specifiers by redirecting them to
|
|
139
|
+
// the in-memory temp barrel files. This lets Vite rewrite the
|
|
140
|
+
// specifier to its optimized dependency bundle while still serving
|
|
141
|
+
// our generated content.
|
|
142
|
+
const isClientBarrelPath = args.path === VENDOR_CLIENT_BARREL_EXPORT_PATH ||
|
|
143
|
+
args.path === SDK_VENDOR_CLIENT_BARREL_PATH ||
|
|
144
|
+
args.path.endsWith("/__vendor_client_barrel.dev-virtual.js");
|
|
145
|
+
const isServerBarrelPath = args.path === VENDOR_SERVER_BARREL_EXPORT_PATH ||
|
|
146
|
+
args.path === SDK_VENDOR_SERVER_BARREL_PATH ||
|
|
147
|
+
args.path.endsWith("/__vendor_server_barrel.dev-virtual.js");
|
|
148
|
+
if (isClientBarrelPath) {
|
|
149
|
+
return {
|
|
150
|
+
path: VENDOR_CLIENT_BARREL_PATH,
|
|
151
|
+
namespace: "rwsdk-barrel-ns",
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (isServerBarrelPath) {
|
|
155
|
+
return {
|
|
156
|
+
path: VENDOR_SERVER_BARREL_PATH,
|
|
157
|
+
namespace: "rwsdk-barrel-ns",
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// Handle barrel files (app + vendor)
|
|
161
|
+
if (barrelFilter.test(args.path)) {
|
|
119
162
|
return {
|
|
120
163
|
path: args.path,
|
|
121
|
-
namespace: "rwsdk-
|
|
164
|
+
namespace: "rwsdk-barrel-ns",
|
|
122
165
|
};
|
|
123
166
|
}
|
|
124
167
|
// context(justinvdm, 11 Sep 2025): Prevent Vite from
|
|
@@ -136,8 +179,26 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
|
|
|
136
179
|
};
|
|
137
180
|
}
|
|
138
181
|
});
|
|
139
|
-
build.onLoad({ filter:
|
|
140
|
-
|
|
182
|
+
build.onLoad({ filter: /__vendor_(client|server)_barrel\.dev-virtual\.js$/ }, async (args) => {
|
|
183
|
+
await scanPromise;
|
|
184
|
+
const isServerBarrel = args.path.includes("server-barrel");
|
|
185
|
+
const files = isServerBarrel ? serverFiles : clientFiles;
|
|
186
|
+
return {
|
|
187
|
+
contents: generateVendorBarrelContent(files, projectRootDir),
|
|
188
|
+
loader: "js",
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
build.onLoad({ filter: /.*/, namespace: "rwsdk-barrel-ns" }, (args) => {
|
|
192
|
+
const isServerBarrel = args.path.includes("server-barrel");
|
|
193
|
+
const isVendorBarrel = args.path.includes("vendor");
|
|
194
|
+
if (isVendorBarrel) {
|
|
195
|
+
const files = isServerBarrel ? serverFiles : clientFiles;
|
|
196
|
+
const content = generateVendorBarrelContent(files, projectRootDir);
|
|
197
|
+
return {
|
|
198
|
+
contents: content,
|
|
199
|
+
loader: "js",
|
|
200
|
+
};
|
|
201
|
+
}
|
|
141
202
|
const files = isServerBarrel ? serverFiles : clientFiles;
|
|
142
203
|
const content = generateAppBarrelContent(files, projectRootDir);
|
|
143
204
|
return {
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import debug from "debug";
|
|
2
|
+
import { writeFileSync } from "node:fs";
|
|
2
3
|
import { readFile } from "node:fs/promises";
|
|
3
4
|
import { resolve } from "node:path";
|
|
4
5
|
import colors from "picocolors";
|
|
6
|
+
import { VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, } from "../lib/constants.mjs";
|
|
5
7
|
import { getShortName } from "../lib/getShortName.mjs";
|
|
6
8
|
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
9
|
+
import { getVendorClientBarrelPath, getVendorServerBarrelPath, } from "./barrelPaths.mjs";
|
|
10
|
+
import { generateVendorBarrelContent } from "./directiveModulesDevPlugin.mjs";
|
|
7
11
|
import { hasDirective as sourceHasDirective } from "./hasDirective.mjs";
|
|
8
12
|
import { invalidateModule } from "./invalidateModule.mjs";
|
|
9
13
|
import { isJsFile } from "./isJsFile.mjs";
|
|
14
|
+
import { runDirectivesScan } from "./runDirectivesScan.mjs";
|
|
10
15
|
import { VIRTUAL_SSR_PREFIX } from "./ssrVirtualModule.mjs";
|
|
11
16
|
const log = debug("rwsdk:vite:hmr-plugin");
|
|
12
17
|
let hasErrored = false;
|
|
@@ -148,6 +153,68 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
148
153
|
// The worker needs an update, and the hot check is for the worker environment
|
|
149
154
|
// => Notify for custom RSC-based HMR update, then short circuit HMR
|
|
150
155
|
if (isWorkerUpdate && this.environment.name === environment) {
|
|
156
|
+
// context(chrisvdm, 22 Jun 2026): When a worker file changes it may have imported
|
|
157
|
+
// a new dependency (or transitive dependency) that contains a directive.
|
|
158
|
+
// The directive scan only runs once at startup, so run a targeted sub-scan
|
|
159
|
+
// from the changed file to discover any new directive files and update the
|
|
160
|
+
// vendor barrels / lookup maps accordingly.
|
|
161
|
+
const clientFilesBefore = clientFiles.size;
|
|
162
|
+
const serverFilesBefore = serverFiles.size;
|
|
163
|
+
// context(chrisvdm, 22 Jun 2026): A full directive scan is expensive and
|
|
164
|
+
// awaiting it here can noticeably delay the HMR reload/refresh while the
|
|
165
|
+
// scan runs. However, this only happens when a changed worker file imports
|
|
166
|
+
// a dependency that was not seen in the initial scan (or a previous
|
|
167
|
+
// sub-scan). For files that were already part of the discovered directive
|
|
168
|
+
// graph, this branch is skipped. We are aware that blocking HMR for a full
|
|
169
|
+
// scan is not ideal, and we will monitor how it performs in practice. If it
|
|
170
|
+
// becomes a bottleneck, we should look into caching scan results and/or
|
|
171
|
+
// making the sub-scan incremental so we only pay the cost once per new
|
|
172
|
+
// dependency rather than on every unrelated edit.
|
|
173
|
+
await runDirectivesScan({
|
|
174
|
+
rootConfig: ctx.server.config,
|
|
175
|
+
environments: ctx.server.environments,
|
|
176
|
+
clientFiles,
|
|
177
|
+
serverFiles,
|
|
178
|
+
entries: [ctx.file],
|
|
179
|
+
esbuildOptions: {},
|
|
180
|
+
});
|
|
181
|
+
const clientFilesAfter = clientFiles.size;
|
|
182
|
+
const serverFilesAfter = serverFiles.size;
|
|
183
|
+
if (clientFilesAfter !== clientFilesBefore ||
|
|
184
|
+
serverFilesAfter !== serverFilesBefore) {
|
|
185
|
+
const clientBarrelPath = getVendorClientBarrelPath();
|
|
186
|
+
const serverBarrelPath = getVendorServerBarrelPath();
|
|
187
|
+
if (clientBarrelPath) {
|
|
188
|
+
writeFileSync(clientBarrelPath, generateVendorBarrelContent(clientFiles, givenOptions.rootDir));
|
|
189
|
+
}
|
|
190
|
+
if (serverBarrelPath) {
|
|
191
|
+
writeFileSync(serverBarrelPath, generateVendorBarrelContent(serverFiles, givenOptions.rootDir));
|
|
192
|
+
}
|
|
193
|
+
for (const envName of ["client", "ssr", environment]) {
|
|
194
|
+
if (clientBarrelPath) {
|
|
195
|
+
invalidateModule(ctx.server, envName, clientBarrelPath);
|
|
196
|
+
}
|
|
197
|
+
if (serverBarrelPath) {
|
|
198
|
+
invalidateModule(ctx.server, envName, serverBarrelPath);
|
|
199
|
+
}
|
|
200
|
+
invalidateModule(ctx.server, envName, VENDOR_CLIENT_BARREL_EXPORT_PATH);
|
|
201
|
+
invalidateModule(ctx.server, envName, VENDOR_SERVER_BARREL_EXPORT_PATH);
|
|
202
|
+
}
|
|
203
|
+
if (clientFilesAfter !== clientFilesBefore) {
|
|
204
|
+
for (const envName of ["client", "ssr", environment]) {
|
|
205
|
+
invalidateModule(ctx.server, envName, "virtual:use-client-lookup.js");
|
|
206
|
+
}
|
|
207
|
+
invalidateModule(ctx.server, environment, VIRTUAL_SSR_PREFIX + "/@id/virtual:use-client-lookup.js");
|
|
208
|
+
invalidateModule(ctx.server, environment, VIRTUAL_SSR_PREFIX + "virtual:use-client-lookup.js");
|
|
209
|
+
}
|
|
210
|
+
if (serverFilesAfter !== serverFilesBefore) {
|
|
211
|
+
for (const envName of ["client", "ssr", environment]) {
|
|
212
|
+
invalidateModule(ctx.server, envName, "virtual:use-server-lookup.js");
|
|
213
|
+
}
|
|
214
|
+
invalidateModule(ctx.server, environment, VIRTUAL_SSR_PREFIX + "/@id/virtual:use-server-lookup.js");
|
|
215
|
+
invalidateModule(ctx.server, environment, VIRTUAL_SSR_PREFIX + "virtual:use-server-lookup.js");
|
|
216
|
+
}
|
|
217
|
+
}
|
|
151
218
|
invalidateModule(ctx.server, environment, ctx.file);
|
|
152
219
|
const shortName = getShortName(ctx.file, ctx.server.config.root);
|
|
153
220
|
this.environment.logger.info(`${colors.green(`worker update`)} ${colors.dim(shortName)}`, {
|
|
@@ -117,6 +117,7 @@ export const redwoodPlugin = async (options = {}) => {
|
|
|
117
117
|
? cloudflare({
|
|
118
118
|
viteEnvironment: { name: "worker" },
|
|
119
119
|
configPath: workerConfigPath,
|
|
120
|
+
inspectorPort: process.env.RWSDK_WORKER_RUN === "1" ? false : undefined,
|
|
120
121
|
})
|
|
121
122
|
: [],
|
|
122
123
|
miniflareHMRPlugin({
|
|
@@ -144,8 +144,11 @@ export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
|
|
|
144
144
|
}
|
|
145
145
|
},
|
|
146
146
|
async load(id) {
|
|
147
|
+
if (this.environment.name !== "worker") {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
147
150
|
const virtualSsrId = normalizeVirtualSsrModuleId(id);
|
|
148
|
-
if (virtualSsrId
|
|
151
|
+
if (virtualSsrId) {
|
|
149
152
|
const realId = virtualSsrId.slice(VIRTUAL_SSR_PREFIX.length);
|
|
150
153
|
let idForFetch = realId.endsWith(".css.js")
|
|
151
154
|
? realId.slice(0, -3)
|
|
@@ -209,6 +212,17 @@ export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
|
|
|
209
212
|
s.overwrite(site.start, site.end, replacement);
|
|
210
213
|
continue;
|
|
211
214
|
}
|
|
215
|
+
// context(chrisvdm, 24 Jun 2026): JSON and ?raw imports should not
|
|
216
|
+
// be pulled into the SSR subgraph. They are static assets that Vite
|
|
217
|
+
// (and the Cloudflare Vite plugin) can handle directly in the worker
|
|
218
|
+
// environment. Keeping them out of the SSR environment avoids Vite's
|
|
219
|
+
// SSR-only JSON helpers and the ?raw access-denial check.
|
|
220
|
+
if (normalized.endsWith(".json") ||
|
|
221
|
+
normalized.includes("?raw")) {
|
|
222
|
+
const replacement = `import("${normalized}")`;
|
|
223
|
+
s.overwrite(site.start, site.end, replacement);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
212
226
|
// context(justinvdm, 11 Aug 2025):
|
|
213
227
|
// - We replace __vite_ssr_import__ and __vite_ssr_dynamic_import__
|
|
214
228
|
// with import() calls so that the module graph can be built
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rwsdk",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -58,10 +58,10 @@
|
|
|
58
58
|
"default": "./dist/runtime/ssrBridge.js"
|
|
59
59
|
},
|
|
60
60
|
"./__vendor_client_barrel": {
|
|
61
|
-
"default": "./dist/__intermediate_builds/
|
|
61
|
+
"default": "./dist/__intermediate_builds/__vendor_client_barrel.dev-virtual.js"
|
|
62
62
|
},
|
|
63
63
|
"./__vendor_server_barrel": {
|
|
64
|
-
"default": "./dist/__intermediate_builds/
|
|
64
|
+
"default": "./dist/__intermediate_builds/__vendor_server_barrel.dev-virtual.js"
|
|
65
65
|
},
|
|
66
66
|
"./router": {
|
|
67
67
|
"types": "./dist/runtime/entries/router.d.ts",
|