rwsdk 0.1.0-alpha.1 → 0.1.0-alpha.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/runtime/entries/clientSSR.d.ts +1 -0
- package/dist/runtime/entries/clientSSR.js +1 -0
- package/dist/vite/configPlugin.mjs +0 -4
- package/dist/vite/directivesPlugin.d.mts +6 -0
- package/dist/vite/directivesPlugin.mjs +80 -0
- package/dist/vite/redwoodPlugin.mjs +2 -2
- package/dist/vite/transformClientComponents.mjs +19 -14
- package/dist/vite/transformClientComponents.test.mjs +18 -4
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../lib/streams/consumeEventStream";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../lib/streams/consumeEventStream";
|
|
@@ -113,10 +113,6 @@ export const configPlugin = ({ mode, silent, projectRootDir, clientEntryPathname
|
|
|
113
113
|
server: {
|
|
114
114
|
hmr: true,
|
|
115
115
|
},
|
|
116
|
-
resolve: {
|
|
117
|
-
conditions: ["workerd"],
|
|
118
|
-
alias: [],
|
|
119
|
-
},
|
|
120
116
|
builder: {
|
|
121
117
|
buildApp: async (builder) => {
|
|
122
118
|
// note(justinvdm, 27 May 2025): **Ordering is important**:
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import debug from "debug";
|
|
2
|
+
import { transformClientComponents } from "./transformClientComponents.mjs";
|
|
3
|
+
import { transformServerFunctions } from "./transformServerFunctions.mjs";
|
|
4
|
+
import { normalizeModulePath } from "./normalizeModulePath.mjs";
|
|
5
|
+
const log = debug("rwsdk:vite:rsc-directives-plugin");
|
|
6
|
+
const verboseLog = debug("verbose:rwsdk:vite:rsc-directives-plugin");
|
|
7
|
+
export const directivesPlugin = ({ projectRootDir, clientFiles, serverFiles, }) => ({
|
|
8
|
+
name: "rwsdk:rsc-directives",
|
|
9
|
+
async transform(code, id) {
|
|
10
|
+
verboseLog("Transform called for id=%s, environment=%s", id, this.environment.name);
|
|
11
|
+
const normalizedId = normalizeModulePath(projectRootDir, id);
|
|
12
|
+
const clientResult = await transformClientComponents(code, normalizedId, {
|
|
13
|
+
environmentName: this.environment.name,
|
|
14
|
+
clientFiles,
|
|
15
|
+
});
|
|
16
|
+
if (clientResult) {
|
|
17
|
+
log("Client component transformation successful for id=%s", id);
|
|
18
|
+
return {
|
|
19
|
+
code: clientResult.code,
|
|
20
|
+
map: clientResult.map,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const serverResult = transformServerFunctions(code, normalizedId, this.environment.name, serverFiles);
|
|
24
|
+
if (serverResult) {
|
|
25
|
+
log("Server function transformation successful for id=%s", id);
|
|
26
|
+
return {
|
|
27
|
+
code: serverResult.code,
|
|
28
|
+
map: serverResult.map,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
verboseLog("No transformation applied for id=%s", id);
|
|
32
|
+
},
|
|
33
|
+
configEnvironment(env, config) {
|
|
34
|
+
log("Configuring environment: env=%s", env);
|
|
35
|
+
config.optimizeDeps ??= {};
|
|
36
|
+
config.optimizeDeps.esbuildOptions ??= {};
|
|
37
|
+
config.optimizeDeps.esbuildOptions.plugins ??= [];
|
|
38
|
+
config.optimizeDeps.esbuildOptions.plugins.push({
|
|
39
|
+
name: "rsc-directives-esbuild-transform",
|
|
40
|
+
setup(build) {
|
|
41
|
+
log("Setting up esbuild plugin for environment: %s", env);
|
|
42
|
+
build.onLoad({ filter: /.*\.js$/ }, async (args) => {
|
|
43
|
+
verboseLog("Esbuild onLoad called for path=%s", args.path);
|
|
44
|
+
const fs = await import("node:fs/promises");
|
|
45
|
+
const path = await import("node:path");
|
|
46
|
+
let code;
|
|
47
|
+
try {
|
|
48
|
+
code = await fs.readFile(args.path, "utf-8");
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
verboseLog("Failed to read file: %s", args.path);
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const clientResult = await transformClientComponents(code, normalizeModulePath(projectRootDir, args.path), {
|
|
55
|
+
environmentName: env,
|
|
56
|
+
clientFiles,
|
|
57
|
+
isEsbuild: true,
|
|
58
|
+
});
|
|
59
|
+
if (clientResult) {
|
|
60
|
+
log("Esbuild client component transformation successful for path=%s", args.path);
|
|
61
|
+
return {
|
|
62
|
+
contents: clientResult.code,
|
|
63
|
+
loader: path.extname(args.path).slice(1),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const serverResult = transformServerFunctions(code, normalizeModulePath(projectRootDir, args.path), env, serverFiles);
|
|
67
|
+
if (serverResult) {
|
|
68
|
+
log("Esbuild server function transformation successful for path=%s", args.path);
|
|
69
|
+
return {
|
|
70
|
+
contents: serverResult.code,
|
|
71
|
+
loader: path.extname(args.path).slice(1),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
verboseLog("Esbuild no transformation applied for path=%s", args.path);
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
log("Environment configuration complete for env=%s", env);
|
|
79
|
+
},
|
|
80
|
+
});
|
|
@@ -2,7 +2,7 @@ import { resolve } from "node:path";
|
|
|
2
2
|
import reactPlugin from "@vitejs/plugin-react";
|
|
3
3
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
4
4
|
import { transformJsxScriptTagsPlugin } from "./transformJsxScriptTagsPlugin.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { directivesPlugin } from "./directivesPlugin.mjs";
|
|
6
6
|
import { useClientLookupPlugin } from "./useClientLookupPlugin.mjs";
|
|
7
7
|
import { useServerLookupPlugin } from "./useServerLookupPlugin.mjs";
|
|
8
8
|
import { miniflarePlugin } from "./miniflarePlugin.mjs";
|
|
@@ -56,7 +56,7 @@ export const redwoodPlugin = async (options = {}) => {
|
|
|
56
56
|
configPath: options.configPath ?? (await findWranglerConfig(projectRootDir)),
|
|
57
57
|
}),
|
|
58
58
|
reactPlugin(),
|
|
59
|
-
|
|
59
|
+
directivesPlugin({
|
|
60
60
|
projectRootDir,
|
|
61
61
|
clientFiles,
|
|
62
62
|
serverFiles,
|
|
@@ -48,13 +48,17 @@ export async function transformClientComponents(code, normalizedId, ctx) {
|
|
|
48
48
|
const sourceFile = project.createSourceFile(normalizedId + ".ts", code);
|
|
49
49
|
const exportInfos = [];
|
|
50
50
|
let defaultExportInfo;
|
|
51
|
+
// Helper to get the computed local name (with alias suffix if present)
|
|
52
|
+
function getComputedLocalName(info) {
|
|
53
|
+
return `${info.local}${info.alias ? `_${info.alias}` : ""}`;
|
|
54
|
+
}
|
|
51
55
|
// Helper to add export info
|
|
52
|
-
function addExport(local, exported, isDefault, statementIdx) {
|
|
56
|
+
function addExport(local, exported, isDefault, statementIdx, alias) {
|
|
53
57
|
if (isDefault) {
|
|
54
58
|
defaultExportInfo = { local, exported, isDefault, statementIdx };
|
|
55
59
|
}
|
|
56
60
|
else {
|
|
57
|
-
exportInfos.push({ local, exported, isDefault, statementIdx });
|
|
61
|
+
exportInfos.push({ local, exported, isDefault, statementIdx, alias });
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
// Walk through statements in order to collect export information
|
|
@@ -106,13 +110,10 @@ export async function transformClientComponents(code, normalizedId, ctx) {
|
|
|
106
110
|
const namedExports = stmt.getNamedExports();
|
|
107
111
|
if (namedExports.length > 0) {
|
|
108
112
|
namedExports.forEach((exp) => {
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
? exp.getAliasNode().getText()
|
|
114
|
-
: exp.getName();
|
|
115
|
-
addExport(local, exported, exported === "default", idx);
|
|
113
|
+
const alias = exp.getAliasNode()?.getText();
|
|
114
|
+
const local = alias ? exp.getNameNode().getText() : exp.getName();
|
|
115
|
+
const exported = alias ? alias : exp.getName();
|
|
116
|
+
addExport(local, exported, exported === "default", idx, alias);
|
|
116
117
|
});
|
|
117
118
|
}
|
|
118
119
|
return;
|
|
@@ -148,14 +149,18 @@ export async function transformClientComponents(code, normalizedId, ctx) {
|
|
|
148
149
|
moduleSpecifier: "rwsdk/worker",
|
|
149
150
|
namedImports: [{ name: "registerClientReference" }],
|
|
150
151
|
});
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
// Compute unique computed local names first
|
|
153
|
+
const computedLocalNames = new Map(exportInfos.map((info) => [getComputedLocalName(info), info]));
|
|
154
|
+
// Add registerClientReference assignments for unique names
|
|
155
|
+
for (const [computedLocalName, correspondingInfo] of computedLocalNames) {
|
|
156
|
+
log(":isEsbuild=%s: Registering client reference for named export: %s as %s", !!ctx.isEsbuild, correspondingInfo.local, correspondingInfo.exported);
|
|
157
|
+
sourceFile.addStatements(`const ${computedLocalName} = registerClientReference("${normalizedId}", "${correspondingInfo.exported}");`);
|
|
155
158
|
}
|
|
156
159
|
// Add grouped export statement for named exports (preserving order and alias)
|
|
157
160
|
if (exportInfos.length > 0) {
|
|
158
|
-
const exportNames =
|
|
161
|
+
const exportNames = Array.from(computedLocalNames.entries()).map(([computedLocalName, correspondingInfo]) => correspondingInfo.local === correspondingInfo.exported
|
|
162
|
+
? computedLocalName
|
|
163
|
+
: `${computedLocalName} as ${correspondingInfo.exported}`);
|
|
159
164
|
log(":isEsbuild=%s: Exporting named exports: %O", !!ctx.isEsbuild, exportNames);
|
|
160
165
|
sourceFile.addStatements(`export { ${exportNames.join(", ")} };`);
|
|
161
166
|
}
|
|
@@ -85,8 +85,8 @@ export { Fourth as AnotherName }`)) ?? "").toEqual(`import { registerClientRefer
|
|
|
85
85
|
const First = registerClientReference("/test/file.tsx", "First");
|
|
86
86
|
const Second = registerClientReference("/test/file.tsx", "Second");
|
|
87
87
|
const Third = registerClientReference("/test/file.tsx", "Third");
|
|
88
|
-
const
|
|
89
|
-
export { First, Second, Third,
|
|
88
|
+
const Fourth_AnotherName = registerClientReference("/test/file.tsx", "AnotherName");
|
|
89
|
+
export { First, Second, Third, Fourth_AnotherName as AnotherName };
|
|
90
90
|
export default registerClientReference("/test/file.tsx", "default");
|
|
91
91
|
`);
|
|
92
92
|
});
|
|
@@ -199,8 +199,8 @@ const MyComponent = () => {
|
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
export { MyComponent as CustomName }`)) ?? "").toEqual(`import { registerClientReference } from "rwsdk/worker";
|
|
202
|
-
const
|
|
203
|
-
export {
|
|
202
|
+
const MyComponent_CustomName = registerClientReference("/test/file.tsx", "CustomName");
|
|
203
|
+
export { MyComponent_CustomName as CustomName };
|
|
204
204
|
`);
|
|
205
205
|
});
|
|
206
206
|
it("correctly processes multiple component exports", async () => {
|
|
@@ -229,6 +229,20 @@ const Component = registerClientReference("/test/file.tsx", "Component");
|
|
|
229
229
|
const data = registerClientReference("/test/file.tsx", "data");
|
|
230
230
|
const helper = registerClientReference("/test/file.tsx", "helper");
|
|
231
231
|
export { Component, data, helper };
|
|
232
|
+
`);
|
|
233
|
+
});
|
|
234
|
+
it("transforms multiple exports aliases for the same component", async () => {
|
|
235
|
+
expect((await transform(`"use client"
|
|
236
|
+
|
|
237
|
+
export const Slot = () => {
|
|
238
|
+
return jsx('div', { children: 'Slot' });
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export { Slot, Slot as Root }
|
|
242
|
+
`)) ?? "").toEqual(`import { registerClientReference } from "rwsdk/worker";
|
|
243
|
+
const Slot = registerClientReference("/test/file.tsx", "Slot");
|
|
244
|
+
const Slot_Root = registerClientReference("/test/file.tsx", "Root");
|
|
245
|
+
export { Slot, Slot_Root as Root };
|
|
232
246
|
`);
|
|
233
247
|
});
|
|
234
248
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rwsdk",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
4
|
"description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"./client": {
|
|
24
24
|
"react-server": "./dist/runtime/entries/no-react-server.js",
|
|
25
|
+
"workerd": "./dist/runtime/entries/clientSSR.js",
|
|
25
26
|
"types": "./dist/runtime/entries/client.d.ts",
|
|
26
27
|
"default": "./dist/runtime/entries/client.js"
|
|
27
28
|
},
|