rwsdk 0.2.0 → 0.3.1

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 (63) hide show
  1. package/dist/lib/constants.d.mts +6 -1
  2. package/dist/lib/constants.mjs +6 -1
  3. package/dist/lib/smokeTests/browser.mjs +5 -21
  4. package/dist/lib/smokeTests/codeUpdates.d.mts +1 -1
  5. package/dist/lib/smokeTests/codeUpdates.mjs +41 -5
  6. package/dist/lib/smokeTests/development.d.mts +1 -1
  7. package/dist/lib/smokeTests/development.mjs +4 -10
  8. package/dist/lib/smokeTests/release.d.mts +1 -1
  9. package/dist/lib/smokeTests/release.mjs +4 -9
  10. package/dist/lib/smokeTests/runSmokeTests.mjs +2 -2
  11. package/dist/lib/smokeTests/templates/SmokeTest.template.js +3 -2
  12. package/dist/lib/testUtils/stubEnvVars.d.mts +2 -0
  13. package/dist/lib/testUtils/stubEnvVars.mjs +11 -0
  14. package/dist/runtime/imports/client.js +4 -9
  15. package/dist/runtime/imports/worker.js +2 -1
  16. package/dist/runtime/register/ssr.js +2 -1
  17. package/dist/runtime/requestInfo/worker.js +9 -1
  18. package/dist/runtime/worker.d.ts +0 -3
  19. package/dist/runtime/worker.js +1 -10
  20. package/dist/scripts/debug-sync.mjs +0 -23
  21. package/dist/scripts/smoke-test.mjs +0 -10
  22. package/dist/vite/buildApp.d.mts +15 -0
  23. package/dist/vite/buildApp.mjs +53 -0
  24. package/dist/vite/configPlugin.d.mts +4 -4
  25. package/dist/vite/configPlugin.mjs +70 -76
  26. package/dist/vite/constants.d.mts +2 -0
  27. package/dist/vite/constants.mjs +12 -0
  28. package/dist/vite/createDirectiveLookupPlugin.d.mts +0 -6
  29. package/dist/vite/createDirectiveLookupPlugin.mjs +69 -145
  30. package/dist/vite/createViteAwareResolver.d.mts +4 -0
  31. package/dist/vite/createViteAwareResolver.mjs +208 -0
  32. package/dist/vite/directiveModulesDevPlugin.d.mts +8 -0
  33. package/dist/vite/directiveModulesDevPlugin.mjs +87 -0
  34. package/dist/vite/directivesFilteringPlugin.d.mts +6 -0
  35. package/dist/vite/directivesFilteringPlugin.mjs +31 -0
  36. package/dist/vite/directivesPlugin.mjs +32 -42
  37. package/dist/vite/getViteEsbuild.d.mts +1 -0
  38. package/dist/vite/getViteEsbuild.mjs +12 -0
  39. package/dist/vite/injectVitePreamblePlugin.d.mts +3 -2
  40. package/dist/vite/injectVitePreamblePlugin.mjs +8 -2
  41. package/dist/vite/linkerPlugin.d.mts +4 -0
  42. package/dist/vite/linkerPlugin.mjs +41 -0
  43. package/dist/vite/manifestPlugin.d.mts +2 -2
  44. package/dist/vite/manifestPlugin.mjs +20 -37
  45. package/dist/vite/moveStaticAssetsPlugin.mjs +2 -1
  46. package/dist/vite/prismaPlugin.mjs +1 -1
  47. package/dist/vite/reactConditionsResolverPlugin.mjs +15 -16
  48. package/dist/vite/redwoodPlugin.d.mts +0 -1
  49. package/dist/vite/redwoodPlugin.mjs +27 -9
  50. package/dist/vite/runDirectivesScan.d.mts +7 -0
  51. package/dist/vite/runDirectivesScan.mjs +156 -0
  52. package/dist/vite/ssrBridgePlugin.mjs +21 -14
  53. package/dist/vite/transformClientComponents.d.mts +0 -1
  54. package/dist/vite/transformClientComponents.mjs +1 -9
  55. package/dist/vite/transformJsxScriptTagsPlugin.d.mts +4 -3
  56. package/dist/vite/transformJsxScriptTagsPlugin.mjs +66 -84
  57. package/dist/vite/transformJsxScriptTagsPlugin.test.mjs +67 -41
  58. package/dist/vite/transformServerFunctions.d.mts +1 -1
  59. package/dist/vite/transformServerFunctions.mjs +11 -12
  60. package/dist/vite/virtualPlugin.mjs +8 -0
  61. package/package.json +7 -1
  62. package/dist/runtime/clientNavigation.d.ts +0 -9
  63. package/dist/runtime/clientNavigation.js +0 -88
