bertui 0.3.2 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bertui",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Lightning-fast React dev server powered by Bun and Elysia",
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/src/build.js CHANGED
@@ -11,7 +11,6 @@ export async function buildProduction(options = {}) {
11
11
 
12
12
  logger.bigLog('BUILDING FOR PRODUCTION', { color: 'green' });
13
13
 
14
- // Clean folders
15
14
  if (existsSync(buildDir)) {
16
15
  rmSync(buildDir, { recursive: true });
17
16
  }
@@ -26,16 +25,13 @@ export async function buildProduction(options = {}) {
26
25
  const startTime = Date.now();
27
26
 
28
27
  try {
29
- // Step 1: Compile for production
30
28
  logger.info('Step 1: Compiling for production...');
31
29
  await compileForBuild(root, buildDir);
32
30
  logger.success('Production compilation complete');
33
31
 
34
- // Step 2: Build CSS with Lightning CSS
35
32
  logger.info('Step 2: Building CSS with Lightning CSS...');
36
33
  await buildAllCSS(root, outDir);
37
34
 
38
- // Step 3: Copy public assets if they exist
39
35
  const publicDir = join(root, 'public');
40
36
  if (existsSync(publicDir)) {
41
37
  logger.info('Step 3: Copying public assets...');
@@ -45,7 +41,6 @@ export async function buildProduction(options = {}) {
45
41
  logger.info('Step 3: No public directory found, skipping...');
46
42
  }
47
43
 
48
- // Step 4: Build JavaScript with Bun's bundler
49
44
  logger.info('Step 4: Bundling JavaScript with Bun...');
50
45
  const buildEntry = join(buildDir, 'main.js');
51
46
 
@@ -54,7 +49,6 @@ export async function buildProduction(options = {}) {
54
49
  process.exit(1);
55
50
  }
56
51
 
57
- // FIXED: Let Bun handle ALL imports with proper externals
58
52
  const result = await Bun.build({
59
53
  entrypoints: [buildEntry],
60
54
  outdir: join(outDir, 'assets'),
@@ -67,7 +61,6 @@ export async function buildProduction(options = {}) {
67
61
  chunk: 'chunks/[name]-[hash].js',
68
62
  asset: '[name]-[hash].[ext]'
69
63
  },
70
- // FIXED: Use CDN externals - Bun handles tree shaking automatically
71
64
  external: ['react', 'react-dom', 'react-dom/client', 'react/jsx-runtime']
72
65
  });
73
66
 
@@ -79,11 +72,9 @@ export async function buildProduction(options = {}) {
79
72
 
80
73
  logger.success('JavaScript bundled with tree-shaking');
81
74
 
82
- // Step 5: Generate index.html
83
75
  logger.info('Step 5: Generating index.html...');
84
76
  await generateProductionHTML(root, outDir, result);
85
77
 
86
- // Step 6: Clean up build folder
87
78
  rmSync(buildDir, { recursive: true });
88
79
  logger.info('Cleaned up .bertuibuild/');
89
80
 
@@ -91,13 +82,11 @@ export async function buildProduction(options = {}) {
91
82
  logger.success(`✨ Build complete in ${duration}ms`);
92
83
  logger.info(`šŸ“¦ Output: ${outDir}`);
93
84
 
94
- // Display build stats
95
85
  logger.table(result.outputs.map(o => ({
96
86
  file: o.path.replace(outDir, ''),
97
87
  size: `${(o.size / 1024).toFixed(2)} KB`
98
88
  })));
99
89
 
100
- // Show deployment instructions
101
90
  logger.bigLog('READY TO DEPLOY', { color: 'green' });
102
91
  console.log('\nšŸ“¤ Deploy your app:\n');
103
92
  console.log(' Vercel: bunx vercel');
@@ -111,7 +100,6 @@ export async function buildProduction(options = {}) {
111
100
  logger.error(error.stack);
112
101
  }
113
102
 
114
- // Clean up on error
115
103
  if (existsSync(buildDir)) {
116
104
  rmSync(buildDir, { recursive: true });
117
105
  }
@@ -122,15 +110,10 @@ export async function buildProduction(options = {}) {
122
110
 
123
111
  async function buildAllCSS(root, outDir) {
124
112
  const srcStylesDir = join(root, 'src', 'styles');
125
- const bertuiCssSource = join(import.meta.dir, 'styles/bertui.css');
126
113
  const stylesOutDir = join(outDir, 'styles');
127
114
 
128
115
  mkdirSync(stylesOutDir, { recursive: true });
129
116
 
130
- // Build BertUI's built-in CSS
131
- await buildCSS(bertuiCssSource, join(stylesOutDir, 'bertui.min.css'));
132
-
133
- // Build user's CSS files if they exist
134
117
  if (existsSync(srcStylesDir)) {
135
118
  const cssFiles = readdirSync(srcStylesDir).filter(f => f.endsWith('.css'));
136
119
  for (const cssFile of cssFiles) {
@@ -149,17 +132,14 @@ async function compileForBuild(root, buildDir) {
149
132
  throw new Error('src/ directory not found!');
150
133
  }
151
134
 
152
- // Discover routes
153
135
  let routes = [];
154
136
  if (existsSync(pagesDir)) {
155
137
  routes = await discoverRoutes(pagesDir);
156
138
  logger.info(`Found ${routes.length} routes`);
157
139
  }
158
140
 
159
- // Compile all source files
160
141
  await compileBuildDirectory(srcDir, buildDir, root);
161
142
 
162
- // Generate router if we have routes
163
143
  if (routes.length > 0) {
164
144
  await generateBuildRouter(routes, buildDir);
165
145
  logger.info('Generated router for build');
@@ -181,7 +161,6 @@ async function discoverRoutes(pagesDir) {
181
161
  } else if (entry.isFile()) {
182
162
  const ext = extname(entry.name);
183
163
 
184
- // FIXED: Ignore CSS files
185
164
  if (ext === '.css') continue;
186
165
 
187
166
  if (['.jsx', '.tsx', '.js', '.ts'].includes(ext)) {
@@ -369,7 +348,6 @@ async function compileBuildDirectory(srcDir, buildDir, root) {
369
348
  } else {
370
349
  const ext = extname(file);
371
350
 
372
- // FIXED: Skip CSS files in build
373
351
  if (ext === '.css') continue;
374
352
 
375
353
  if (['.jsx', '.tsx', '.ts'].includes(ext)) {
@@ -377,7 +355,11 @@ async function compileBuildDirectory(srcDir, buildDir, root) {
377
355
  } else if (ext === '.js') {
378
356
  const outPath = join(buildDir, file);
379
357
  let code = await Bun.file(srcPath).text();
358
+
359
+ // CRITICAL FIX: Remove CSS imports
360
+ code = removeCSSImports(code);
380
361
  code = fixBuildImports(code, srcPath, outPath, root);
362
+
381
363
  await Bun.write(outPath, code);
382
364
  }
383
365
  }
@@ -391,6 +373,9 @@ async function compileBuildFile(srcPath, buildDir, filename, root) {
391
373
  try {
392
374
  let code = await Bun.file(srcPath).text();
393
375
 
376
+ // CRITICAL FIX: Remove CSS imports before transpilation
377
+ code = removeCSSImports(code);
378
+
394
379
  const outFilename = filename.replace(/\.(jsx|tsx|ts)$/, '.js');
395
380
  const outPath = join(buildDir, outFilename);
396
381
 
@@ -422,19 +407,20 @@ async function compileBuildFile(srcPath, buildDir, filename, root) {
422
407
  }
423
408
  }
424
409
 
425
- // FIXED: Only fix router imports, preserve all others
426
- function fixBuildImports(code, srcPath, outPath, root) {
427
- // Remove bertui/styles imports
410
+ // NEW FUNCTION: Remove all CSS imports
411
+ function removeCSSImports(code) {
412
+ code = code.replace(/import\s+['"][^'"]*\.css['"];?\s*/g, '');
428
413
  code = code.replace(/import\s+['"]bertui\/styles['"]\s*;?\s*/g, '');
429
-
414
+ return code;
415
+ }
416
+
417
+ function fixBuildImports(code, srcPath, outPath, root) {
430
418
  const buildDir = join(root, '.bertuibuild');
431
419
  const routerPath = join(buildDir, 'router.js');
432
420
 
433
- // Calculate relative path from output file to router.js
434
421
  const relativeToRouter = relative(dirname(outPath), routerPath).replace(/\\/g, '/');
435
422
  const routerImport = relativeToRouter.startsWith('.') ? relativeToRouter : './' + relativeToRouter;
436
423
 
437
- // ONLY replace bertui/router imports
438
424
  code = code.replace(
439
425
  /from\s+['"]bertui\/router['"]/g,
440
426
  `from '${routerImport}'`
@@ -467,6 +453,17 @@ async function generateProductionHTML(root, outDir, buildResult) {
467
453
 
468
454
  const bundlePath = mainBundle.path.replace(outDir, '').replace(/^\//, '');
469
455
 
456
+ // Find user CSS files
457
+ const srcStylesDir = join(root, 'src', 'styles');
458
+ let userStylesheets = '';
459
+
460
+ if (existsSync(srcStylesDir)) {
461
+ const cssFiles = readdirSync(srcStylesDir).filter(f => f.endsWith('.css'));
462
+ userStylesheets = cssFiles.map(f =>
463
+ ` <link rel="stylesheet" href="/styles/${f.replace('.css', '.min.css')}">`
464
+ ).join('\n');
465
+ }
466
+
470
467
  const html = `<!DOCTYPE html>
471
468
  <html lang="en">
472
469
  <head>
@@ -474,7 +471,7 @@ async function generateProductionHTML(root, outDir, buildResult) {
474
471
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
475
472
  <meta name="description" content="Built with BertUI - Lightning fast React development">
476
473
  <title>BertUI App</title>
477
- <link rel="stylesheet" href="/styles/bertui.min.css">
474
+ ${userStylesheets}
478
475
  <script type="importmap">
479
476
  {
480
477
  "imports": {
@@ -65,13 +65,8 @@ async function discoverRoutes(pagesDir) {
65
65
  } else if (entry.isFile()) {
66
66
  const ext = extname(entry.name);
67
67
 
68
- // FIXED: Ignore CSS files completely
69
- if (ext === '.css') {
70
- logger.debug(`Skipping CSS file: ${relativePath}`);
71
- continue;
72
- }
68
+ if (ext === '.css') continue;
73
69
 
74
- // Only process valid page files
75
70
  if (['.jsx', '.tsx', '.js', '.ts'].includes(ext)) {
76
71
  const fileName = entry.name.replace(ext, '');
77
72
 
@@ -263,7 +258,6 @@ async function compileDirectory(srcDir, outDir, root) {
263
258
  const ext = extname(file);
264
259
  const relativePath = relative(join(root, 'src'), srcPath);
265
260
 
266
- // FIXED: Handle CSS files properly - copy to styles output
267
261
  if (ext === '.css') {
268
262
  const stylesOutDir = join(root, '.bertui', 'styles');
269
263
  if (!existsSync(stylesOutDir)) {
@@ -274,14 +268,15 @@ async function compileDirectory(srcDir, outDir, root) {
274
268
  logger.debug(`Copied CSS: ${relativePath}`);
275
269
  stats.files++;
276
270
  } else if (['.jsx', '.tsx', '.ts'].includes(ext)) {
277
- await compileFile(srcPath, outDir, file, relativePath);
271
+ await compileFile(srcPath, outDir, file, relativePath, root);
278
272
  stats.files++;
279
273
  } else if (ext === '.js') {
280
274
  const outPath = join(outDir, file);
281
275
  let code = await Bun.file(srcPath).text();
282
276
 
283
- // FIXED: Don't modify imports - let Bun handle them
284
- // Only fix router imports
277
+ // Remove ALL CSS imports
278
+ code = removeCSSImports(code);
279
+ // Fix router imports
285
280
  code = fixRouterImports(code, outPath, root);
286
281
 
287
282
  await Bun.write(outPath, code);
@@ -297,17 +292,18 @@ async function compileDirectory(srcDir, outDir, root) {
297
292
  return stats;
298
293
  }
299
294
 
300
- async function compileFile(srcPath, outDir, filename, relativePath) {
295
+ async function compileFile(srcPath, outDir, filename, relativePath, root) {
301
296
  const ext = extname(filename);
302
297
  const loader = ext === '.tsx' ? 'tsx' : ext === '.ts' ? 'ts' : 'jsx';
303
298
 
304
299
  try {
305
300
  let code = await Bun.file(srcPath).text();
306
301
 
307
- // FIXED: Don't remove any imports - preserve them all
308
- // Only fix router imports to point to compiled location
302
+ // CRITICAL FIX: Remove ALL CSS imports before transpilation
303
+ code = removeCSSImports(code);
304
+
309
305
  const outPath = join(outDir, filename.replace(/\.(jsx|tsx|ts)$/, '.js'));
310
- code = fixRouterImports(code, outPath, process.cwd());
306
+ code = fixRouterImports(code, outPath, root);
311
307
 
312
308
  const transpiler = new Bun.Transpiler({
313
309
  loader,
@@ -335,24 +331,30 @@ async function compileFile(srcPath, outDir, filename, relativePath) {
335
331
  }
336
332
  }
337
333
 
338
- // FIXED: New function - only fixes bertui/router imports
334
+ // NEW FUNCTION: Remove all CSS imports
335
+ function removeCSSImports(code) {
336
+ // Remove CSS imports (with or without quotes, single or double)
337
+ // Matches: import './styles.css', import "./styles.css", import "styles.css", import 'styles.css'
338
+ code = code.replace(/import\s+['"][^'"]*\.css['"];?\s*/g, '');
339
+
340
+ // Also remove bertui/styles imports
341
+ code = code.replace(/import\s+['"]bertui\/styles['"]\s*;?\s*/g, '');
342
+
343
+ return code;
344
+ }
345
+
339
346
  function fixRouterImports(code, outPath, root) {
340
347
  const buildDir = join(root, '.bertui', 'compiled');
341
348
  const routerPath = join(buildDir, 'router.js');
342
349
 
343
- // Calculate relative path from output file to router.js
344
350
  const relativeToRouter = relative(dirname(outPath), routerPath).replace(/\\/g, '/');
345
351
  const routerImport = relativeToRouter.startsWith('.') ? relativeToRouter : './' + relativeToRouter;
346
352
 
347
- // ONLY replace bertui/router imports
348
353
  code = code.replace(
349
354
  /from\s+['"]bertui\/router['"]/g,
350
355
  `from '${routerImport}'`
351
356
  );
352
357
 
353
- // Remove bertui/styles imports (CSS handled separately)
354
- code = code.replace(/import\s+['"]bertui\/styles['"]\s*;?\s*/g, '');
355
-
356
358
  return code;
357
359
  }
358
360