rwsdk 1.0.0-alpha.11 → 1.0.0-alpha.12

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.
@@ -124,3 +124,9 @@ export declare namespace testDevAndDeploy {
124
124
  * This should be used before any user interaction is simulated.
125
125
  */
126
126
  export declare function waitForHydration(page: Page): Promise<void>;
127
+ export declare function trackPageErrors(page: Page): {
128
+ get: () => {
129
+ consoleErrors: string[];
130
+ failedRequests: string[];
131
+ };
132
+ };
@@ -416,3 +416,22 @@ export async function waitForHydration(page) {
416
416
  // This is a pragmatic approach to ensure React has mounted.
417
417
  await new Promise((resolve) => setTimeout(resolve, HYDRATION_TIMEOUT));
418
418
  }
419
+ export function trackPageErrors(page) {
420
+ const consoleErrors = [];
421
+ const failedRequests = [];
422
+ page.on("requestfailed", (request) => {
423
+ failedRequests.push(`${request.url()} | ${request.failure()?.errorText}`);
424
+ });
425
+ page.on("console", (msg) => {
426
+ if (msg.type() === "error") {
427
+ consoleErrors.push(msg.text());
428
+ }
429
+ });
430
+ return {
431
+ get: () => ({
432
+ // context(justinvdm, 25 Sep 2025): Filter out irrelevant 404s (e.g. favicon)
433
+ consoleErrors: consoleErrors.filter((e) => !e.includes("404")),
434
+ failedRequests,
435
+ }),
436
+ };
437
+ }
@@ -9,6 +9,7 @@ export function registerServerReference(action, id, name) {
9
9
  // Note: We no longer need to register in a Map since we use virtual lookup
10
10
  return baseRegisterServerReference(action, id, name);
11
11
  }
12
+ const isComponent = (target) => isValidElementType(target) && target?.toString().includes("jsx");
12
13
  export function registerClientReference(ssrModule, id, exportName) {
13
14
  const target = ssrModule[exportName] ?? {};
14
15
  if (isValidElementType(target)) {
@@ -31,7 +32,13 @@ export function registerClientReference(ssrModule, id, exportName) {
31
32
  }
32
33
  finalDescriptors.$$async = { value: true };
33
34
  finalDescriptors.$$isClientReference = { value: true };
34
- return Object.defineProperties(() => null, finalDescriptors);
35
+ // context(justinvdm, 25 Sep 2025): We create a wrapper function to avoid
36
+ // getting the SSR component's property descriptors - otherwise
37
+ // this will take precedence over the client reference descriptors
38
+ const fn = typeof target === "function"
39
+ ? (...args) => target(...args)
40
+ : () => null;
41
+ return Object.defineProperties(fn, finalDescriptors);
35
42
  }
36
43
  // For non-components, return the target object directly for use in SSR.
37
44
  return target;
@@ -84,7 +84,7 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
84
84
  env.optimizeDeps.include ??= [];
85
85
  const entries = (env.optimizeDeps.entries = castArray(env.optimizeDeps.entries ?? []));
86
86
  env.optimizeDeps.include.push(VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH);
87
- if (envName === "client") {
87
+ if (envName === "client" || envName === "ssr") {
88
88
  entries.push(APP_CLIENT_BARREL_PATH);
89
89
  }
90
90
  else if (envName === "worker") {
@@ -17,11 +17,12 @@ export declare function classifyModule({ contents, inheritedEnv, }: {
17
17
  isClient: boolean;
18
18
  isServer: boolean;
19
19
  };
20
+ export type EsbuildLoader = "js" | "jsx" | "ts" | "tsx" | "default";
20
21
  export declare const runDirectivesScan: ({ rootConfig, environments, clientFiles, serverFiles, entries: initialEntries, }: {
21
22
  rootConfig: ResolvedConfig;
22
23
  environments: Record<string, Environment>;
23
24
  clientFiles: Set<string>;
24
25
  serverFiles: Set<string>;
25
- entries: string[];
26
+ entries?: string[];
26
27
  }) => Promise<void>;
27
28
  export {};
@@ -7,6 +7,7 @@ import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
7
7
  import { INTERMEDIATES_OUTPUT_DIR } from "../lib/constants.mjs";
8
8
  import { externalModules } from "./constants.mjs";
9
9
  import { createViteAwareResolver } from "./createViteAwareResolver.mjs";
10
+ import { compile } from "@mdx-js/mdx";
10
11
  const log = debug("rwsdk:vite:run-directives-scan");
11
12
  // Copied from Vite's source code.
12
13
  // https://github.com/vitejs/vite/blob/main/packages/vite/src/shared/utils.ts
@@ -50,7 +51,7 @@ export function classifyModule({ contents, inheritedEnv, }) {
50
51
  return { moduleEnv, isClient, isServer };
51
52
  }
52
53
  export const runDirectivesScan = async ({ rootConfig, environments, clientFiles, serverFiles, entries: initialEntries, }) => {
53
- console.log("\n🔍 Scanning for 'use client' and 'use server' directives...");
54
+ deferredLog("\n (rwsdk) Scanning for 'use client' and 'use server' directives...");
54
55
  // Set environment variable to indicate scanning is in progress
55
56
  process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE = "true";
56
57
  try {
@@ -94,7 +95,7 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
94
95
  setup(build) {
95
96
  // Match Vite's behavior by externalizing assets and special queries.
96
97
  // This prevents esbuild from trying to bundle them, which would fail.
97
- const scriptFilter = /\.(c|m)?[jt]sx?$/;
98
+ const scriptFilter = /\.(c|m)?[jt]sx?$|\.mdx$/;
98
99
  const specialQueryFilter = /[?&](?:url|raw|worker|sharedworker|inline)\b/;
99
100
  // This regex is used to identify if a path has any file extension.
100
101
  const hasExtensionRegex = /\.[^/]+$/;
@@ -162,7 +163,7 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
162
163
  log("Marking as external:", args.path, "resolved to:", resolvedPath);
163
164
  return { external: true };
164
165
  });
165
- build.onLoad({ filter: /\.(m|c)?[jt]sx?$/ }, async (args) => {
166
+ build.onLoad({ filter: /\.(m|c)?[jt]sx?$|\.mdx$/ }, async (args) => {
166
167
  log("onLoad called for:", args.path);
167
168
  if (!args.path.startsWith("/") ||
168
169
  args.path.includes("virtual:") ||
@@ -175,10 +176,10 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
175
176
  return null;
176
177
  }
177
178
  try {
178
- const contents = await readFileWithCache(args.path);
179
+ const originalContents = await readFileWithCache(args.path);
179
180
  const inheritedEnv = args.pluginData?.inheritedEnv || "worker";
180
181
  const { moduleEnv, isClient, isServer } = classifyModule({
181
- contents,
182
+ contents: originalContents,
182
183
  inheritedEnv,
183
184
  });
184
185
  // Store the definitive environment for this module, so it can be used when it becomes an importer.
@@ -194,7 +195,33 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
194
195
  log("Discovered 'use server' in:", realPath);
195
196
  serverFiles.add(normalizeModulePath(realPath, rootConfig.root));
196
197
  }
197
- return { contents, loader: "default" };
198
+ let code;
199
+ let loader;
200
+ if (args.path.endsWith(".mdx")) {
201
+ const result = await compile(originalContents, {
202
+ jsx: true,
203
+ jsxImportSource: "react",
204
+ });
205
+ code = String(result.value);
206
+ loader = "tsx";
207
+ }
208
+ else if (/\.(m|c)?tsx$/.test(args.path)) {
209
+ code = originalContents;
210
+ loader = "tsx";
211
+ }
212
+ else if (/\.(m|c)?ts$/.test(args.path)) {
213
+ code = originalContents;
214
+ loader = "ts";
215
+ }
216
+ else if (/\.(m|c)?jsx$/.test(args.path)) {
217
+ code = originalContents;
218
+ loader = "jsx";
219
+ }
220
+ else {
221
+ code = originalContents;
222
+ loader = "js";
223
+ }
224
+ return { contents: code, loader };
198
225
  }
199
226
  catch (e) {
200
227
  log("Could not read file during scan, skipping:", args.path, e);
@@ -220,8 +247,13 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
220
247
  finally {
221
248
  // Always clear the scanning flag when done
222
249
  delete process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE;
223
- console.log(" Scan complete.");
250
+ deferredLog(" (rwsdk) Done scanning for 'use client' and 'use server' directives.");
224
251
  process.env.VERBOSE &&
225
252
  log("Client/server files after scanning: client=%O, server=%O", Array.from(clientFiles), Array.from(serverFiles));
226
253
  }
227
254
  };
255
+ const deferredLog = (message) => {
256
+ setTimeout(() => {
257
+ console.log(message);
258
+ }, 500);
259
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rwsdk",
3
- "version": "1.0.0-alpha.11",
3
+ "version": "1.0.0-alpha.12",
4
4
  "description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
5
5
  "type": "module",
6
6
  "bin": {
@@ -134,6 +134,7 @@
134
134
  "dependencies": {
135
135
  "@ast-grep/napi": "^0.38.5",
136
136
  "@cloudflare/workers-types": "^4.20250407.0",
137
+ "@mdx-js/mdx": "^3.1.1",
137
138
  "@puppeteer/browsers": "^2.8.0",
138
139
  "@types/fs-extra": "^11.0.4",
139
140
  "@types/react": "^19.1.2",