@rainfw/core 0.1.2 → 0.2.0

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/client/dom.d.ts +4 -0
  2. package/dist/client/dom.d.ts.map +1 -0
  3. package/dist/client/dom.js +130 -0
  4. package/dist/client/dom.js.map +1 -0
  5. package/dist/client/hooks.d.ts +58 -0
  6. package/dist/client/hooks.d.ts.map +1 -0
  7. package/dist/client/hooks.js +173 -0
  8. package/dist/client/hooks.js.map +1 -0
  9. package/dist/client/hydrate.d.ts +14 -0
  10. package/dist/client/hydrate.d.ts.map +1 -0
  11. package/dist/client/hydrate.js +167 -0
  12. package/dist/client/hydrate.js.map +1 -0
  13. package/dist/client/jsx-runtime.d.ts +6 -0
  14. package/dist/client/jsx-runtime.d.ts.map +1 -0
  15. package/dist/client/jsx-runtime.js +20 -0
  16. package/dist/client/jsx-runtime.js.map +1 -0
  17. package/dist/client/reconciler.d.ts +4 -0
  18. package/dist/client/reconciler.d.ts.map +1 -0
  19. package/dist/client/reconciler.js +238 -0
  20. package/dist/client/reconciler.js.map +1 -0
  21. package/dist/client/runtime.d.ts +6 -0
  22. package/dist/client/runtime.d.ts.map +1 -0
  23. package/dist/client/runtime.js +17 -0
  24. package/dist/client/runtime.js.map +1 -0
  25. package/dist/client/scheduler.d.ts +4 -0
  26. package/dist/client/scheduler.d.ts.map +1 -0
  27. package/dist/client/scheduler.js +44 -0
  28. package/dist/client/scheduler.js.map +1 -0
  29. package/dist/compiler/inject.d.ts +6 -0
  30. package/dist/compiler/inject.d.ts.map +1 -0
  31. package/dist/compiler/inject.js +19 -0
  32. package/dist/compiler/inject.js.map +1 -0
  33. package/dist/compiler/server-action.d.ts +9 -0
  34. package/dist/compiler/server-action.d.ts.map +1 -0
  35. package/dist/compiler/server-action.js +98 -0
  36. package/dist/compiler/server-action.js.map +1 -0
  37. package/dist/context.js +1 -1
  38. package/dist/context.js.map +1 -1
  39. package/dist/index.d.ts +5 -3
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +2 -1
  42. package/dist/index.js.map +1 -1
  43. package/dist/jsx/index.d.ts +3 -2
  44. package/dist/jsx/index.d.ts.map +1 -1
  45. package/dist/jsx/index.js +2 -2
  46. package/dist/jsx/index.js.map +1 -1
  47. package/dist/jsx/render.d.ts +7 -1
  48. package/dist/jsx/render.d.ts.map +1 -1
  49. package/dist/jsx/render.js +96 -14
  50. package/dist/jsx/render.js.map +1 -1
  51. package/dist/jsx/types.d.ts +4 -0
  52. package/dist/jsx/types.d.ts.map +1 -1
  53. package/dist/jsx/types.js +10 -0
  54. package/dist/jsx/types.js.map +1 -1
  55. package/dist/router.d.ts +7 -1
  56. package/dist/router.d.ts.map +1 -1
  57. package/dist/router.js +84 -3
  58. package/dist/router.js.map +1 -1
  59. package/dist/types.d.ts +2 -0
  60. package/dist/types.d.ts.map +1 -1
  61. package/package.json +5 -1
  62. package/scripts/dev.js +28 -1
  63. package/scripts/generate.js +150 -10
@@ -3,6 +3,13 @@ const path = require("node:path");
3
3
  const { execSync } = require("node:child_process");
4
4
  const ts = require("typescript");
5
5
 
6
+ let esbuild;
7
+ try {
8
+ esbuild = require("esbuild");
9
+ } catch (_esbuildOptional) {
10
+ esbuild = null;
11
+ }
12
+
6
13
  const PROJECT_ROOT = process.cwd();
7
14
 
