@flexireact/core 3.0.0 → 3.0.2

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 (56) hide show
  1. package/README.md +204 -52
  2. package/dist/cli/index.js +1514 -0
  3. package/dist/cli/index.js.map +1 -0
  4. package/dist/core/client/index.js +373 -0
  5. package/dist/core/client/index.js.map +1 -0
  6. package/dist/core/index.js +6415 -0
  7. package/dist/core/index.js.map +1 -0
  8. package/dist/core/server/index.js +3094 -0
  9. package/dist/core/server/index.js.map +1 -0
  10. package/package.json +80 -80
  11. package/bin/flexireact.js +0 -23
  12. package/cli/generators.ts +0 -616
  13. package/cli/index.ts +0 -1182
  14. package/core/actions/index.ts +0 -364
  15. package/core/api.ts +0 -143
  16. package/core/build/index.ts +0 -425
  17. package/core/cli/logger.ts +0 -353
  18. package/core/client/Link.tsx +0 -345
  19. package/core/client/hydration.ts +0 -147
  20. package/core/client/index.ts +0 -12
  21. package/core/client/islands.ts +0 -143
  22. package/core/client/navigation.ts +0 -212
  23. package/core/client/runtime.ts +0 -52
  24. package/core/config.ts +0 -116
  25. package/core/context.ts +0 -83
  26. package/core/dev.ts +0 -47
  27. package/core/devtools/index.ts +0 -644
  28. package/core/edge/cache.ts +0 -344
  29. package/core/edge/fetch-polyfill.ts +0 -247
  30. package/core/edge/handler.ts +0 -248
  31. package/core/edge/index.ts +0 -81
  32. package/core/edge/ppr.ts +0 -264
  33. package/core/edge/runtime.ts +0 -161
  34. package/core/font/index.ts +0 -306
  35. package/core/helpers.ts +0 -494
  36. package/core/image/index.ts +0 -413
  37. package/core/index.ts +0 -218
  38. package/core/islands/index.ts +0 -293
  39. package/core/loader.ts +0 -111
  40. package/core/logger.ts +0 -242
  41. package/core/metadata/index.ts +0 -622
  42. package/core/middleware/index.ts +0 -416
  43. package/core/plugins/index.ts +0 -373
  44. package/core/render/index.ts +0 -1243
  45. package/core/render.ts +0 -136
  46. package/core/router/index.ts +0 -551
  47. package/core/router.ts +0 -141
  48. package/core/rsc/index.ts +0 -199
  49. package/core/server/index.ts +0 -779
  50. package/core/server.ts +0 -203
  51. package/core/ssg/index.ts +0 -346
  52. package/core/start-dev.ts +0 -6
  53. package/core/start-prod.ts +0 -6
  54. package/core/tsconfig.json +0 -30
  55. package/core/types.ts +0 -239
  56. package/core/utils.ts +0 -176