@@ -1,4 +1,9 @@
1
1
  export declare const ROOT_DIR: string;
2
2
  export declare const SRC_DIR: string;
3
3
  export declare const DIST_DIR: string;
4
- export declare const SSR_BRIDGE_PATH: string;
4
+ export declare const VITE_DIR: string;
5
+ export declare const INTERMEDIATES_OUTPUT_DIR: string;
6
+ export declare const CLIENT_BARREL_PATH: string;
7
+ export declare const SERVER_BARREL_PATH: string;
8
+ export declare const INTERMEDIATE_SSR_BRIDGE_PATH: string;
9
+ export declare const CLIENT_MANIFEST_RELATIVE_PATH: string;
@@ -3,4 +3,9 @@ const __dirname = new URL(".", import.meta.url).pathname;
3
3
  export const ROOT_DIR = resolve(__dirname, "..", "..");
4
4
  export const SRC_DIR = resolve(ROOT_DIR, "src");
5
5
  export const DIST_DIR = resolve(ROOT_DIR, "dist");
6
- export const SSR_BRIDGE_PATH = resolve(DIST_DIR, "worker", "__ssr_bridge.js");
6
+ export const VITE_DIR = resolve(ROOT_DIR, "src", "vite");
7
+ export const INTERMEDIATES_OUTPUT_DIR = resolve(DIST_DIR, "__intermediate_builds");
8
+ export const CLIENT_BARREL_PATH = resolve(INTERMEDIATES_OUTPUT_DIR, "rwsdk-client-barrel.js");
9
+ export const SERVER_BARREL_PATH = resolve(INTERMEDIATES_OUTPUT_DIR, "rwsdk-server-barrel.js");
10
+ export const INTERMEDIATE_SSR_BRIDGE_PATH = resolve(INTERMEDIATES_OUTPUT_DIR, "ssr", "ssr_bridge.js");
11
+ export const CLIENT_MANIFEST_RELATIVE_PATH = resolve("dist", "client", ".vite", "manifest.json");
@@ -316,25 +316,9 @@ export async function checkUrl(url, artifactDir, browserPath, headless = true, b
316
316
  export async function checkUrlSmoke(page, url, isRealtime, bail = false, skipClient = false, environment = "Development", timestampState, targetDir, skipHmr = false, skipStyleTests = false) {
317
317
  const phase = isRealtime ? "Post-upgrade" : "Initial";
318
318
  console.log(`🔍 Testing ${phase} smoke tests at ${url}`);
319
- // Parse the base URL and path to properly handle smoke test queries
320
- const parsedUrl = new URL(url);
321
- log("Parsed URL: %O", {
322
- origin: parsedUrl.origin,
323
- pathname: parsedUrl.pathname,
324
- search: parsedUrl.search,
325
- });
326
- // Add __smoke_test query parameter, preserving any existing query parameters
327
- if (parsedUrl.searchParams.has("__smoke_test")) {
328
- console.log(`URL already has __smoke_test parameter: ${url}`);
329
- }
330
- else {
331
- parsedUrl.searchParams.append("__smoke_test", "1");
332
- log("Added __smoke_test parameter to URL");
333
- }
334
319
  // Navigate to smoke test page
335
- const smokeUrl = parsedUrl.toString();
336
- console.log(`🔍 Accessing smoke test page: ${smokeUrl}`);
337
- await page.goto(smokeUrl, { waitUntil: "networkidle0" });
320
+ console.log(`🔍 Accessing smoke test page: ${url}`);
321
+ await page.goto(url, { waitUntil: "networkidle0" });
338
322
  log("Page loaded successfully");
339
323
  // Track failures to report at the end
340
324
  let hasFailures = false;
@@ -692,9 +676,9 @@ export async function checkClientSmoke(page, phase = "", environment = "Developm
692
676
  // Check if we're on a smoke test page - in which case missing the refresh button is a failure
693
677
  const currentUrl = page.url();
694
678
  log("Current URL: %s", currentUrl);
695
- if (currentUrl.includes("__smoke_test")) {
696
- log("ERROR: Smoke test page is missing the refresh-health button");
697
- throw new Error("Smoke test page is missing the refresh-health button - this is a test failure");
679
+ if (!currentUrl.includes("/__smoke_test")) {
680
+ log("ERROR: Smoke test page is not the current URL");
681
+ throw new Error("Smoke test page is not the current URL - this is a test failure");
698
682
  }
699
683
  console.log("ℹ️ Basic page structure verified, continuing without client-side smoke test");
700
684
  return null;
@@ -6,4 +6,4 @@ export declare function createSmokeTestStylesheets(targetDir: string): Promise<v
6
6
  /**
7
7
  * Modifies the worker.tsx and wrangler.jsonc files to add realtime support
8
8
  */
9
- export declare function modifyAppForRealtime(targetDir: string): Promise<void>;
9
+ export declare function modifyAppForRealtime(targetDir: string, skipClient?: boolean): Promise<void>;
@@ -46,7 +46,7 @@ export async function createSmokeTestComponents(targetDir, skipClient = false) {
46
46
  log("Skipping client-side smoke test component creation");
47
47
  }
48
48
  // Modify worker.tsx and wrangler.jsonc for realtime support
49
- await modifyAppForRealtime(targetDir);
49
+ await modifyAppForRealtime(targetDir, skipClient);
50
50
  log("Smoke test components created successfully");
51
51
  console.log("Created smoke test components:");
52
52
  console.log(`- ${smokeTestFunctionsPath}`);
@@ -104,7 +104,7 @@ export async function createSmokeTestStylesheets(targetDir) {
104
104
  /**
105
105
  * Modifies the worker.tsx and wrangler.jsonc files to add realtime support
106
106
  */
107
- export async function modifyAppForRealtime(targetDir) {
107
+ export async function modifyAppForRealtime(targetDir, skipClient = false) {
108
108
  log("Modifying worker.tsx and wrangler.jsonc for realtime support");
109
109
  // Modify worker.tsx
110
110
  const workerPath = join(targetDir, "src", "worker.tsx");
@@ -118,8 +118,14 @@ export async function modifyAppForRealtime(targetDir) {
118
118
  const hasRealtimeExport = workerContent.includes('export { RealtimeDurableObject } from "rwsdk/realtime/durableObject"');
119
119
  const hasRealtimeRoute = workerContent.includes("realtimeRoute(");
120
120
  const hasEnvImport = workerContent.includes('import { env } from "cloudflare:workers"');
121
- if (!hasRealtimeExport || !hasRealtimeRoute || !hasEnvImport) {
122
- log("Need to modify worker.tsx for realtime support");
121
+ const hasSmokeTestImport = workerContent.includes('import { SmokeTest } from "@/app/components/__SmokeTest.tsx"');
122
+ const hasSmokeTestRoute = workerContent.includes('route("/__smoke_test", SmokeTest)');
123
+ if (!hasRealtimeExport ||
124
+ !hasRealtimeRoute ||
125
+ !hasEnvImport ||
126
+ !hasSmokeTestImport ||
127
+ !hasSmokeTestRoute) {
128
+ log("Need to modify worker.tsx for realtime and smoke test support");
123
129
  const s = new MagicString(workerContent);
124
130
  // Add the export line if it doesn't exist
125
131
  if (!hasRealtimeExport) {
@@ -145,6 +151,26 @@ export async function modifyAppForRealtime(targetDir) {
145
151
  log("Added env import from cloudflare:workers");
146
152
  }
147
153
  }
154
+ // Add SmokeTest import if it doesn't exist
155
+ if (!hasSmokeTestImport) {
156
+ const importRegex = /import.*?from.*?;\n/g;
157
+ let lastImportMatch;
158
+ let lastImportPosition = 0;
159
+ // Find the position after the last import statement
160
+ while ((lastImportMatch = importRegex.exec(workerContent)) !== null) {
161
+ lastImportPosition =
162
+ lastImportMatch.index + lastImportMatch[0].length;
163
+ }
164
+ if (lastImportPosition > 0) {
165
+ s.appendRight(lastImportPosition, 'import { SmokeTest } from "@/app/components/__SmokeTest";\n');
166
+ log("Added SmokeTest import");
167
+ }
168
+ else {
169
+ // if no imports found, just prepend to the file
170
+ s.prepend('import { SmokeTest } from "@/app/components/__SmokeTest";\n');
171
+ log("Added SmokeTest import to the beginning of the file");
172
+ }
173
+ }
148
174
  // Add the realtimeRoute line if it doesn't exist
149
175
  if (!hasRealtimeRoute) {
150
176
  const defineAppMatch = workerContent.match(/export default defineApp\(\[/);
@@ -154,6 +180,16 @@ export async function modifyAppForRealtime(targetDir) {
154
180
  log("Added realtimeRoute to defineApp");
155
181
  }
156
182
  }
183
+ // Add the smoke test route if it doesn't exist
184
+ if (!hasSmokeTestRoute) {
185
+ const defineAppRegex = /(export default defineApp\(\[)([\s\S]*)(\]\);)/m;
186
+ const match = workerContent.match(defineAppRegex);
187
+ if (match) {
188
+ const insertionPoint = match.index + match[1].length + match[2].length;
189
+ s.appendLeft(insertionPoint, ' render(Document, [route("/__smoke_test", SmokeTest)]),\n');
190
+ log("Added smoke test route to defineApp");
191
+ }
192
+ }
157
193
  // Import realtimeRoute if it's not already imported
158
194
  if (!workerContent.includes("realtimeRoute")) {
159
195
  // First check if we already have the import from rwsdk/realtime/worker
@@ -196,7 +232,7 @@ export async function modifyAppForRealtime(targetDir) {
196
232
  log("Successfully modified worker.tsx");
197
233
  }
198
234
  else {
199
- log("worker.tsx already has realtime support, no changes needed");
235
+ log("worker.tsx already has realtime and smoke test support, no changes needed");
200
236
  }
201
237
  }
202
238
  else {
@@ -8,4 +8,4 @@ export declare function runDevServer(cwd?: string): Promise<{
8
8
  /**
9
9
  * Runs tests against the development server
10
10
  */
11
- export declare function runDevTest(url: string, artifactDir: string, customPath?: string, browserPath?: string, headless?: boolean, bail?: boolean, skipClient?: boolean, realtime?: boolean, skipHmr?: boolean, skipStyleTests?: boolean): Promise<void>;
11
+ export declare function runDevTest(url: string, artifactDir: string, browserPath?: string, headless?: boolean, bail?: boolean, skipClient?: boolean, realtime?: boolean, skipHmr?: boolean, skipStyleTests?: boolean): Promise<void>;
@@ -172,21 +172,15 @@ export async function runDevServer(cwd) {
172
172
  /**
173
173
  * Runs tests against the development server
174
174
  */
175
- export async function runDevTest(url, artifactDir, customPath = "/", browserPath, headless = true, bail = false, skipClient = false, realtime = false, skipHmr = false, skipStyleTests = false) {
176
- log("Starting dev server test with path: %s", customPath || "/");
175
+ export async function runDevTest(url, artifactDir, browserPath, headless = true, bail = false, skipClient = false, realtime = false, skipHmr = false, skipStyleTests = false) {
176
+ log("Starting dev server test");
177
177
  console.log("🚀 Testing local development server");
178
178
  const browser = await launchBrowser(browserPath, headless);
179
179
  const page = await browser.newPage();
180
180
  try {
181
+ const testUrl = new URL("/__smoke_test", url).toString();
181
182
  // DRY: check both root and custom path
182
- await checkServerUp(url, customPath, RETRIES, bail);
183
- // Now run the tests with the custom path
184
- const testUrl = url +
185
- (customPath === "/"
186
- ? ""
187
- : customPath.startsWith("/")
188
- ? customPath
189
- : "/" + customPath);
183
+ await checkServerUp(url, "/", RETRIES, bail);
190
184
  // Pass the target directory to checkUrl for HMR testing
191
185
  const targetDir = state.resources.targetDir;
192
186
  await page.goto(testUrl, { waitUntil: "networkidle0" });
@@ -40,7 +40,7 @@ export declare function runRelease(cwd: string, projectDir: string, resourceUniq
40
40
  /**
41
41
  * Runs tests against the production deployment
42
42
  */
43
- export declare function runReleaseTest(customPath: string | undefined, artifactDir: string, resources: TestResources, browserPath?: string, headless?: boolean, bail?: boolean, skipClient?: boolean, projectDir?: string, realtime?: boolean, skipHmr?: boolean, skipStyleTests?: boolean): Promise<void>;
43
+ export declare function runReleaseTest(artifactDir: string, resources: TestResources, browserPath?: string, headless?: boolean, bail?: boolean, skipClient?: boolean, projectDir?: string, realtime?: boolean, skipHmr?: boolean, skipStyleTests?: boolean): Promise<void>;
44
44
  /**
45
45
  * Check if a resource name includes a specific resource unique key
46
46
  * This is used to identify resources created during our tests
@@ -379,8 +379,8 @@ export async function runRelease(cwd, projectDir, resourceUniqueKey) {
379
379
  /**
380
380
  * Runs tests against the production deployment
381
381
  */
382
- export async function runReleaseTest(customPath = "/", artifactDir, resources, browserPath, headless = true, bail = false, skipClient = false, projectDir, realtime = false, skipHmr = false, skipStyleTests = false) {
383
- log("Starting release test with path: %s", customPath || "/");
382
+ export async function runReleaseTest(artifactDir, resources, browserPath, headless = true, bail = false, skipClient = false, projectDir, realtime = false, skipHmr = false, skipStyleTests = false) {
383
+ log("Starting release test");
384
384
  console.log("\n🚀 Testing production deployment");
385
385
  try {
386
386
  log("Running release process");
@@ -389,14 +389,9 @@ export async function runReleaseTest(customPath = "/", artifactDir, resources, b
389
389
  log("Waiting 1s before checking server...");
390
390
  await setTimeout(1000);
391
391
  // DRY: check both root and custom path
392
- await checkServerUp(url, customPath);
392
+ await checkServerUp(url, "/");
393
393
  // Now run the tests with the custom path
394
- const testUrl = url +
395
- (customPath === "/"
396
- ? ""
397
- : customPath.startsWith("/")
398
- ? customPath
399
- : "/" + customPath);
394
+ const testUrl = new URL("/__smoke_test", url).toString();
400
395
  await checkUrl(testUrl, artifactDir, browserPath, headless, bail, skipClient, "Production", realtime, resources.targetDir, // Add target directory parameter
401
396
  true, // Always skip HMR in production
402
397
  skipStyleTests);
@@ -57,7 +57,7 @@ export async function runSmokeTests(options = {}) {
57
57
  resources.stopDev = stopDev;
58
58
  state.resources.stopDev = stopDev;
59
59
  log("Running development server tests");
60
- await runDevTest(url, options.artifactDir, options.customPath, browserPath, options.headless !== false, options.bail, options.skipClient, options.realtime, options.skipHmr, options.skipStyleTests);
60
+ await runDevTest(url, options.artifactDir, browserPath, options.headless !== false, options.bail, options.skipClient, options.realtime, options.skipHmr, options.skipStyleTests);
61
61
  // Mark that dev tests have run successfully
62
62
  state.devTestsRan = true;
63
63
  // Update the overall dev test status to PASSED
@@ -95,7 +95,7 @@ export async function runSmokeTests(options = {}) {
95
95
  // Update status when release command runs
96
96
  try {
97
97
  console.log("\n🚀 Running release command smoke test");
98
- await runReleaseTest(options.customPath, options.artifactDir, resources, browserPath, options.headless !== false, options.bail, options.skipClient, options.projectDir, options.realtime, options.skipHmr, options.skipStyleTests);
98
+ await runReleaseTest(options.artifactDir, resources, browserPath, options.headless !== false, options.bail, options.skipClient, options.projectDir, options.realtime, options.skipHmr, options.skipStyleTests);
99
99
  // Update release command status to PASSED
100
100
  updateTestStatus("production", "releaseCommand", "PASSED");
101
101
  // Mark that release tests have run successfully
@@ -5,7 +5,7 @@ import { RequestInfo } from "rwsdk/worker";
5
5
  ${skipClient ? "" : 'import { SmokeTestClient } from "./__SmokeTestClient";'}
6
6
  import { getSmokeTestTimestamp } from "./__smokeTestFunctions";
7
7
 
8
- export const SmokeTestInfo: React.FC = async () => {
8
+ export const SmokeTest = async () => {
9
9
  const currentTime = Date.now();
10
10
  let status = "error";
11
11
  let timestamp = 0;
@@ -77,5 +77,6 @@ export const SmokeTestInfo: React.FC = async () => {
77
77
  ${!skipClient ? "<SmokeTestClient/>" : ""}
78
78
  </div>
79
79
  );
80
- };`;
80
+ };
81
+ `;
81
82
  }
@@ -0,0 +1,2 @@
1
+ declare const stubEnvVars: () => void;
2
+ export default stubEnvVars;
@@ -0,0 +1,11 @@
1
+ import { beforeEach, afterEach } from "vitest";
2
+ const stubEnvVars = () => {
3
+ let originals = {};
4
+ beforeEach(() => {
5
+ originals = { ...process.env };
6
+ });
7
+ afterEach(() => {
8
+ process.env = { ...originals };
9
+ });
10
+ };
11
+ export default stubEnvVars;
@@ -4,16 +4,11 @@ import { memoizeOnId } from "../lib/memoizeOnId";
4
4
  // @ts-ignore
5
5
  import { useClientLookup } from "virtual:use-client-lookup.js";
6
6
  export const loadModule = memoizeOnId(async (id) => {
7
- if (import.meta.env.VITE_IS_DEV_SERVER) {
8
- return await import(/* @vite-ignore */ id);
9
- }
10
- else {
11
- const moduleFn = useClientLookup[id];
12
- if (!moduleFn) {
13
- throw new Error(`(client) No module found for '${id}' in module lookup for "use client" directive`);
14
- }
15
- return await moduleFn();
7
+ const moduleFn = useClientLookup[id];
8
+ if (!moduleFn) {
9
+ throw new Error(`(client) No module found for '${id}' in module lookup for "use client" directive`);
16
10
  }
11
+ return await moduleFn();
17
12
  });
18
13
  // context(justinvdm, 2 Dec 2024): re memoize(): React relies on the same promise instance being returned for the same id
19
14
  export const clientWebpackRequire = memoizeOnId(async (id) => {
@@ -1,8 +1,9 @@
1
1
  import { requestInfo } from "../requestInfo/worker";
2
2
  import { ssrWebpackRequire as baseSsrWebpackRequire } from "rwsdk/__ssr_bridge";
3
3
  import { memoizeOnId } from "../lib/memoizeOnId";
4
+ // @ts-ignore
5
+ import { useServerLookup } from "virtual:use-server-lookup.js";
4
6
  export const loadServerModule = memoizeOnId(async (id) => {
5
- const { useServerLookup } = await import("virtual:use-server-lookup.js");
6
7
  const moduleFn = useServerLookup[id];
7
8
  if (!moduleFn) {
8
9
  throw new Error(`(worker) No module found for '${id}' in module lookup for "use server" directive`);
@@ -1,7 +1,8 @@
1
1
  import { createServerReference as baseCreateServerReference } from "react-server-dom-webpack/client.edge";
2
2
  import { memoizeOnId } from "../lib/memoizeOnId";
3
+ // @ts-ignore
4
+ import { useServerLookup } from "virtual:use-server-lookup.js";
3
5
  export const loadServerModule = memoizeOnId(async (id) => {
4
- const { useServerLookup } = await import("virtual:use-server-lookup.js");
5
6
  const moduleFn = useServerLookup[id];
6
7
  if (!moduleFn) {
7
8
  throw new Error(`(worker) No module found for '${id}' in module lookup for "use server" directive`);
@@ -2,7 +2,15 @@ import { AsyncLocalStorage } from "async_hooks";
2
2
  const requestInfoDeferred = Promise.withResolvers();
3
3
  const requestInfoStore = new AsyncLocalStorage();
4
4
  const requestInfoBase = {};
5
- const REQUEST_INFO_KEYS = ["request", "params", "ctx", "headers", "rw", "cf", "response"];
5
+ const REQUEST_INFO_KEYS = [
6
+ "request",
7
+ "params",
8
+ "ctx",
9
+ "headers",
10
+ "rw",
11
+ "cf",
12
+ "response",
13
+ ];
6
14
  REQUEST_INFO_KEYS.forEach((key) => {
7
15
  Object.defineProperty(requestInfoBase, key, {
8
16
  enumerable: true,
@@ -10,9 +10,6 @@ declare global {
10
10
  export declare const defineApp: <T extends RequestInfo = RequestInfo<any, DefaultAppContext>>(routes: Route<T>[]) => {
11
11
  fetch: (request: Request, env: Env, cf: ExecutionContext) => Promise<Response>;
12
12
  };
13
- export declare const SmokeTestWrapper: React.FC<{
14
- children: React.ReactNode;
15
- }>;
16
13
  export declare const DefaultDocument: React.FC<{
17
14
  children: React.ReactNode;
18
15
  }>;
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { transformRscToHtmlStream } from "./render/transformRscToHtmlStream";
3
3
  import { renderToRscStream } from "./render/renderToRscStream";
4
4
  import { rscActionHandler } from "./register/worker";
@@ -33,7 +33,6 @@ export const defineApp = (routes) => {
33
33
  const url = new URL(request.url);
34
34
  const isRSCRequest = url.searchParams.has("__rsc") ||
35
35
  request.headers.get("accept")?.includes("text/x-component");
36
- const isSmokeTest = url.searchParams.has("__smoke_test");
37
36
  const userHeaders = new Headers();
38
37
  const rw = {
39
38
  Document: DefaultDocument,
@@ -67,9 +66,6 @@ export const defineApp = (routes) => {
67
66
  else {
68
67
  pageElement = _jsx(Page, { ...requestInfo });
69
68
  }
70
- if (isSmokeTest) {
71
- pageElement = _jsx(SmokeTestWrapper, { children: pageElement });
72
- }
73
69
  return pageElement;
74
70
  };
75
71
  const renderPage = async (requestInfo, Page, onError) => {
@@ -175,11 +171,6 @@ export const defineApp = (routes) => {
175
171
  },
176
172
  };
177
173
  };
178
- export const SmokeTestWrapper = async ({ children }) => {
179
- const smokeTestInfo = await Object.values(await import.meta.glob("/src/app/components/__SmokeTest.tsx"))[0]();
180
- const SmokeTestInfo = smokeTestInfo.SmokeTestInfo;
181
- return (_jsxs(_Fragment, { children: [_jsx(SmokeTestInfo, {}), children] }));
182
- };
183
174
  export const DefaultDocument = ({ children, }) => (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx("meta", { charSet: "utf-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" })] }), _jsx("body", { children: _jsx("div", { id: "root", children: children }) })] }));
184
175
  const isClientReference = (Component) => {
185
176
  return Object.prototype.hasOwnProperty.call(Component, "$$isClientReference");
@@ -59,30 +59,11 @@ const cleanupViteEntries = async (targetDir) => {
59
59
  }
60
60
  };
61
61
  const performFullSync = async (sdkDir, targetDir) => {
62
- const sdkPackageJsonPath = path.join(sdkDir, "package.json");
63
- let originalSdkPackageJson = null;
64
62
  let tarballPath = "";
65
63
  let tarballName = "";
66
64
  // Clean up vite cache
67
65
  await cleanupViteEntries(targetDir);
68
66
  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
- }
86
67
  console.log("📦 Packing SDK...");
87
68
  const packResult = await $({ cwd: sdkDir }) `npm pack --json`;
88
69
  const json = JSON.parse(packResult.stdout || "[]");
@@ -152,10 +133,6 @@ const performFullSync = async (sdkDir, targetDir) => {
152
133
  }
153
134
  }
154
135
  finally {
155
- if (originalSdkPackageJson) {
156
- console.log("Restoring package.json...");
157
- await fs.writeFile(sdkPackageJsonPath, originalSdkPackageJson);
158
- }
159
136
  if (tarballPath) {
160
137
  console.log("Removing tarball...");
161
138
  await fs.unlink(tarballPath).catch(() => {
@@ -17,7 +17,6 @@ if (fileURLToPath(import.meta.url) === process.argv[1]) {
17
17
  const ciFlag = args.includes("--ci");
18
18
  // Set initial default values (sync will be determined below)
19
19
  const options = {
20
- customPath: "/", // Default path
21
20
  skipDev: false,
22
21
  skipRelease: false,
23
22
  skipClient: false,
@@ -88,7 +87,6 @@ Smoke Test Usage:
88
87
  node smoke-test.mjs [options]
89
88
 
90
89
  Options:
91
- --url=PATH Custom URL path to test (e.g., "/login")
92
90
  --skip-dev Skip testing the local development server
93
91
  --skip-release Skip testing the release/production deployment
94
92
  --skip-client Skip client-side tests, only run server-side checks
@@ -114,14 +112,6 @@ Options:
114
112
  else if (arg.startsWith("--artifact-dir=")) {
115
113
  options.artifactDir = arg.substring(15);
116
114
  }
117
- else if (arg.startsWith("--url=")) {
118
- options.customPath = arg.substring(6);
119
- }
120
- else if (!arg.startsWith("--")) {
121
- // For backwards compatibility, any non-flag argument is treated as the custom path
122
- console.log(`Setting URL path to "${arg}" (use --url= format in the future)`);
123
- options.customPath = arg;
124
- }
125
115
  else {
126
116
  // Throw error for unknown options instead of just warning
127
117
  log("Unknown option: %s", arg);
@@ -0,0 +1,15 @@
1
+ import type { ViteBuilder } from "vite";
2
+ /**
3
+ * The build orchestrator is responsible for running the multi-phase build
4
+ * process for production. It is designed to solve the circular dependency
5
+ * between the worker, client, and SSR builds.
6
+ *
7
+ * @see docs/architecture/productionBuildProcess.md
8
+ */
9
+ export declare function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, }: {
10
+ builder: ViteBuilder;
11
+ clientEntryPoints: Set<string>;
12
+ clientFiles: Set<string>;
13
+ serverFiles: Set<string>;
14
+ projectRootDir: string;
15
+ }): Promise<void>;
@@ -0,0 +1,53 @@
1
+ import { resolve } from "node:path";
2
+ import debug from "debug";
3
+ import { runDirectivesScan } from "./runDirectivesScan.mjs";
4
+ const log = debug("rwsdk:vite:build-app");
5
+ /**
6
+ * The build orchestrator is responsible for running the multi-phase build
7
+ * process for production. It is designed to solve the circular dependency
8
+ * between the worker, client, and SSR builds.
9
+ *
10
+ * @see docs/architecture/productionBuildProcess.md
11
+ */
12
+ export async function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, }) {
13
+ const workerEnv = builder.environments.worker;
14
+ await runDirectivesScan({
15
+ rootConfig: builder.config,
16
+ environment: workerEnv,
17
+ clientFiles,
18
+ serverFiles,
19
+ });
20
+ console.log("Building worker to discover used client components...");
21
+ process.env.RWSDK_BUILD_PASS = "worker";
22
+ await builder.build(workerEnv);
23
+ log("Used client files after worker build & filtering: %O", Array.from(clientFiles));
24
+ console.log("Building SSR...");
25
+ await builder.build(builder.environments.ssr);
26
+ log("Discovered clientEntryPoints: %O", Array.from(clientEntryPoints));
27
+ console.log("Building client...");
28
+ const clientEnv = builder.environments["client"];
29
+ clientEnv.config.build ??= {};
30
+ clientEnv.config.build.rollupOptions ??= {};
31
+ const clientEntryPointsArray = Array.from(clientEntryPoints);
32
+ if (clientEntryPointsArray.length === 0) {
33
+ log("No client entry points discovered, using default: src/client.tsx");
34
+ clientEnv.config.build.rollupOptions.input = ["src/client.tsx"];
35
+ }
36
+ else {
37
+ clientEnv.config.build.rollupOptions.input = clientEntryPointsArray;
38
+ }
39
+ await builder.build(clientEnv);
40
+ console.log("Linking worker build...");
41
+ process.env.RWSDK_BUILD_PASS = "linker";
42
+ // Re-configure the worker environment for the linking pass
43
+ const workerConfig = workerEnv.config;
44
+ workerConfig.build.emptyOutDir = false;
45
+ workerConfig.build.rollupOptions.input = {
46
+ worker: resolve(projectRootDir, "dist", "worker", "worker.js"),
47
+ };
48
+ workerConfig.build.rollupOptions.output = {
49
+ entryFileNames: "worker.js",
50
+ };
51
+ await builder.build(workerEnv);
52
+ console.log("Build complete!");
53
+ }
@@ -1,9 +1,9 @@
1
1
  import { Plugin } from "vite";
2
- export declare const cloudflareBuiltInModules: string[];
3
- export declare const externalModules: string[];
4
- export declare const configPlugin: ({ silent, projectRootDir, clientEntryPathnames, workerEntryPathname, }: {
2
+ export declare const configPlugin: ({ silent, projectRootDir, workerEntryPathname, clientFiles, serverFiles, clientEntryPoints, }: {
5
3
  silent: boolean;
6
4
  projectRootDir: string;
7
- clientEntryPathnames: string[];
8
5
  workerEntryPathname: string;
6
+ clientFiles: Set<string>;
7
+ serverFiles: Set<string>;
8
+ clientEntryPoints: Set<string>;
9
9
  }) => Plugin;