8
15
  function unwrapExpression(node) {
@@ -166,6 +173,104 @@ function middlewarePathToDir(filePath) {
166
173
  .replace(/\/$/, "");
167
174
  }
168
175
 
176
+ function detectUseClientDirective(content) {
177
+ const sourceFile = ts.createSourceFile(
178
+ "file.tsx",
179
+ content,
180
+ ts.ScriptTarget.Latest,
181
+ true,
182
+ );
183
+ const firstStatement = sourceFile.statements[0];
184
+ if (!firstStatement) return false;
185
+ return (
186
+ ts.isExpressionStatement(firstStatement) &&
187
+ ts.isStringLiteral(firstStatement.expression) &&
188
+ firstStatement.expression.text === "use client"
189
+ );
190
+ }
191
+
192
+ function getClientFiles(dir, base = "") {
193
+ if (!fs.existsSync(dir)) return [];
194
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
195
+ const files = [];
196
+
197
+ for (const entry of entries) {
198
+ const fullPath = path.join(dir, entry.name);
199
+ const relativePath = path.join(base, entry.name);
200
+
201
+ if (entry.isDirectory()) {
202
+ if (entry.name === "node_modules" || entry.name === ".rainjs") continue;
203
+ files.push(...getClientFiles(fullPath, relativePath));
204
+ } else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
205
+ const content = fs.readFileSync(fullPath, "utf-8");
206
+ if (detectUseClientDirective(content)) {
207
+ files.push(relativePath);
208
+ }
209
+ }
210
+ }
211
+
212
+ return files;
213
+ }
214
+
215
+ function bundleClientFilesSync(clientFiles, srcDir) {
216
+ if (clientFiles.length === 0) return [];
217
+ if (!esbuild) {
218
+ console.warn(
219
+ "[Rain] Warning: esbuild not found.\n" +
220
+ " → Install esbuild to enable client bundling: npm install -D esbuild\n" +
221
+ " → Client-side components will not be bundled.",
222
+ );
223
+ return [];
224
+ }
225
+
226
+ const outDir = path.join(PROJECT_ROOT, "public", "_rain");
227
+ if (!fs.existsSync(outDir)) {
228
+ fs.mkdirSync(outDir, { recursive: true });
229
+ }
230
+
231
+ for (const file of fs.readdirSync(outDir)) {
232
+ if (file.startsWith("island-")) {
233
+ fs.unlinkSync(path.join(outDir, file));
234
+ }
235
+ }
236
+
237
+ const entryPoints = clientFiles.map((f) => path.join(srcDir, f));
238
+
239
+ const result = esbuild.buildSync({
240
+ entryPoints,
241
+ outdir: outDir,
242
+ bundle: true,
243
+ minify: true,
244
+ format: "esm",
245
+ metafile: true,
246
+ entryNames: "island-[hash]",
247
+ write: true,
248
+ treeShaking: true,
249
+ platform: "browser",
250
+ target: ["es2022"],
251
+ jsx: "automatic",
252
+ jsxImportSource: "@rainfw/core",
253
+ alias: {
254
+ "@rainfw/core/jsx-runtime": path.resolve(
255
+ PROJECT_ROOT,
256
+ "src/framework/client/jsx-runtime.ts",
257
+ ),
258
+ },
259
+ loader: { ".ts": "ts", ".tsx": "tsx" },
260
+ });
261
+
262
+ const publicDir = path.join(PROJECT_ROOT, "public");
263
+ const scripts = [];
264
+ for (const [outPath, meta] of Object.entries(result.metafile.outputs)) {
265
+ if (meta.entryPoint) {
266
+ const relPath = path.relative(publicDir, outPath);
267
+ scripts.push(`/${relPath.replace(/\\/g, "/")}`);
268
+ }
269
+ }
270
+
271
+ return scripts;
272
+ }
273
+
169
274
  function routePathToDir(filePath) {
170
275
  return filePath
171
276
  .replace(/\\/g, "/")
@@ -546,13 +651,9 @@ function validateCompatibilityFlags() {
546
651
  if (!fs.existsSync(wranglerPath)) return;
547
652
 
548
653
  const content = fs.readFileSync(wranglerPath, "utf-8");
549
- const flagsMatch = content.match(
550
- /compatibility_flags\s*=\s*\[([^\]]*)\]/,
551
- );
654
+ const flagsMatch = content.match(/compatibility_flags\s*=\s*\[([^\]]*)\]/);
552
655
  const flags = flagsMatch
553
- ? (flagsMatch[1].match(/"([^"]+)"/g) || []).map((s) =>
554
- s.replace(/"/g, ""),
555
- )
656
+ ? (flagsMatch[1].match(/"([^"]+)"/g) || []).map((s) => s.replace(/"/g, ""))
556
657
  : [];
557
658
 
