@rainfw/core 0.2.4 → 0.2.6

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 (2) hide show
  1. package/package.json +9 -1
  2. package/scripts/generate.js +89 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainfw/core",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "A TypeScript web framework for Cloudflare Workers",
5
5
  "bin": {
6
6
  "rainjs": "./cli/index.js"
@@ -62,6 +62,14 @@
62
62
  "./client": {
63
63
  "types": "./dist/client/hooks.d.ts",
64
64
  "import": "./dist/client/hooks.js"
65
+ },
66
+ "./client/runtime": {
67
+ "types": "./dist/client/runtime.d.ts",
68
+ "import": "./dist/client/runtime.js"
69
+ },
70
+ "./client/jsx-runtime": {
71
+ "types": "./dist/client/jsx-runtime.d.ts",
72
+ "import": "./dist/client/jsx-runtime.js"
65
73
  }
66
74
  },
67
75
  "devDependencies": {
@@ -213,7 +213,80 @@ function getClientFiles(dir, base = "") {
213
213
  return files;
214
214
  }
215
215
 
216
- function bundleClientFilesSync(clientFiles, srcDir) {
216
+ function ensureRelativeImport(importPath) {
217
+ return importPath.startsWith(".") ? importPath : `./${importPath}`;
218
+ }
219
+
220
+ function buildIslandImportLines(index, file, srcDir, entryDir) {
221
+ const fullPath = path.join(srcDir, file);
222
+ const content = fs.readFileSync(fullPath, "utf-8");
223
+ const { named, hasDefault } = detectAllExportsFromContent(content);
224
+ const islandId = clientFileToIslandId(file);
225
+
226
+ const importPath = path
227
+ .relative(entryDir, path.join(srcDir, file.replace(/\.tsx?$/, "")))
228
+ .replace(/\\/g, "/");
229
+ const safeImport = ensureRelativeImport(importPath);
230
+
231
+ const specifiers = [];
232
+ if (hasDefault) specifiers.push(`default as _d${index}`);
233
+ for (const name of named) specifiers.push(`${name} as _n${index}_${name}`);
234
+ if (specifiers.length === 0) return [];
235
+
236
+ const lines = [];
237
+ lines.push(`import { ${specifiers.join(", ")} } from "${safeImport}";`);
238
+ if (hasDefault) {
239
+ lines.push(`registerIsland("${islandId}:default", _d${index});`);
240
+ }
241
+ for (const name of named) {
242
+ lines.push(`registerIsland("${islandId}:${name}", _n${index}_${name});`);
243
+ }
244
+ return lines;
245
+ }
246
+
247
+ function resolveClientRuntimeImport(fwPkg) {
248
+ if (fwPkg.startsWith(".") || fwPkg.startsWith("/")) {
249
+ const entryDir = path.join(PROJECT_ROOT, BUILD_CONFIG.outDir);
250
+ const runtimePath = path
251
+ .relative(entryDir, path.join(PROJECT_ROOT, fwPkg, "client/runtime"))
252
+ .replace(/\\/g, "/");
253
+ return ensureRelativeImport(runtimePath);
254
+ }
255
+ return `${fwPkg}/client/runtime`;
256
+ }
257
+
258
+ function generateClientEntrySource(clientFiles, srcDir, fwPkg) {
259
+ const entryDir = path.join(PROJECT_ROOT, BUILD_CONFIG.outDir);
260
+ const runtimeImport = resolveClientRuntimeImport(fwPkg);
261
+
262
+ const lines = [];
263
+ lines.push(
264
+ `import { registerIsland, startHydration } from "${runtimeImport}";`,
265
+ );
266
+
267
+ for (let i = 0; i < clientFiles.length; i++) {
268
+ lines.push(...buildIslandImportLines(i, clientFiles[i], srcDir, entryDir));
269
+ }
270
+
271
+ lines.push("startHydration();");
272
+ lines.push("");
273
+
274
+ return lines.join("\n");
275
+ }
276
+
277
+ function buildClientEsbuildAliases(fwPkg) {
278
+ if (fwPkg.startsWith(".") || fwPkg.startsWith("/")) {
279
+ const clientDir = path.resolve(PROJECT_ROOT, fwPkg, "client");
280
+ return {
281
+ "@rainfw/core/jsx-runtime": path.join(clientDir, "jsx-runtime.ts"),
282
+ "@rainfw/core/client/runtime": path.join(clientDir, "runtime.ts"),
283
+ "@rainfw/core/client/jsx-runtime": path.join(clientDir, "jsx-runtime.ts"),
284
+ };
285
+ }
286
+ return {};
287
+ }
288
+
289
+ function bundleClientFilesSync(clientFiles, srcDir, fwPkg) {
217
290
  if (clientFiles.length === 0) return [];
218
291
  if (!esbuild) {
219
292
  console.warn(
@@ -230,33 +303,34 @@ function bundleClientFilesSync(clientFiles, srcDir) {
230
303
  }
231
304
 
232
305
  for (const file of fs.readdirSync(outDir)) {
233
- if (file.startsWith("island-")) {
306
+ if (file.startsWith("island-") || file.startsWith("rain-client-")) {
234
307
  fs.unlinkSync(path.join(outDir, file));
235
308
  }
236
309
  }
237
310
 
238
- const entryPoints = clientFiles.map((f) => path.join(srcDir, f));
311
+ const entrySource = generateClientEntrySource(clientFiles, srcDir, fwPkg);
312
+ const entryDir = path.join(PROJECT_ROOT, BUILD_CONFIG.outDir);
313
+ if (!fs.existsSync(entryDir)) {
314
+ fs.mkdirSync(entryDir, { recursive: true });
315
+ }
316
+ const clientEntryPath = path.join(entryDir, "client-entry.ts");
317
+ fs.writeFileSync(clientEntryPath, entrySource);
239
318
 
240
319
  const result = esbuild.buildSync({
241
- entryPoints,
320
+ entryPoints: [clientEntryPath],
242
321
  outdir: outDir,
243
322
  bundle: true,
244
323
  minify: true,
245
324
  format: "esm",
246
325
  metafile: true,
247
- entryNames: "island-[hash]",
326
+ entryNames: "rain-client-[hash]",
248
327
  write: true,
249
328
  treeShaking: true,
250
329
  platform: "browser",
251
330
  target: ["es2022"],
252
331
  jsx: "automatic",
253
332
  jsxImportSource: "@rainfw/core",
254
- alias: {
255
- "@rainfw/core/jsx-runtime": path.resolve(
256
- PROJECT_ROOT,
257
- "src/framework/client/jsx-runtime.ts",
258
- ),
259
- },
333
+ alias: buildClientEsbuildAliases(fwPkg),
260
334
  loader: { ".ts": "ts", ".tsx": "tsx" },
261
335
  });
262
336
 
@@ -816,7 +890,8 @@ function buildAppInitLine(clientScripts, hasConfig) {
816
890
  function regenerateClient() {
817
891
  const srcDir = path.join(PROJECT_ROOT, "src");
818
892
  const clientFiles = getClientFiles(srcDir);
819
- const clientScripts = bundleClientFilesSync(clientFiles, srcDir);
893
+ const fwPkg = BUILD_CONFIG.frameworkPackage;
894
+ const clientScripts = bundleClientFilesSync(clientFiles, srcDir, fwPkg);
820
895
 
821
896
  if (!fs.existsSync(ENTRY_FILE)) return;
822
897
 
@@ -1052,10 +1127,9 @@ function generate() {
1052
1127
 
1053
1128
  const srcDir = path.join(PROJECT_ROOT, "src");
1054
1129
  const clientFiles = getClientFiles(srcDir);
1055
- const clientScripts = bundleClientFilesSync(clientFiles, srcDir);
1056
-
1057
1130
  const hasConfig = fs.existsSync(CONFIG_FILE);
1058
1131
  const fwPkg = BUILD_CONFIG.frameworkPackage;
1132
+ const clientScripts = bundleClientFilesSync(clientFiles, srcDir, fwPkg);
1059
1133
  const frameworkImport =
1060
1134
  fwPkg.startsWith(".") || fwPkg.startsWith("/")
1061
1135
  ? relativeImportPath(path.join(PROJECT_ROOT, fwPkg))
@@ -1125,6 +1199,7 @@ module.exports = {
1125
1199
  updateWranglerAliases,
1126
1200
  clientFileToIslandId,
1127
1201
  bundleClientFilesSync,
1202
+ generateClientEntrySource,
1128
1203
  validateNoPageRouteColocation,
1129
1204
  validateNoDuplicateUrls,
1130
1205
  stripRouteGroupSegments,