@@ -1,425 +0,0 @@
1
- /**
2
- * FlexiReact Build System
3
- * Uses esbuild for fast bundling of client and server code
4
- */
5
-
6
- import * as esbuild from 'esbuild';
7
- import fs from 'fs';
8
- import path from 'path';
9
- import { fileURLToPath } from 'url';
10
- import { findFiles, ensureDir, cleanDir, generateHash, isClientComponent, isIsland } from '../utils.js';
11
- import { buildRouteTree } from '../router/index.js';
12
-
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = path.dirname(__filename);
15
-
16
- /**
17
- * Build configuration
18
- */
19
- export const BuildMode = {
20
- DEVELOPMENT: 'development',
21
- PRODUCTION: 'production'
22
- };
23
-
24
- /**
25
- * Main build function
26
- */
27
- export async function build(options) {
28
- const {
29
- projectRoot,
30
- config,
31
- mode = BuildMode.PRODUCTION,
32
- analyze = false
33
- } = options;
34
-
35
- const startTime = Date.now();
36
- const outDir = config.outDir;
37
- const isDev = mode === BuildMode.DEVELOPMENT;
38
-
39
- console.log('\n⚡ FlexiReact Build\n');
40
- console.log(` Mode: ${mode}`);
41
- console.log(` Output: ${outDir}\n`);
42
-
43
- // Clean output directory
44
- cleanDir(outDir);
45
- ensureDir(path.join(outDir, 'client'));
46
- ensureDir(path.join(outDir, 'server'));
47
- ensureDir(path.join(outDir, 'static'));
48
-
49
- // Build routes
50
- const routes = buildRouteTree(config.pagesDir, config.layoutsDir);
51
-
52
- // Find all client components and islands
53
- const clientEntries = findClientEntries(config.pagesDir, config.layoutsDir);
54
-
55
- // Build client bundle
56
- console.log('📦 Building client bundle...');
57
- const clientResult = await buildClient({
58
- entries: clientEntries,
59
- outDir: path.join(outDir, 'client'),
60
- config,
61
- isDev
62
- });
63
-
64
- // Build server bundle
65
- console.log('📦 Building server bundle...');
66
- const serverResult = await buildServer({
67
- pagesDir: config.pagesDir,
68
- layoutsDir: config.layoutsDir,
69
- outDir: path.join(outDir, 'server'),
70
- config,
71
- isDev
72
- });
73
-
74
- // Copy public assets
75
- console.log('📁 Copying public assets...');
76
- await copyPublicAssets(config.publicDir, path.join(outDir, 'static'));
77
-
78
- // Generate manifest
79
- const manifest = generateManifest({
80
- routes,
81
- clientResult,
82
- serverResult,
83
- config
84
- });
85
-
86
- fs.writeFileSync(
87
- path.join(outDir, 'manifest.json'),
88
- JSON.stringify(manifest, null, 2)
89
- );
90
-
91
- const duration = Date.now() - startTime;
92
-
93
- console.log('\n✨ Build complete!\n');
94
- console.log(` Duration: ${duration}ms`);
95
- console.log(` Client chunks: ${clientResult.outputs.length}`);
96
- console.log(` Server modules: ${serverResult.outputs.length}`);
97
- console.log('');
98
-
99
- // Generate bundle analysis if requested
100
- let analysis = null;
101
- if (analyze) {
102
- analysis = generateBundleAnalysis(clientResult, serverResult, outDir);
103
- }
104
-
105
- return {
106
- success: true,
107
- duration,
108
- manifest,
109
- clientResult,
110
- serverResult,
111
- analysis
112
- };
113
- }
114
-
115
- /**
116
- * Generates bundle analysis data
117
- */
118
- function generateBundleAnalysis(clientResult, serverResult, outDir) {
119
- const files: Record<string, { size: number; gzipSize?: number }> = {};
120
- let totalSize = 0;
121
- let totalGzipSize = 0;
122
-
123
- // Analyze client outputs
124
- for (const output of clientResult.outputs || []) {
125
- if (output.path && fs.existsSync(output.path)) {
126
- const stat = fs.statSync(output.path);
127
- const relativePath = path.relative(outDir, output.path);
128
-
129
- // Estimate gzip size (roughly 30% of original for JS)
130
- const gzipSize = Math.round(stat.size * 0.3);
131
-
132
- files[relativePath] = {
133
- size: stat.size,
134
- gzipSize
135
- };
136
-
137
- totalSize += stat.size;
138
- totalGzipSize += gzipSize;
139
- }
140
- }
141
-
142
- // Analyze server outputs
143
- for (const output of serverResult.outputs || []) {
144
- if (output.path && fs.existsSync(output.path)) {
145
- const stat = fs.statSync(output.path);
146
- const relativePath = path.relative(outDir, output.path);
147
-
148
- files[relativePath] = {
149
- size: stat.size
150
- };
151
-
152
- totalSize += stat.size;
153
- }
154
- }
155
-
156
- return {
157
- files,
158
- totalSize,
159
- totalGzipSize,
160
- clientSize: clientResult.outputs?.reduce((sum, o) => {
161
- if (o.path && fs.existsSync(o.path)) {
162
- return sum + fs.statSync(o.path).size;
163
- }
164
- return sum;
165
- }, 0) || 0,
166
- serverSize: serverResult.outputs?.reduce((sum, o) => {
167
- if (o.path && fs.existsSync(o.path)) {
168
- return sum + fs.statSync(o.path).size;
169
- }
170
- return sum;
171
- }, 0) || 0
172
- };
173
- }
174
-
175
- /**
176
- * Finds all client component entries
177
- */
178
- function findClientEntries(pagesDir, layoutsDir) {
179
- const entries = [];
180
- const dirs = [pagesDir, layoutsDir].filter(d => fs.existsSync(d));
181
-
182
- for (const dir of dirs) {
183
- const files = findFiles(dir, /\.(jsx|tsx)$/);
184
-
185
- for (const file of files) {
186
- if (isClientComponent(file) || isIsland(file)) {
187
- entries.push(file);
188
- }
189
- }
190
- }
191
-
192
- return entries;
193
- }
194
-
195
- /**
196
- * Builds client-side JavaScript
197
- */
198
- async function buildClient(options) {
199
- const { entries, outDir, config, isDev } = options;
200
-
201
- if (entries.length === 0) {
202
- return { outputs: [] };
203
- }
204
-
205
- // Create entry points map
206
- const entryPoints = {};
207
- for (const entry of entries) {
208
- const name = path.basename(entry, path.extname(entry));
209
- const hash = generateHash(entry);
210
- entryPoints[`${name}-${hash}`] = entry;
211
- }
212
-
213
- // Add runtime entry
214
- const runtimePath = path.join(__dirname, '..', 'client', 'runtime.js');
215
- if (fs.existsSync(runtimePath)) {
216
- entryPoints['runtime'] = runtimePath;
217
- }
218
-
219
- try {
220
- const result = await esbuild.build({
221
- entryPoints,
222
- bundle: true,
223
- splitting: true,
224
- format: 'esm',
225
- outdir: outDir,
226
- minify: !isDev && config.build.minify,
227
- sourcemap: config.build.sourcemap,
228
- target: config.build.target,
229
- jsx: 'automatic',
230
- jsxImportSource: 'react',
231
- metafile: true,
232
- external: [],
233
- define: {
234
- 'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production')
235
- },
236
- loader: {
237
- '.js': 'jsx',
238
- '.jsx': 'jsx',
239
- '.ts': 'tsx',
240
- '.tsx': 'tsx'
241
- }
242
- });
243
-
244
- const outputs = Object.keys(result.metafile.outputs).map(file => ({
245
- file: path.basename(file),
246
- size: result.metafile.outputs[file].bytes
247
- }));
248
-
249
- return { outputs, metafile: result.metafile };
250
-
251
- } catch (error) {
252
- console.error('Client build failed:', error);
253
- throw error;
254
- }
255
- }
256
-
257
- /**
258
- * Builds server-side modules
259
- */
260
- async function buildServer(options) {
261
- const { pagesDir, layoutsDir, outDir, config, isDev } = options;
262
-
263
- const entries = [];
264
-
265
- // Find all page and layout files
266
- for (const dir of [pagesDir, layoutsDir]) {
267
- if (fs.existsSync(dir)) {
268
- entries.push(...findFiles(dir, /\.(jsx|tsx|js|ts)$/));
269
- }
270
- }
271
-
272
- if (entries.length === 0) {
273
- return { outputs: [] };
274
- }
275
-
276
- // Create entry points
277
- const entryPoints = {};
278
- for (const entry of entries) {
279
- const relativePath = path.relative(pagesDir, entry);
280
- const name = relativePath.replace(/[\/\\]/g, '_').replace(/\.(jsx|tsx|js|ts)$/, '');
281
- entryPoints[name] = entry;
282
- }
283
-
284
- try {
285
- const result = await esbuild.build({
286
- entryPoints,
287
- bundle: true,
288
- format: 'esm',
289
- platform: 'node',
290
- outdir: outDir,
291
- minify: false, // Keep server code readable
292
- sourcemap: true,
293
- target: 'node18',
294
- jsx: 'automatic',
295
- jsxImportSource: 'react',
296
- metafile: true,
297
- packages: 'external', // Don't bundle node_modules
298
- loader: {
299
- '.js': 'jsx',
300
- '.jsx': 'jsx',
301
- '.ts': 'tsx',
302
- '.tsx': 'tsx'
303
- }
304
- });
305
-
306
- const outputs = Object.keys(result.metafile.outputs).map(file => ({
307
- file: path.basename(file),
308
- size: result.metafile.outputs[file].bytes
309
- }));
310
-
311
- return { outputs, metafile: result.metafile };
312
-
313
- } catch (error) {
314
- console.error('Server build failed:', error);
315
- throw error;
316
- }
317
- }
318
-
319
- /**
320
- * Copies public assets to output directory
321
- */
322
- async function copyPublicAssets(publicDir, outDir) {
323
- if (!fs.existsSync(publicDir)) {
324
- return;
325
- }
326
-
327
- const copyRecursive = (src, dest) => {
328
- const entries = fs.readdirSync(src, { withFileTypes: true });
329
-
330
- ensureDir(dest);
331
-
332
- for (const entry of entries) {
333
- const srcPath = path.join(src, entry.name);
334
- const destPath = path.join(dest, entry.name);
335
-
336
- if (entry.isDirectory()) {
337
- copyRecursive(srcPath, destPath);
338
- } else {
339
- fs.copyFileSync(srcPath, destPath);
340
- }
341
- }
342
- };
343
-
344
- copyRecursive(publicDir, outDir);
345
- }
346
-
347
- /**
348
- * Generates build manifest
349
- */
350
- function generateManifest(options) {
351
- const { routes, clientResult, serverResult, config } = options;
352
-
353
- return {
354
- version: '2.0.0',
355
- generatedAt: new Date().toISOString(),
356
- routes: {
357
- pages: routes.pages.map(r => ({
358
- path: r.path,
359
- file: r.filePath,
360
- hasLayout: !!r.layout,
361
- hasLoading: !!r.loading,
362
- hasError: !!r.error
363
- })),
364
- api: routes.api.map(r => ({
365
- path: r.path,
366
- file: r.filePath
367
- }))
368
- },
369
- client: {
370
- chunks: clientResult.outputs || []
371
- },
372
- server: {
373
- modules: serverResult.outputs || []
374
- },
375
- config: {
376
- islands: config.islands.enabled,
377
- rsc: config.rsc.enabled
378
- }
379
- };
380
- }
381
-
382
- /**
383
- * Development build with watch mode
384
- */
385
- export async function buildDev(options) {
386
- const { projectRoot, config, onChange } = options;
387
-
388
- const outDir = config.outDir;
389
- ensureDir(outDir);
390
-
391
- // Use esbuild's watch mode
392
- const ctx = await esbuild.context({
393
- entryPoints: findFiles(config.pagesDir, /\.(jsx|tsx)$/),
394
- bundle: true,
395
- format: 'esm',
396
- outdir: path.join(outDir, 'dev'),
397
- sourcemap: true,
398
- jsx: 'automatic',
399
- jsxImportSource: 'react',
400
- loader: {
401
- '.js': 'jsx',
402
- '.jsx': 'jsx'
403
- },
404
- plugins: [{
405
- name: 'flexi-watch',
406
- setup(build) {
407
- build.onEnd(result => {
408
- if (result.errors.length === 0) {
409
- onChange?.();
410
- }
411
- });
412
- }
413
- }]
414
- });
415
-
416
- await ctx.watch();
417
-
418
- return ctx;
419
- }
420
-
421
- export default {
422
- build,
423
- buildDev,
424
- BuildMode
425
- };