558
659
  if (!(flags.includes("nodejs_compat") || flags.includes("nodejs_als"))) {
@@ -571,6 +672,37 @@ function validateCompatibilityFlags() {
571
672
  }
572
673
  }
573
674
 
675
+ function buildAppInitLine(clientScripts, hasConfig) {
676
+ if (hasConfig) {
677
+ return clientScripts.length > 0
678
+ ? `const app = new Rain({ ...config, clientScripts: ${JSON.stringify(clientScripts)} });`
679
+ : "const app = new Rain(config);";
680
+ }
681
+ return clientScripts.length > 0
682
+ ? `const app = new Rain({ clientScripts: ${JSON.stringify(clientScripts)} });`
683
+ : "const app = new Rain();";
684
+ }
685
+
686
+ function regenerateClient() {
687
+ const srcDir = path.join(PROJECT_ROOT, "src");
688
+ const clientFiles = getClientFiles(srcDir);
689
+ const clientScripts = bundleClientFilesSync(clientFiles, srcDir);
690
+
691
+ if (!fs.existsSync(ENTRY_FILE)) return;
692
+
693
+ const content = fs.readFileSync(ENTRY_FILE, "utf-8");
694
+ const hasConfig = fs.existsSync(CONFIG_FILE);
695
+ const appInit = buildAppInitLine(clientScripts, hasConfig);
696
+ const updated = content.replace(/^const app = new Rain\(.*\);$/m, appInit);
697
+ if (updated !== content) {
698
+ fs.writeFileSync(ENTRY_FILE, updated);
699
+ }
700
+
701
+ const clientMsg =
702
+ clientFiles.length > 0 ? `${clientFiles.length} client` : "0 client";
703
+ console.log(`[gen:client] ${clientMsg} -> .rainjs/entry.ts`);
704
+ }
705
+
574
706
  function generate() {
575
707
  if (!fs.existsSync(ROUTES_DIR)) {
576
708
  console.error(
@@ -632,6 +764,10 @@ function generate() {
632
764
  registrations,
633
765
  );
634
766
 
767
+ const srcDir = path.join(PROJECT_ROOT, "src");
768
+ const clientFiles = getClientFiles(srcDir);
769
+ const clientScripts = bundleClientFilesSync(clientFiles, srcDir);
770
+
635
771
  const hasConfig = fs.existsSync(CONFIG_FILE);
636
772
  const fwPkg = BUILD_CONFIG.frameworkPackage;
637
773
  const frameworkImport =
@@ -647,9 +783,7 @@ function generate() {
647
783
  headerImports.push(`import config from "${configPath}";`);
648
784
  }
649
785
 
650
- const appInit = hasConfig
651
- ? "const app = new Rain(config);"
652
- : "const app = new Rain();";
786
+ const appInit = buildAppInitLine(clientScripts, hasConfig);
653
787
 
654
788
  const content = [
655
789
  ...headerImports,
@@ -665,18 +799,22 @@ function generate() {
665
799
 
666
800
  fs.writeFileSync(ENTRY_FILE, content);
667
801
  const total = files.length + pageFiles.length;
802
+ const clientMsg =
803
+ clientFiles.length > 0 ? `, ${clientFiles.length} client` : "";
668
804
  console.log(
669
- `[gen] ${total} route(s) (${files.length} api, ${pageFiles.length} page, ${layoutFiles.length} layout) -> .rainjs/entry.ts`,
805
+ `[gen] ${total} route(s) (${files.length} api, ${pageFiles.length} page, ${layoutFiles.length} layout${clientMsg}) -> .rainjs/entry.ts`,
670
806
  );
671
807
  }
672
808
 
673
809
  module.exports = {
674
810
  generate,
811
+ regenerateClient,
675
812
  loadBuildConfig,
676
813
  getRouteFiles,
677
814
  getMiddlewareFiles,
678
815
  getPageFiles,
679
816
  getLayoutFiles,
817
+ getClientFiles,
680
818
  getMiddlewaresForRoute,
681
819
  getLayoutsForPage,
682
820
  filePathToUrlPath,
@@ -691,6 +829,8 @@ module.exports = {
691
829
  detectMiddlewareExportFromContent,
692
830
  detectDefaultExport,
693
831
  detectDefaultExportFromContent,
832
+ detectUseClientDirective,
833
+ bundleClientFilesSync,
694
834
  validateNoPageRouteColocation,
695
835
  ROUTES_DIR,
696
836
  ENTRY_FILE,