@rainfw/core 0.2.3 → 0.2.5

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/cli/index.js CHANGED
@@ -5,6 +5,7 @@ const fs = require("node:fs");
5
5
  const { spawn } = require("node:child_process");
6
6
 
7
7
  const { stripControlChars } = require("./utils/sanitize");
8
+ const { printBanner } = require("./utils/banner");
8
9
 
9
10
  const PACKAGE_JSON = path.join(__dirname, "..", "package.json");
10
11
  const pkg = JSON.parse(fs.readFileSync(PACKAGE_JSON, "utf-8"));
@@ -44,6 +45,8 @@ if (command === "--version" || command === "-v") {
44
45
  process.exit(0);
45
46
  }
46
47
 
48
+ printBanner();
49
+
47
50
  if (!VALID_COMMANDS.includes(command)) {
48
51
  console.error(
49
52
  `[Rain] Error: Unknown command "${stripControlChars(command)}".\n` +
@@ -0,0 +1,14 @@
1
+ const path = require("node:path");
2
+
3
+ const BRAND_COLOR = "\x1b[38;2;101;187;233m";
4
+ const RESET = "\x1b[0m";
5
+ const version = require(path.join(__dirname, "..", "..", "package.json")).version;
6
+
7
+ function printBanner() {
8
+ console.log(
9
+ `\n ${BRAND_COLOR}\u{1F327}\uFE0F rain.js ${version}${RESET}`,
10
+ );
11
+ console.log(`${BRAND_COLOR}${"─".repeat(20)}${RESET}\n`);
12
+ }
13
+
14
+ module.exports = { printBanner, version, BRAND_COLOR, RESET };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainfw/core",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "A TypeScript web framework for Cloudflare Workers",
5
5
  "bin": {
6
6
  "rainjs": "./cli/index.js"
package/scripts/dev.js CHANGED
@@ -2,9 +2,12 @@ const fs = require("node:fs");
2
2
  const path = require("node:path");
3
3
  const { spawn } = require("node:child_process");
4
4
  const { generate, regenerateClient, ROUTES_DIR } = require("./generate");
5
+ const { printBanner } = require("../cli/utils/banner");
5
6
 
6
7
  const SRC_DIR = path.join(process.cwd(), "src");
7
8
 
9
+ printBanner();
10
+
8
11
  generate();
9
12
 
10
13
  let debounceTimer = null;
@@ -2,6 +2,7 @@ const fs = require("node:fs");
2
2
  const path = require("node:path");
3
3
  const { execSync } = require("node:child_process");
4
4
  const ts = require("typescript");
5
+ const { printBanner } = require("../cli/utils/banner");
5
6
 
6
7
  let esbuild;
7
8
  try {
@@ -212,6 +213,59 @@ function getClientFiles(dir, base = "") {
212
213
  return files;
213
214
  }
214
215
 
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 generateClientEntrySource(clientFiles, srcDir) {
248
+ const entryDir = path.join(PROJECT_ROOT, BUILD_CONFIG.outDir);
249
+ const runtimePath = path
250
+ .relative(entryDir, path.join(PROJECT_ROOT, "src/framework/client/runtime"))
251
+ .replace(/\\/g, "/");
252
+ const runtimeImport = ensureRelativeImport(runtimePath);
253
+
254
+ const lines = [];
255
+ lines.push(
256
+ `import { registerIsland, startHydration } from "${runtimeImport}";`,
257
+ );
258
+
259
+ for (let i = 0; i < clientFiles.length; i++) {
260
+ lines.push(...buildIslandImportLines(i, clientFiles[i], srcDir, entryDir));
261
+ }
262
+
263
+ lines.push("startHydration();");
264
+ lines.push("");
265
+
266
+ return lines.join("\n");
267
+ }
268
+
215
269
  function bundleClientFilesSync(clientFiles, srcDir) {
216
270
  if (clientFiles.length === 0) return [];
217
271
  if (!esbuild) {
@@ -229,21 +283,27 @@ function bundleClientFilesSync(clientFiles, srcDir) {
229
283
  }
230
284
 
231
285
  for (const file of fs.readdirSync(outDir)) {
232
- if (file.startsWith("island-")) {
286
+ if (file.startsWith("island-") || file.startsWith("rain-client-")) {
233
287
  fs.unlinkSync(path.join(outDir, file));
234
288
  }
235
289
  }
236
290
 
237
- const entryPoints = clientFiles.map((f) => path.join(srcDir, f));
291
+ const entrySource = generateClientEntrySource(clientFiles, srcDir);
292
+ const entryDir = path.join(PROJECT_ROOT, BUILD_CONFIG.outDir);
293
+ if (!fs.existsSync(entryDir)) {
294
+ fs.mkdirSync(entryDir, { recursive: true });
295
+ }
296
+ const clientEntryPath = path.join(entryDir, "client-entry.ts");
297
+ fs.writeFileSync(clientEntryPath, entrySource);
238
298
 
239
299
  const result = esbuild.buildSync({
240
- entryPoints,
300
+ entryPoints: [clientEntryPath],
241
301
  outdir: outDir,
242
302
  bundle: true,
243
303
  minify: true,
244
304
  format: "esm",
245
305
  metafile: true,
246
- entryNames: "island-[hash]",
306
+ entryNames: "rain-client-[hash]",
247
307
  write: true,
248
308
  treeShaking: true,
249
309
  platform: "browser",
@@ -1124,6 +1184,7 @@ module.exports = {
1124
1184
  updateWranglerAliases,
1125
1185
  clientFileToIslandId,
1126
1186
  bundleClientFilesSync,
1187
+ generateClientEntrySource,
1127
1188
  validateNoPageRouteColocation,
1128
1189
  validateNoDuplicateUrls,
1129
1190
  stripRouteGroupSegments,
@@ -1133,5 +1194,6 @@ module.exports = {
1133
1194
  };
1134
1195
 
1135
1196
  if (require.main === module) {
1197
+ printBanner();
1136
1198
  generate();
1137
1199
  }