bertui 1.0.0 → 1.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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/build.js +64 -46
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bertui",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
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
@@ -1,4 +1,4 @@
1
- // src/build.js - COMPLETELY FIXED VERSION
1
+ // src/build.js - COMPLETE v1.0.0 FIXED VERSION
2
2
  import { join, relative, basename, extname, dirname } from 'path';
3
3
  import { existsSync, mkdirSync, rmSync, cpSync, readdirSync, statSync } from 'fs';
4
4
  import logger from './logger/logger.js';
@@ -11,7 +11,8 @@ export async function buildProduction(options = {}) {
11
11
  const buildDir = join(root, '.bertuibuild');
12
12
  const outDir = join(root, 'dist');
13
13
 
14
- logger.bigLog('BUILDING FOR PRODUCTION', { color: 'green' });
14
+ logger.bigLog('BUILDING FOR PRODUCTION v1.0.0', { color: 'green' });
15
+ logger.info('🔥 SINGLE CSS FILE SOLUTION - NO BULLSHIT');
15
16
 
16
17
  // Clean up old builds
17
18
  if (existsSync(buildDir)) {
@@ -38,15 +39,14 @@ export async function buildProduction(options = {}) {
38
39
  const { routes } = await compileForBuild(root, buildDir, envVars);
39
40
  logger.success(`Production compilation complete - ${routes.length} routes`);
40
41
 
41
- logger.info('Step 2: Building CSS with Lightning CSS...');
42
+ logger.info('Step 2: Combining ALL CSS into ONE file...');
42
43
  await buildAllCSS(root, outDir);
43
44
 
44
45
  logger.info('Step 3: Checking image optimization tools...');
45
46
  const optimizationTools = await checkOptimizationTools();
46
47
 
47
48
  logger.info('Step 4: Copying and optimizing static assets...');
48
- // SKIP OPTIMIZATION FOR NOW - JUST COPY
49
- await copyAllStaticAssets(root, outDir);
49
+ await copyAllStaticAssets(root, outDir, false);
50
50
 
51
51
  logger.info('Step 5: Bundling JavaScript with Bun...');
52
52
  const buildEntry = join(buildDir, 'main.js');
@@ -88,14 +88,7 @@ export async function buildProduction(options = {}) {
88
88
 
89
89
  logger.success('JavaScript bundled successfully');
90
90
 
91
- // DEBUG: Show what was built
92
- logger.info('Built outputs:');
93
- result.outputs.forEach((output, i) => {
94
- logger.info(` ${i + 1}. ${relative(outDir, output.path)} (${output.kind})`);
95
- });
96
-
97
- logger.info('Step 6: Generating HTML files...');
98
- // ✅ CRITICAL FIX: Generate HTML files
91
+ logger.info('Step 6: Generating HTML files with SINGLE CSS...');
99
92
  await generateProductionHTML(root, outDir, result, routes);
100
93
 
101
94
  // Clean up build directory
@@ -108,7 +101,6 @@ export async function buildProduction(options = {}) {
108
101
  logger.success(`✨ Build complete in ${duration}ms`);
109
102
  logger.info(`📦 Output: ${outDir}`);
110
103
 
111
- // Show build summary
112
104
  logger.table(result.outputs.map(o => ({
113
105
  file: o.path.replace(outDir, ''),
114
106
  size: `${(o.size / 1024).toFixed(2)} KB`,
@@ -136,28 +128,35 @@ export async function buildProduction(options = {}) {
136
128
  }
137
129
  }
138
130
 
139
- async function copyAllStaticAssets(root, outDir) {
131
+ // SIMPLE asset copying
132
+ async function copyAllStaticAssets(root, outDir, optimize = true) {
140
133
  const publicDir = join(root, 'public');
141
134
  const srcImagesDir = join(root, 'src', 'images');
142
135
 
143
136
  logger.info('📦 Copying static assets...');
144
137
 
145
- // Copy from public/ to dist/
138
+ // Copy from public/ to root of dist/
146
139
  if (existsSync(publicDir)) {
147
140
  logger.info(' Copying public/ directory...');
148
141
  copyImages(publicDir, outDir);
142
+ } else {
143
+ logger.info(' No public/ directory found');
149
144
  }
150
145
 
151
146
  // Copy from src/images/ to dist/images/
152
147
  if (existsSync(srcImagesDir)) {
148
+ logger.info(' Copying src/images/ to dist/images/...');
153
149
  const distImagesDir = join(outDir, 'images');
154
- logger.info(` Copying src/images/ to ${relative(root, distImagesDir)}/...`);
150
+ mkdirSync(distImagesDir, { recursive: true });
155
151
  copyImages(srcImagesDir, distImagesDir);
152
+ } else {
153
+ logger.info(' No src/images/ directory found');
156
154
  }
157
155
 
158
156
  logger.success('✅ All assets copied');
159
157
  }
160
158
 
159
+ // COMBINE ALL CSS INTO ONE FILE
161
160
  async function buildAllCSS(root, outDir) {
162
161
  const srcStylesDir = join(root, 'src', 'styles');
163
162
  const stylesOutDir = join(outDir, 'styles');
@@ -166,11 +165,29 @@ async function buildAllCSS(root, outDir) {
166
165
 
167
166
  if (existsSync(srcStylesDir)) {
168
167
  const cssFiles = readdirSync(srcStylesDir).filter(f => f.endsWith('.css'));
168
+ logger.info(`📦 Found ${cssFiles.length} CSS files to combine`);
169
+
170
+ // COMBINE ALL CSS INTO ONE FILE
171
+ let combinedCSS = '';
172
+
169
173
  for (const cssFile of cssFiles) {
170
174
  const srcPath = join(srcStylesDir, cssFile);
171
- const destPath = join(stylesOutDir, cssFile.replace('.css', '.min.css'));
172
- await buildCSS(srcPath, destPath);
175
+ const cssContent = await Bun.file(srcPath).text();
176
+ combinedCSS += `/* === ${cssFile} === */\n${cssContent}\n\n`;
173
177
  }
178
+
179
+ // Write combined CSS
180
+ const combinedPath = join(stylesOutDir, 'bertui.min.css');
181
+ await Bun.write(combinedPath, combinedCSS);
182
+
183
+ // Minify it
184
+ await buildCSS(combinedPath, combinedPath);
185
+
186
+ const size = (await Bun.file(combinedPath).size()) / 1024;
187
+ logger.success(`✅ Combined ${cssFiles.length} CSS files → bertui.min.css (${size.toFixed(1)}KB)`);
188
+
189
+ } else {
190
+ logger.warn('⚠️ No src/styles/ directory found');
174
191
  }
175
192
  }
176
193
 
@@ -545,39 +562,29 @@ function extractMetaFromSource(code) {
545
562
  }
546
563
  }
547
564
 
548
- // CRITICAL FIX: Generate HTML files
565
+ // GENERATE HTML WITH SINGLE CSS FILE
549
566
  async function generateProductionHTML(root, outDir, buildResult, routes) {
550
- if (routes.length === 0) {
551
- logger.warn('No routes found, skipping HTML generation');
552
- return;
553
- }
567
+ logger.info('Step 6: Generating HTML files with SINGLE CSS...');
554
568
 
555
- logger.info(`Generating HTML files for ${routes.length} routes...`);
556
-
557
- // Find main JS bundle
558
569
  const mainBundle = buildResult.outputs.find(o =>
559
570
  o.path.includes('main') && o.kind === 'entry-point'
560
571
  );
561
572
 
562
573
  if (!mainBundle) {
563
- logger.error('Could not find main bundle in build output');
564
- // List all outputs for debugging
565
- logger.info('Available outputs:');
566
- buildResult.outputs.forEach((o, i) => {
567
- logger.info(` ${i + 1}. ${o.path} (${o.kind})`);
568
- });
574
+ logger.error('Could not find main bundle');
569
575
  return;
570
576
  }
571
577
 
572
578
  const bundlePath = relative(outDir, mainBundle.path).replace(/\\/g, '/');
573
- logger.info(`Main bundle: ${bundlePath}`);
579
+ logger.info(`Main JS bundle: /${bundlePath}`);
574
580
 
575
- // Load config for default meta
581
+ // Load config
576
582
  const { loadConfig } = await import('./config/loadConfig.js');
577
583
  const config = await loadConfig(root);
578
584
  const defaultMeta = config.meta || {};
579
585
 
580
- // Generate HTML for each route
586
+ logger.info(`Generating HTML for ${routes.length} routes...`);
587
+
581
588
  for (const route of routes) {
582
589
  try {
583
590
  const sourceCode = await Bun.file(route.path).text();
@@ -590,26 +597,23 @@ async function generateProductionHTML(root, outDir, buildResult, routes) {
590
597
  if (route.route === '/') {
591
598
  htmlPath = join(outDir, 'index.html');
592
599
  } else {
593
- // Create directory for the route
594
- const routeDir = join(outDir, route.route.slice(1)); // Remove leading slash
600
+ const routeDir = join(outDir, route.route.replace(/^\//, ''));
595
601
  mkdirSync(routeDir, { recursive: true });
596
602
  htmlPath = join(routeDir, 'index.html');
597
603
  }
598
604
 
599
605
  await Bun.write(htmlPath, html);
600
- logger.success(`Generated: ${route.route === '/' ? 'index.html' : route.route + '/index.html'}`);
606
+ logger.success(`✅ Generated: ${route.route === '/' ? '/' : route.route}`);
607
+
601
608
  } catch (error) {
602
609
  logger.error(`Failed to generate HTML for ${route.route}: ${error.message}`);
603
610
  }
604
611
  }
612
+
613
+ logger.success('✨ All HTML files generated with SINGLE CSS file!');
605
614
  }
606
615
 
607
616
  function generateHTML(meta, route, bundlePath) {
608
- const cssFiles = ['global.min.css', 'home.min.css'];
609
- const stylesheets = cssFiles.map(css =>
610
- ` <link rel="stylesheet" href="/styles/${css}">`
611
- ).join('\n');
612
-
613
617
  return `<!DOCTYPE html>
614
618
  <html lang="${meta.lang || 'en'}">
615
619
  <head>
@@ -620,10 +624,24 @@ function generateHTML(meta, route, bundlePath) {
620
624
  <meta name="description" content="${meta.description || 'Built with BertUI - Lightning fast React development'}">
621
625
  ${meta.keywords ? `<meta name="keywords" content="${meta.keywords}">` : ''}
622
626
  ${meta.author ? `<meta name="author" content="${meta.author}">` : ''}
627
+ ${meta.themeColor ? `<meta name="theme-color" content="${meta.themeColor}">` : ''}
623
628
 
624
- <link rel="icon" type="image/svg+xml" href="/favicon.svg">
629
+ <meta property="og:title" content="${meta.ogTitle || meta.title || 'BertUI App'}">
630
+ <meta property="og:description" content="${meta.ogDescription || meta.description || 'Built with BertUI'}">
631
+ ${meta.ogImage ? `<meta property="og:image" content="${meta.ogImage}">` : ''}
632
+ <meta property="og:type" content="website">
633
+ <meta property="og:url" content="${route.route}">
634
+
635
+ <meta name="twitter:card" content="summary_large_image">
636
+ <meta name="twitter:title" content="${meta.twitterTitle || meta.ogTitle || meta.title || 'BertUI App'}">
637
+ <meta name="twitter:description" content="${meta.twitterDescription || meta.ogDescription || meta.description || 'Built with BertUI'}">
638
+ ${meta.twitterImage || meta.ogImage ? `<meta name="twitter:image" content="${meta.twitterImage || meta.ogImage}">` : ''}
625
639
 
626
- ${stylesheets}
640
+ <!-- 🔥 ONE CSS FILE FOR ALL PAGES - NO BULLSHIT -->
641
+ <link rel="stylesheet" href="/styles/bertui.min.css">
642
+
643
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
644
+ <link rel="canonical" href="${route.route}">
627
645
 
628
646
  <script type="importmap">
629
647
  {