rwsdk 1.4.1 → 1.5.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 (34) hide show
  1. package/dist/lib/e2e/environment.d.mts +1 -1
  2. package/dist/lib/e2e/environment.mjs +28 -1
  3. package/dist/lib/e2e/tarball.d.mts +2 -1
  4. package/dist/lib/e2e/tarball.mjs +2 -2
  5. package/dist/lib/e2e/testHarness.d.mts +5 -0
  6. package/dist/lib/e2e/testHarness.mjs +7 -1
  7. package/dist/lib/smokeTests/environment.mjs +1 -0
  8. package/dist/lib/smokeTests/types.d.mts +1 -0
  9. package/dist/runtime/render/assembleDocument.js +1 -1
  10. package/dist/runtime/render/renderDocumentHtmlStream.js +1 -1
  11. package/dist/runtime/render/stylesheets.js +22 -0
  12. package/dist/scripts/smoke-test.mjs +8 -0
  13. package/dist/vite/addOptimizeDepsPlugin.d.mts +10 -0
  14. package/dist/vite/addOptimizeDepsPlugin.mjs +6 -0
  15. package/dist/vite/buildApp.mjs +54 -15
  16. package/dist/vite/configPlugin.mjs +27 -20
  17. package/dist/vite/createDirectiveLookupPlugin.mjs +11 -15
  18. package/dist/vite/directiveModulesDevPlugin.mjs +86 -103
  19. package/dist/vite/directivesFilteringPlugin.mjs +55 -14
  20. package/dist/vite/directivesPlugin.mjs +44 -87
  21. package/dist/vite/knownDepsResolverPlugin.mjs +29 -36
  22. package/dist/vite/linkerPlugin.mjs +1 -1
  23. package/dist/vite/prismaPlugin.mjs +7 -10
  24. package/dist/vite/redwoodPlugin.mjs +5 -4
  25. package/dist/vite/runDirectivesScan.mjs +1 -1
  26. package/dist/vite/ssrBridgePlugin.mjs +11 -21
  27. package/dist/vite/statePlugin.mjs +8 -15
  28. package/dist/vite/transformJsxScriptTagsPlugin.mjs +3 -3
  29. package/dist/vite/viteCompat.d.mts +5 -0
  30. package/dist/vite/viteCompat.mjs +378 -0
  31. package/dist/vite/viteCompat.test.d.mts +1 -0
  32. package/dist/vite/viteCompat.test.mjs +72 -0
  33. package/dist/vite/vitePreamblePlugin.d.mts +2 -153
  34. package/package.json +8 -7
@@ -5,7 +5,7 @@ export declare function getDirectoryHash(directory: string): Promise<string>;
5
5
  /**
6
6
  * Copy project to a temporary directory with a unique name
7
7
  */
8
- export declare function copyProjectToTempDir(projectDir: string, resourceUniqueKey: string, packageManager?: PackageManager, monorepoRoot?: string, installDependenciesRetries?: number): Promise<{
8
+ export declare function copyProjectToTempDir(projectDir: string, resourceUniqueKey: string, packageManager?: PackageManager, monorepoRoot?: string, installDependenciesRetries?: number, viteVersion?: number): Promise<{
9
9
  tempDir: tmp.DirectoryResult;
10
10
  targetDir: string;
11
11
  workerName: string;
@@ -136,7 +136,7 @@ const setTarballDependency = async (targetDir, tarballName) => {
136
136
  /**
137
137
  * Copy project to a temporary directory with a unique name
138
138
  */
139
- export async function copyProjectToTempDir(projectDir, resourceUniqueKey, packageManager, monorepoRoot, installDependenciesRetries) {
139
+ export async function copyProjectToTempDir(projectDir, resourceUniqueKey, packageManager, monorepoRoot, installDependenciesRetries, viteVersion) {
140
140
  const { tarballPath, cleanupTarball } = await createSdkTarball();
141
141
  try {
142
142
  log("Creating temporary directory for project");
@@ -249,6 +249,33 @@ export async function copyProjectToTempDir(projectDir, resourceUniqueKey, packag
249
249
  log("Created .yarnrc with cache-folder for yarn-classic");
250
250
  }
251
251
  await setTarballDependency(targetDir, tarballFilename);
252
+ if (viteVersion === 7) {
253
+ log("Patching package.json for Vite 7 compatibility");
254
+ const pkgJsonPath = join(targetDir, "package.json");
255
+ const pkgJson = JSON.parse(await fs.promises.readFile(pkgJsonPath, "utf-8"));
256
+ pkgJson.devDependencies ??= {};
257
+ pkgJson.devDependencies.vite = "~7.3.5";
258
+ pkgJson.devDependencies["@vitejs/plugin-react"] = "~5.1.4";
259
+ await fs.promises.writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
260
+ const viteConfigExtensions = [".mts", ".ts", ".js", ".mjs", ".cjs"];
261
+ let viteConfigPath;
262
+ for (const ext of viteConfigExtensions) {
263
+ const candidate = join(targetDir, `vite.config${ext}`);
264
+ if (await pathExists(candidate)) {
265
+ viteConfigPath = candidate;
266
+ break;
267
+ }
268
+ }
269
+ if (viteConfigPath) {
270
+ log("Patching %s to include @vitejs/plugin-react", basename(viteConfigPath));
271
+ let viteConfig = await fs.promises.readFile(viteConfigPath, "utf-8");
272
+ if (!viteConfig.includes("@vitejs/plugin-react")) {
273
+ viteConfig = `import react from "@vitejs/plugin-react";\n${viteConfig}`;
274
+ viteConfig = viteConfig.replace(/plugins:\s*\[/, "plugins: [\n react(),");
275
+ await fs.promises.writeFile(viteConfigPath, viteConfig);
276
+ }
277
+ }
278
+ }
252
279
  // Install dependencies in the target directory
253
280
  const installDir = monorepoRoot ? tempCopyRoot : targetDir;
254
281
  await retry(() => installDependencies(installDir, packageManager, projectDir, monorepoRoot), {
@@ -2,6 +2,7 @@ interface SetupTarballOptions {
2
2
  projectDir: string;
3
3
  monorepoRoot?: string;
4
4
  packageManager?: "pnpm" | "npm" | "yarn" | "yarn-classic";
5
+ viteVersion?: number;
5
6
  }
6
7
  interface TarballEnvironment {
7
8
  targetDir: string;
@@ -10,5 +11,5 @@ interface TarballEnvironment {
10
11
  /**
11
12
  * Creates a tarball-based test environment similar to the release script approach
12
13
  */
13
- export declare function setupTarballEnvironment({ projectDir, monorepoRoot, packageManager, }: SetupTarballOptions): Promise<TarballEnvironment>;
14
+ export declare function setupTarballEnvironment({ projectDir, monorepoRoot, packageManager, viteVersion, }: SetupTarballOptions): Promise<TarballEnvironment>;
14
15
  export {};
@@ -65,7 +65,7 @@ async function copyWranglerCache(targetDir, sdkRoot) {
65
65
  /**
66
66
  * Creates a tarball-based test environment similar to the release script approach
67
67
  */
68
- export async function setupTarballEnvironment({ projectDir, monorepoRoot, packageManager = "pnpm", }) {
68
+ export async function setupTarballEnvironment({ projectDir, monorepoRoot, packageManager = "pnpm", viteVersion, }) {
69
69
  log(`🚀 Setting up tarball environment for ${projectDir}`);
70
70
  // Generate a resource unique key for this test run
71
71
  // Use just the hash to keep worker names short (under Cloudflare's 54 char limit)
@@ -75,7 +75,7 @@ export async function setupTarballEnvironment({ projectDir, monorepoRoot, packag
75
75
  .substring(0, 8);
76
76
  const resourceUniqueKey = hash;
77
77
  try {
78
- const { tempDir, targetDir } = await copyProjectToTempDir(projectDir, resourceUniqueKey, packageManager, monorepoRoot);
78
+ const { tempDir, targetDir } = await copyProjectToTempDir(projectDir, resourceUniqueKey, packageManager, monorepoRoot, undefined, viteVersion);
79
79
  // Copy wrangler cache to improve deployment performance
80
80
  const sdkRoot = ROOT_DIR;
81
81
  await copyWranglerCache(targetDir, sdkRoot);
@@ -45,6 +45,11 @@ export interface SetupPlaygroundEnvironmentOptions {
45
45
  * @default true
46
46
  */
47
47
  autoStartDevServer?: boolean;
48
+ /**
49
+ * Major Vite version to test against. When set to 7, the test project
50
+ * is patched to use Vite 7 + @vitejs/plugin-react 5.
51
+ */
52
+ viteVersion?: number;
48
53
  }
49
54
  /**
50
55
  * A Vitest hook that sets up a playground environment for a test file.
@@ -109,9 +109,13 @@ function getPlaygroundDirFromImportMeta(importMetaUrl) {
109
109
  * This ensures that tests run in a clean, isolated environment.
110
110
  */
111
111
  export function setupPlaygroundEnvironment(options) {
112
- const { sourceProjectDir, monorepoRoot, dev = true, deploy = true, autoStartDevServer = true, } = typeof options === "string"
112
+ const { sourceProjectDir, monorepoRoot, dev = true, deploy = true, autoStartDevServer = true, viteVersion: explicitViteVersion, } = typeof options === "string"
113
113
  ? { sourceProjectDir: options, autoStartDevServer: true }
114
114
  : options;
115
+ const envViteVersion = process.env.RWSDK_VITE_VERSION
116
+ ? Number(process.env.RWSDK_VITE_VERSION)
117
+ : undefined;
118
+ const viteVersion = explicitViteVersion ?? envViteVersion;
115
119
  ensureHooksRegistered();
116
120
  beforeAll(async () => {
117
121
  let projectDir;
@@ -132,6 +136,7 @@ export function setupPlaygroundEnvironment(options) {
132
136
  projectDir,
133
137
  monorepoRoot,
134
138
  packageManager: process.env.PACKAGE_MANAGER || "pnpm",
139
+ viteVersion,
135
140
  });
136
141
  globalDevPlaygroundEnv = {
137
142
  projectDir: devEnv.targetDir,
@@ -156,6 +161,7 @@ export function setupPlaygroundEnvironment(options) {
156
161
  projectDir,
157
162
  monorepoRoot,
158
163
  packageManager: process.env.PACKAGE_MANAGER || "pnpm",
164
+ viteVersion,
159
165
  });
160
166
  globalDeployPlaygroundEnv = {
161
167
  projectDir: deployEnv.targetDir,
@@ -11,6 +11,7 @@ export async function setupTestEnvironment(options = {}) {
11
11
  const tarballEnv = await setupTarballEnvironment({
12
12
  projectDir: options.projectDir,
13
13
  packageManager: options.packageManager,
14
+ viteVersion: options.viteVersion,
14
15
  });
15
16
  const resources = {
16
17
  tempDirCleanup: tarballEnv.cleanup,
@@ -26,6 +26,7 @@ export interface SmokeTestOptions {
26
26
  skipHmr?: boolean;
27
27
  skipStyleTests?: boolean;
28
28
  packageManager?: PackageManager;
29
+ viteVersion?: number;
29
30
  }
30
31
  export interface TestResources {
31
32
  tempDirCleanup?: () => Promise<void>;
@@ -17,6 +17,6 @@ export const assembleDocument = ({ requestInfo, pageElement, shouldSSR, }) => {
17
17
  };
18
18
  const Document = requestInfo.rw.Document;
19
19
  return (_jsxs(Document, { ...requestInfo, children: [_jsx("script", { nonce: requestInfo.rw.nonce, dangerouslySetInnerHTML: {
20
- __html: `globalThis.__RWSDK_CONTEXT = ${JSON.stringify(clientContext)}`,
20
+ __html: `globalThis.__RWSDK_CONTEXT = ${JSON.stringify(clientContext)};if(!globalThis.__webpack_require__){globalThis.__webpack_require__=function(id){throw new Error("rwsdk: __webpack_require__ called before client init for: "+id)};globalThis.__webpack_require__.u=function(){}}`,
21
21
  } }), _jsx(Stylesheets, { requestInfo: requestInfo }), _jsx(Preloads, { requestInfo: requestInfo }), _jsx("div", { id: "hydrate-root", children: pageElement })] }));
22
22
  };
@@ -20,7 +20,7 @@ export const renderDocumentHtmlStream = async ({ rscPayloadStream, Document, req
20
20
  };
21
21
  // Create the outer document with a marker for injection
22
22
  const documentElement = (_jsxs(Document, { ...requestInfo, children: [_jsx("script", { nonce: requestInfo.rw.nonce, dangerouslySetInnerHTML: {
23
- __html: `globalThis.__RWSDK_CONTEXT = ${JSON.stringify(clientContext)}`,
23
+ __html: `globalThis.__RWSDK_CONTEXT = ${JSON.stringify(clientContext)};if(!globalThis.__webpack_require__){globalThis.__webpack_require__=function(id){throw new Error("rwsdk: __webpack_require__ called before client init for: "+id)};globalThis.__webpack_require__.u=function(){}}`,
24
24
  } }), _jsx(Stylesheets, { requestInfo: requestInfo }), _jsx(Preloads, { requestInfo: requestInfo }), _jsx("div", { id: "hydrate-root", children: _jsx("div", { id: "rwsdk-app-start" }) })] }));
25
25
  const outerHtmlStream = await renderHtmlStream({
26
26
  node: documentElement,
@@ -23,6 +23,20 @@ const findCssForModule = (scriptId, manifest) => {
23
23
  css.add(href);
24
24
  }
25
25
  }
26
+ // context(justinvdm, 2026-04-23): Rolldown associates CSS with the
27
+ // chunk that imports the CSS file, which may be a dynamic import target
28
+ // rather than the entry chunk. Walk both static and dynamic imports to
29
+ // find CSS from transitive dependencies.
30
+ if (entry.imports) {
31
+ for (const importId of entry.imports) {
32
+ inner(importId);
33
+ }
34
+ }
35
+ if (entry.dynamicImports) {
36
+ for (const importId of entry.dynamicImports) {
37
+ inner(importId);
38
+ }
39
+ }
26
40
  };
27
41
  inner(scriptId);
28
42
  return Array.from(css);
@@ -37,5 +51,13 @@ export const Stylesheets = async ({ requestInfo, }) => {
37
51
  allStylesheets.add(toAbsoluteHref(entry));
38
52
  }
39
53
  }
54
+ for (const [, entry] of Object.entries(manifest)) {
55
+ if (entry.isEntry) {
56
+ const css = findCssForModule(entry.src ?? "", manifest);
57
+ for (const href of css) {
58
+ allStylesheets.add(toAbsoluteHref(href));
59
+ }
60
+ }
61
+ }
40
62
  return (_jsx(_Fragment, { children: Array.from(allStylesheets).map((href) => (_jsx("link", { rel: "stylesheet", href: href, precedence: "first" }, href))) }));
41
63
  };
@@ -77,6 +77,13 @@ if (fileURLToPath(import.meta.url) === process.argv[1]) {
77
77
  else if (arg === "--realtime") {
78
78
  options.realtime = true;
79
79
  }
80
+ else if (arg.startsWith("--vite-version=")) {
81
+ const version = parseInt(arg.substring(15), 10);
82
+ if (Number.isNaN(version) || version <= 0) {
83
+ throw new Error(`Invalid Vite version: ${arg}`);
84
+ }
85
+ options.viteVersion = version;
86
+ }
80
87
  else if (arg === "--help" || arg === "-h") {
81
88
  // Display help text
82
89
  console.log(`
@@ -99,6 +106,7 @@ Options:
99
106
  --bail Stop on first test failure
100
107
  --copy-project Copy the project to the artifacts directory
101
108
  --realtime Only run realtime smoke tests, skip initial tests
109
+ --vite-version=VERSION Major Vite version to test against (default: current, e.g. --vite-version=7)
102
110
  --help Show this help message
103
111
  `);
104
112
  process.exit(0);
@@ -0,0 +1,10 @@
1
+ import type { EnvironmentOptions } from "vite";
2
+ interface OptimizeDepsPlugin {
3
+ name: string;
4
+ resolveId?: (id: string, importer: string | undefined, opts: {
5
+ kind: string;
6
+ }) => any;
7
+ load?: (id: string) => any;
8
+ }
9
+ export declare function addOptimizeDepsPlugin(config: EnvironmentOptions, plugin: OptimizeDepsPlugin): void;
10
+ export {};
@@ -0,0 +1,6 @@
1
+ export function addOptimizeDepsPlugin(config, plugin) {
2
+ config.optimizeDeps ??= {};
3
+ config.optimizeDeps.rolldownOptions ??= {};
4
+ config.optimizeDeps.rolldownOptions.plugins ??= [];
5
+ config.optimizeDeps.rolldownOptions.plugins.push(plugin);
6
+ }
@@ -25,20 +25,20 @@ export async function buildApp({ builder, clientEntryPoints, clientFiles, server
25
25
  await mkdir(dirname(tempEntryPath), { recursive: true });
26
26
  }
27
27
  await writeFile(tempEntryPath, "");
28
- const originalWorkerBuildConfig = workerEnv.config.build;
29
- workerEnv.config.build = {
30
- ...originalWorkerBuildConfig,
31
- write: false,
32
- rollupOptions: {
33
- ...originalWorkerBuildConfig?.rollupOptions,
34
- input: {
35
- index: tempEntryPath,
36
- },
37
- },
28
+ // context(justinvdm, 2026-05-13): Mutate the resolved build config in
29
+ // place rather than replacing the build object. Creating a new object
30
+ // loses Vite's rolldownOptions compat proxy, so we save and restore
31
+ // individual properties instead.
32
+ const originalWrite = workerEnv.config.build.write;
33
+ const originalInput = workerEnv.config.build.rolldownOptions.input;
34
+ workerEnv.config.build.write = false;
35
+ workerEnv.config.build.rolldownOptions.input = {
36
+ index: tempEntryPath,
38
37
  };
39
38
  await builder.build(workerEnv);
40
39
  // Restore the original config
41
- workerEnv.config.build = originalWorkerBuildConfig;
40
+ workerEnv.config.build.write = originalWrite;
41
+ workerEnv.config.build.rolldownOptions.input = originalInput;
42
42
  }
43
43
  finally {
44
44
  await rm(tempEntryPath, { force: true });
@@ -51,6 +51,19 @@ export async function buildApp({ builder, clientEntryPoints, clientFiles, server
51
51
  entries: [workerEntryPathname],
52
52
  esbuildOptions,
53
53
  });
54
+ // context(justinvdm, 2026-05-13): In Vite 8 (Rolldown), the worker build
55
+ // fragments into hundreds of tiny chunks by default. Disabling code
56
+ // splitting forces a single consolidated intermediate worker file, matching
57
+ // the architecture's expectation of an intermediate `worker.js` and
58
+ // preventing leftover artifacts from cluttering the final output.
59
+ workerEnv.config.build.rolldownOptions.output ??= {};
60
+ if (Array.isArray(workerEnv.config.build.rolldownOptions.output)) {
61
+ workerEnv.config.build.rolldownOptions.output.forEach((o) => (o.codeSplitting = false));
62
+ }
63
+ else {
64
+ workerEnv.config.build.rolldownOptions.output.codeSplitting =
65
+ false;
66
+ }
54
67
  console.log("Building worker...");
55
68
  process.env.RWSDK_BUILD_PASS = "worker";
56
69
  await builder.build(workerEnv);
@@ -61,14 +74,14 @@ export async function buildApp({ builder, clientEntryPoints, clientFiles, server
61
74
  console.log("Building client...");
62
75
  const clientEnv = builder.environments["client"];
63
76
  clientEnv.config.build ??= {};
64
- clientEnv.config.build.rollupOptions ??= {};
77
+ clientEnv.config.build.rolldownOptions ??= {};
65
78
  const clientEntryPointsArray = Array.from(clientEntryPoints);
66
79
  if (clientEntryPointsArray.length === 0) {
67
80
  log("No client entry points discovered, using default: src/client.tsx");
68
- clientEnv.config.build.rollupOptions.input = ["src/client.tsx"];
81
+ clientEnv.config.build.rolldownOptions.input = ["src/client.tsx"];
69
82
  }
70
83
  else {
71
- clientEnv.config.build.rollupOptions.input = clientEntryPointsArray;
84
+ clientEnv.config.build.rolldownOptions.input = clientEntryPointsArray;
72
85
  }
73
86
  await builder.build(clientEnv);
74
87
  console.log("Linking worker build...");
@@ -82,10 +95,36 @@ export async function buildApp({ builder, clientEntryPoints, clientFiles, server
82
95
  // directly. Instead, we re-point the original entry to the intermediate
83
96
  // worker bundle from the first pass. This allows the linker pass to re-use
84
97
  // the same plugin-driven configuration while bundling the final worker.
85
- workerConfig.build.rollupOptions.input = {
98
+ workerConfig.build.rolldownOptions.input = {
86
99
  index: resolve(projectRootDir, "dist", "worker", "index.js"),
87
100
  };
101
+ // context(justinvdm, 2026-05-13): In Vite 8 (Rolldown), the linker pass
102
+ // was producing hundreds of tiny chunks instead of a single consolidated
103
+ // worker bundle. Setting codeSplitting:false forces all code (including
104
+ // dynamic imports from the intermediate worker artifact) into the entry
105
+ // chunk, restoring the single-file worker output the architecture expects.
106
+ workerConfig.build.rolldownOptions.output ??= {};
107
+ if (Array.isArray(workerConfig.build.rolldownOptions.output)) {
108
+ workerConfig.build.rolldownOptions.output.forEach((o) => (o.codeSplitting = false));
109
+ }
110
+ else {
111
+ workerConfig.build.rolldownOptions.output.codeSplitting = false;
112
+ }
88
113
  await builder.build(workerEnv);
114
+ // Remove first-pass JS artifacts that are now inlined into the final worker
115
+ // bundle. Without this cleanup, ~480 leftover chunks from the first pass
116
+ // clutter dist/worker/assets/ and inflate deployment file counts.
117
+ const workerAssetsDir = resolve(projectRootDir, "dist", "worker", "assets");
118
+ try {
119
+ for (const entry of await readdir(workerAssetsDir)) {
120
+ if (entry.endsWith(".js") || entry.endsWith(".js.map")) {
121
+ await rm(join(workerAssetsDir, entry), { force: true });
122
+ }
123
+ }
124
+ }
125
+ catch {
126
+ // Directory may not exist (e.g. if the app has no worker assets)
127
+ }
89
128
  console.log("Build complete!");
90
129
  // context(zshannon, 16 Mar 2026): Nest client output under base subdirectory
91
130
  // for Cloudflare's assets module, which maps URL paths directly to file paths.
@@ -50,11 +50,13 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
50
50
  ],
51
51
  exclude: [],
52
52
  entries: [workerEntryPathname],
53
- esbuildOptions: {
54
- jsx: "automatic",
55
- jsxImportSource: "react",
56
- define: {
57
- "process.env.NODE_ENV": JSON.stringify(mode),
53
+ rolldownOptions: {
54
+ transform: {
55
+ jsx: "react-jsx",
56
+ define: {
57
+ "process.env.NODE_ENV": JSON.stringify(mode),
58
+ "__webpack_require__": "globalThis.__webpack_require__",
59
+ },
58
60
  },
59
61
  },
60
62
  },
@@ -70,6 +72,9 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
70
72
  appType: "custom",
71
73
  mode,
72
74
  logLevel: silent ? "silent" : "info",
75
+ resolve: {
76
+ tsconfigPaths: true,
77
+ },
73
78
  build: {
74
79
  minify: mode !== "development",
75
80
  sourcemap,
@@ -86,7 +91,7 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
86
91
  build: {
87
92
  outDir: resolve(projectRootDir, "dist", "client"),
88
93
  manifest: true,
89
- rollupOptions: {
94
+ rolldownOptions: {
90
95
  input: [],
91
96
  },
92
97
  },
@@ -105,12 +110,13 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
105
110
  "rwsdk/use-synced-state/client",
106
111
  ],
107
112
  entries: [],
108
- esbuildOptions: {
109
- jsx: "automatic",
110
- jsxImportSource: "react",
111
- plugins: [],
112
- define: {
113
- "process.env.NODE_ENV": JSON.stringify(mode),
113
+ rolldownOptions: {
114
+ transform: {
115
+ jsx: "react-jsx",
116
+ define: {
117
+ "process.env.NODE_ENV": JSON.stringify(mode),
118
+ "__webpack_require__": "globalThis.__webpack_require__",
119
+ },
114
120
  },
115
121
  },
116
122
  },
@@ -143,12 +149,13 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
143
149
  "rwsdk/realtime/worker",
144
150
  "rwsdk/use-synced-state/client",
145
151
  ],
146
- esbuildOptions: {
147
- jsx: "automatic",
148
- jsxImportSource: "react",
149
- plugins: [],
150
- define: {
151
- "process.env.NODE_ENV": JSON.stringify(mode),
152
+ rolldownOptions: {
153
+ transform: {
154
+ jsx: "react-jsx",
155
+ define: {
156
+ "process.env.NODE_ENV": JSON.stringify(mode),
157
+ "__webpack_require__": "globalThis.__webpack_require__",
158
+ },
152
159
  },
153
160
  },
154
161
  },
@@ -161,7 +168,7 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
161
168
  fileName: () => path.basename(INTERMEDIATE_SSR_BRIDGE_PATH),
162
169
  },
163
170
  outDir: path.dirname(INTERMEDIATE_SSR_BRIDGE_PATH),
164
- rollupOptions: {
171
+ rolldownOptions: {
165
172
  output: {
166
173
  // context(justinvdm, 15 Sep 2025): The SSR bundle is a
167
174
  // pre-compiled artifact. When the linker pass bundles it into
@@ -176,7 +183,7 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
176
183
  // context(justinvdm, 19 Nov 2025): We use a custom plugin
177
184
  // (ssrBridgeWrapPlugin) to intelligently inject the IIFE *after*
178
185
  // any top-level external imports, ensuring they remain valid.
179
- inlineDynamicImports: true,
186
+ codeSplitting: false,
180
187
  },
181
188
  plugins: [ssrBridgeWrapPlugin()],
182
189
  },
@@ -1,6 +1,7 @@
1
1
  import debug from "debug";
2
2
  import MagicString from "magic-string";
3
3
  import path from "path";
4
+ import { addOptimizeDepsPlugin } from "./addOptimizeDepsPlugin.mjs";
4
5
  import { VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, } from "../lib/constants.mjs";
5
6
  export function generateLookupMap({ files, isDev, kind, exportName, }) {
6
7
  const s = new MagicString(`
@@ -55,32 +56,27 @@ export const createDirectiveLookupPlugin = async ({ projectRootDir, files, confi
55
56
  return;
56
57
  }
57
58
  log("Configuring environment: env=%s", env);
58
- viteConfig.optimizeDeps ??= {};
59
- viteConfig.optimizeDeps.esbuildOptions ??= {};
60
- viteConfig.optimizeDeps.esbuildOptions.plugins ??= [];
61
- viteConfig.optimizeDeps.esbuildOptions.plugins.push({
59
+ const escapedVirtualModuleName = config.virtualModuleName.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
60
+ const escapedPrefixedModuleName = `/@id/${config.virtualModuleName}`.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
61
+ const lookupFilter = new RegExp(`^(${escapedVirtualModuleName}|${escapedPrefixedModuleName})\\.js$`);
62
+ addOptimizeDepsPlugin(viteConfig, {
62
63
  name: `rwsdk:${config.pluginName}`,
63
- setup(build) {
64
- log("Setting up esbuild plugin for %s", config.virtualModuleName);
65
- // Handle both direct virtual module name and /@id/ prefixed version
66
- const escapedVirtualModuleName = config.virtualModuleName.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
67
- const escapedPrefixedModuleName = `/@id/${config.virtualModuleName}`.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
68
- build.onResolve({
69
- filter: new RegExp(`^(${escapedVirtualModuleName}|${escapedPrefixedModuleName})\\.js$`),
70
- }, () => {
64
+ resolveId(id) {
65
+ if (lookupFilter.test(id)) {
71
66
  process.env.VERBOSE &&
72
- log("Esbuild onResolve: marking %s as external", config.virtualModuleName);
67
+ log("Marking %s as external", config.virtualModuleName);
73
68
  return {
74
- path: `${config.virtualModuleName}.js`,
69
+ id: `${config.virtualModuleName}.js`,
75
70
  external: true,
76
71
  };
77
- });
72
+ }
78
73
  },
79
74
  });
80
75
  const shouldOptimizeForEnv = !config.optimizeForEnvironments ||
81
76
  config.optimizeForEnvironments.includes(env);
82
77
  if (shouldOptimizeForEnv) {
83
78
  log("Applying optimizeDeps and aliasing for environment: %s", env);
79
+ viteConfig.optimizeDeps ??= {};
84
80
  viteConfig.optimizeDeps.include ??= [];
85
81
  for (const file of files) {
86
82
  if (file.includes("node_modules")) {