bertui 1.2.8 → 2.0.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 (182) hide show
  1. package/README.md +45 -196
  2. package/TYPES_PATCH.md +17 -0
  3. package/bin/bertui.js +2 -7
  4. package/package.json +32 -98
  5. package/src/config.ts +4 -0
  6. package/src/index.ts +32 -0
  7. package/src/optional.ts +49 -0
  8. package/src/router.ts +3 -0
  9. package/tsconfig.json +29 -0
  10. package/LICENSE +0 -21
  11. package/index.js +0 -103
  12. package/src/analyzer/index.js +0 -370
  13. package/src/build/compiler/file-transpiler.js +0 -216
  14. package/src/build/compiler/index.js +0 -31
  15. package/src/build/compiler/route-discoverer.js +0 -49
  16. package/src/build/compiler/router-generator.js +0 -105
  17. package/src/build/css-builder.js +0 -81
  18. package/src/build/generators/html-generator.js +0 -151
  19. package/src/build/generators/robots-generator.js +0 -58
  20. package/src/build/generators/sitemap-generator.js +0 -63
  21. package/src/build/image-optimizer.js +0 -137
  22. package/src/build/processors/asset-processor.js +0 -19
  23. package/src/build/processors/css-builder.js +0 -142
  24. package/src/build/server-island-validator.js +0 -12
  25. package/src/build.js +0 -266
  26. package/src/cli.js +0 -131
  27. package/src/client/compiler.js +0 -522
  28. package/src/client/fast-refresh.js +0 -72
  29. package/src/client/hmr-runtime.js +0 -59
  30. package/src/compiler/index.js +0 -25
  31. package/src/compiler/router-generator-pure.js +0 -104
  32. package/src/compiler/transform.js +0 -149
  33. package/src/config/defaultConfig.js +0 -37
  34. package/src/config/index.js +0 -2
  35. package/src/config/loadConfig.js +0 -64
  36. package/src/config/og-image.png +0 -0
  37. package/src/css/index.js +0 -46
  38. package/src/css/processor.js +0 -172
  39. package/src/dev.js +0 -68
  40. package/src/hydration/index.js +0 -151
  41. package/src/image-optimizer/index.js +0 -103
  42. package/src/images/index.js +0 -102
  43. package/src/images/processor.js +0 -169
  44. package/src/layouts/index.js +0 -165
  45. package/src/loading/index.js +0 -210
  46. package/src/logger/logger.js +0 -320
  47. package/src/logger/notes.md +0 -20
  48. package/src/middleware/index.js +0 -182
  49. package/src/router/Router.js +0 -150
  50. package/src/router/SSRRouter.js +0 -156
  51. package/src/router/index.js +0 -3
  52. package/src/scaffolder/index.js +0 -310
  53. package/src/serve.js +0 -193
  54. package/src/server/dev-handler.js +0 -195
  55. package/src/server/dev-server-utils.js +0 -406
  56. package/src/server/dev-server.js +0 -15
  57. package/src/server/hmr-handler.js +0 -148
  58. package/src/server/index.js +0 -3
  59. package/src/server/notes.md +0 -1
  60. package/src/server/request-handler.js +0 -36
  61. package/src/server-islands/extractor.js +0 -198
  62. package/src/server-islands/index.js +0 -59
  63. package/src/styles/bertui.css +0 -210
  64. package/src/utils/cache.js +0 -297
  65. package/src/utils/env.js +0 -87
  66. package/src/utils/importhow.js +0 -52
  67. package/src/utils/index.js +0 -11
  68. package/src/utils/meta-extractor.js +0 -127
  69. package/types/bin/bertui.d.ts +0 -3
  70. package/types/bin/bertui.d.ts.map +0 -1
  71. package/types/error-overlay.d.ts +0 -2
  72. package/types/error-overlay.d.ts.map +0 -1
  73. package/types/index.d.ts +0 -26
  74. package/types/index.d.ts.map +0 -1
  75. package/types/scripts/fix-wasm-exports.d.ts +0 -2
  76. package/types/scripts/fix-wasm-exports.d.ts.map +0 -1
  77. package/types/src/analyzer/index.d.ts +0 -8
  78. package/types/src/analyzer/index.d.ts.map +0 -1
  79. package/types/src/build/compiler/file-transpiler.d.ts +0 -5
  80. package/types/src/build/compiler/file-transpiler.d.ts.map +0 -1
  81. package/types/src/build/compiler/index.d.ts +0 -12
  82. package/types/src/build/compiler/index.d.ts.map +0 -1
  83. package/types/src/build/compiler/route-discoverer.d.ts +0 -2
  84. package/types/src/build/compiler/route-discoverer.d.ts.map +0 -1
  85. package/types/src/build/compiler/router-generator.d.ts +0 -2
  86. package/types/src/build/compiler/router-generator.d.ts.map +0 -1
  87. package/types/src/build/css-builder.d.ts +0 -18
  88. package/types/src/build/css-builder.d.ts.map +0 -1
  89. package/types/src/build/generators/html-generator.d.ts +0 -2
  90. package/types/src/build/generators/html-generator.d.ts.map +0 -1
  91. package/types/src/build/generators/robots-generator.d.ts +0 -11
  92. package/types/src/build/generators/robots-generator.d.ts.map +0 -1
  93. package/types/src/build/generators/sitemap-generator.d.ts +0 -5
  94. package/types/src/build/generators/sitemap-generator.d.ts.map +0 -1
  95. package/types/src/build/image-optimizer.d.ts +0 -11
  96. package/types/src/build/image-optimizer.d.ts.map +0 -1
  97. package/types/src/build/processors/asset-processor.d.ts +0 -2
  98. package/types/src/build/processors/asset-processor.d.ts.map +0 -1
  99. package/types/src/build/processors/css-builder.d.ts +0 -2
  100. package/types/src/build/processors/css-builder.d.ts.map +0 -1
  101. package/types/src/build/server-island-validator.d.ts +0 -27
  102. package/types/src/build/server-island-validator.d.ts.map +0 -1
  103. package/types/src/build.d.ts +0 -5
  104. package/types/src/build.d.ts.map +0 -1
  105. package/types/src/cli.d.ts +0 -2
  106. package/types/src/cli.d.ts.map +0 -1
  107. package/types/src/client/compiler.d.ts +0 -16
  108. package/types/src/client/compiler.d.ts.map +0 -1
  109. package/types/src/client/fast-refresh.d.ts +0 -3
  110. package/types/src/client/fast-refresh.d.ts.map +0 -1
  111. package/types/src/client/hmr-runtime.d.ts +0 -4
  112. package/types/src/client/hmr-runtime.d.ts.map +0 -1
  113. package/types/src/compiler/index.d.ts +0 -8
  114. package/types/src/compiler/index.d.ts.map +0 -1
  115. package/types/src/compiler/router-generator-pure.d.ts +0 -2
  116. package/types/src/compiler/router-generator-pure.d.ts.map +0 -1
  117. package/types/src/compiler/transform.d.ts +0 -36
  118. package/types/src/compiler/transform.d.ts.map +0 -1
  119. package/types/src/config/defaultConfig.d.ts +0 -26
  120. package/types/src/config/defaultConfig.d.ts.map +0 -1
  121. package/types/src/config/index.d.ts +0 -3
  122. package/types/src/config/index.d.ts.map +0 -1
  123. package/types/src/config/loadConfig.d.ts +0 -2
  124. package/types/src/config/loadConfig.d.ts.map +0 -1
  125. package/types/src/css/index.d.ts +0 -6
  126. package/types/src/css/index.d.ts.map +0 -1
  127. package/types/src/css/processor.d.ts +0 -23
  128. package/types/src/css/processor.d.ts.map +0 -1
  129. package/types/src/dev.d.ts +0 -2
  130. package/types/src/dev.d.ts.map +0 -1
  131. package/types/src/hydration/index.d.ts +0 -33
  132. package/types/src/hydration/index.d.ts.map +0 -1
  133. package/types/src/image-optimizer/index.d.ts +0 -24
  134. package/types/src/image-optimizer/index.d.ts.map +0 -1
  135. package/types/src/images/index.d.ts +0 -12
  136. package/types/src/images/index.d.ts.map +0 -1
  137. package/types/src/images/processor.d.ts +0 -30
  138. package/types/src/images/processor.d.ts.map +0 -1
  139. package/types/src/layouts/index.d.ts +0 -28
  140. package/types/src/layouts/index.d.ts.map +0 -1
  141. package/types/src/loading/index.d.ts +0 -28
  142. package/types/src/loading/index.d.ts.map +0 -1
  143. package/types/src/logger/logger.d.ts +0 -30
  144. package/types/src/logger/logger.d.ts.map +0 -1
  145. package/types/src/middleware/index.d.ts +0 -61
  146. package/types/src/middleware/index.d.ts.map +0 -1
  147. package/types/src/router/Router.d.ts +0 -16
  148. package/types/src/router/Router.d.ts.map +0 -1
  149. package/types/src/router/SSRRouter.d.ts +0 -20
  150. package/types/src/router/SSRRouter.d.ts.map +0 -1
  151. package/types/src/router/index.d.ts +0 -3
  152. package/types/src/router/index.d.ts.map +0 -1
  153. package/types/src/scaffolder/index.d.ts +0 -14
  154. package/types/src/scaffolder/index.d.ts.map +0 -1
  155. package/types/src/serve.d.ts +0 -3
  156. package/types/src/serve.d.ts.map +0 -1
  157. package/types/src/server/dev-handler.d.ts +0 -13
  158. package/types/src/server/dev-handler.d.ts.map +0 -1
  159. package/types/src/server/dev-server-utils.d.ts +0 -6
  160. package/types/src/server/dev-server-utils.d.ts.map +0 -1
  161. package/types/src/server/dev-server.d.ts +0 -18
  162. package/types/src/server/dev-server.d.ts.map +0 -1
  163. package/types/src/server/hmr-handler.d.ts +0 -19
  164. package/types/src/server/hmr-handler.d.ts.map +0 -1
  165. package/types/src/server/index.d.ts +0 -4
  166. package/types/src/server/index.d.ts.map +0 -1
  167. package/types/src/server/request-handler.d.ts +0 -19
  168. package/types/src/server/request-handler.d.ts.map +0 -1
  169. package/types/src/server-islands/extractor.d.ts +0 -16
  170. package/types/src/server-islands/extractor.d.ts.map +0 -1
  171. package/types/src/server-islands/index.d.ts +0 -3
  172. package/types/src/server-islands/index.d.ts.map +0 -1
  173. package/types/src/utils/cache.d.ts +0 -52
  174. package/types/src/utils/cache.d.ts.map +0 -1
  175. package/types/src/utils/env.d.ts +0 -20
  176. package/types/src/utils/env.d.ts.map +0 -1
  177. package/types/src/utils/importhow.d.ts +0 -15
  178. package/types/src/utils/importhow.d.ts.map +0 -1
  179. package/types/src/utils/index.d.ts +0 -3
  180. package/types/src/utils/index.d.ts.map +0 -1
  181. package/types/src/utils/meta-extractor.d.ts +0 -13
  182. package/types/src/utils/meta-extractor.d.ts.map +0 -1
@@ -1,19 +0,0 @@
1
- // bertui/src/build/processors/asset-processor.js
2
- import { join } from 'path';
3
- import { existsSync, mkdirSync } from 'fs'; // ✅ ADD THIS IMPORT
4
- import { copyImages } from '../image-optimizer.js';
5
-
6
- export async function copyAllStaticAssets(root, outDir) {
7
- const publicDir = join(root, 'public');
8
- const srcImagesDir = join(root, 'src', 'images');
9
-
10
- if (existsSync(publicDir)) {
11
- copyImages(publicDir, outDir);
12
- }
13
-
14
- if (existsSync(srcImagesDir)) {
15
- const distImagesDir = join(outDir, 'images');
16
- mkdirSync(distImagesDir, { recursive: true });
17
- copyImages(srcImagesDir, distImagesDir);
18
- }
19
- }
@@ -1,142 +0,0 @@
1
- // bertui/src/build/processors/css-builder.js - WITH SCSS + CACHING + CSS MODULES
2
- import { join } from 'path';
3
- import { existsSync, readdirSync, mkdirSync } from 'fs';
4
- import logger from '../../logger/logger.js';
5
- import { globalCache } from '../../utils/cache.js';
6
- import { minifyCSS, processSCSS } from '../../css/processor.js';
7
-
8
- export async function buildAllCSS(root, outDir) {
9
- const startTime = process.hrtime.bigint();
10
-
11
- const srcStylesDir = join(root, 'src', 'styles');
12
- // CSS modules scoped CSS is staged here by file-transpiler.js
13
- const modulesStagingDir = join(root, '.bertuibuild', 'styles-staged');
14
- const stylesOutDir = join(outDir, 'styles');
15
-
16
- mkdirSync(stylesOutDir, { recursive: true });
17
-
18
- const cacheKey = `css-build:${root}:${Date.now()}`;
19
- const cached = globalCache.get(cacheKey, { ttl: 1000 });
20
-
21
- if (cached) {
22
- logger.info(`⚡ Using cached CSS (${cached.files} files)`);
23
- await Bun.write(join(stylesOutDir, 'bertui.min.css'), cached.content);
24
- return;
25
- }
26
-
27
- let combinedCSS = '';
28
- let fileCount = 0;
29
-
30
- // 1. Process src/styles/ (plain CSS + SCSS)
31
- if (existsSync(srcStylesDir)) {
32
- await processSCSSDirectory(srcStylesDir, root);
33
- const cssFiles = readdirSync(srcStylesDir).filter(f => f.endsWith('.css') && !f.endsWith('.module.css'));
34
-
35
- logger.info(`Processing ${cssFiles.length} CSS file(s)...`);
36
-
37
- for (const cssFile of cssFiles) {
38
- const srcPath = join(srcStylesDir, cssFile);
39
- const fileBuffer = await globalCache.getFile(srcPath, { logSpeed: true });
40
- if (fileBuffer) {
41
- const content = fileBuffer.toString('utf-8');
42
- combinedCSS += `/* ${cssFile} */\n${content}\n\n`;
43
- fileCount++;
44
- }
45
- }
46
- } else {
47
- logger.info('No styles directory found');
48
- }
49
-
50
- // 2. Include scoped CSS from CSS modules (staged by file-transpiler.js)
51
- if (existsSync(modulesStagingDir)) {
52
- const moduleFiles = readdirSync(modulesStagingDir).filter(f => f.endsWith('.css'));
53
- if (moduleFiles.length > 0) {
54
- logger.info(`Including ${moduleFiles.length} CSS module(s)...`);
55
- for (const cssFile of moduleFiles) {
56
- const srcPath = join(modulesStagingDir, cssFile);
57
- const content = await Bun.file(srcPath).text();
58
- combinedCSS += `/* module: ${cssFile} */\n${content}\n\n`;
59
- fileCount++;
60
- }
61
- }
62
- }
63
-
64
- if (!combinedCSS.trim()) {
65
- await Bun.write(join(stylesOutDir, 'bertui.min.css'), '/* No CSS */');
66
- return;
67
- }
68
-
69
- const combinedPath = join(stylesOutDir, 'bertui.min.css');
70
-
71
- const minifyCacheKey = `minify:${Buffer.from(combinedCSS).length}:${combinedCSS.substring(0, 100)}`;
72
- let minified = globalCache.get(minifyCacheKey);
73
-
74
- if (!minified) {
75
- minified = await minifyCSS(combinedCSS, {
76
- filename: 'bertui.min.css',
77
- sourceMap: false
78
- });
79
- globalCache.set(minifyCacheKey, minified, { ttl: 60000 });
80
- }
81
-
82
- await Bun.write(combinedPath, minified);
83
-
84
- const originalSize = Buffer.byteLength(combinedCSS);
85
- const minifiedSize = Buffer.byteLength(minified);
86
- const reduction = ((1 - minifiedSize / originalSize) * 100).toFixed(1);
87
-
88
- const endTime = process.hrtime.bigint();
89
- const duration = Number(endTime - startTime) / 1000;
90
-
91
- logger.success(`CSS optimized: ${(originalSize/1024).toFixed(2)}KB → ${(minifiedSize/1024).toFixed(2)}KB (-${reduction}%)`);
92
- logger.info(`⚡ Processing time: ${duration.toFixed(3)}µs`);
93
-
94
- globalCache.set(cacheKey, {
95
- files: fileCount,
96
- content: minified,
97
- size: minifiedSize
98
- }, { ttl: 5000 });
99
- }
100
-
101
- async function processSCSSDirectory(stylesDir, root) {
102
- try {
103
- const sass = await import('sass').catch(() => null);
104
- if (!sass) return;
105
-
106
- const files = readdirSync(stylesDir);
107
- const scssFiles = files.filter(f => f.endsWith('.scss') || f.endsWith('.sass'));
108
-
109
- if (scssFiles.length === 0) return;
110
-
111
- logger.info(`📝 Compiling ${scssFiles.length} SCSS files...`);
112
-
113
- for (const file of scssFiles) {
114
- const srcPath = join(stylesDir, file);
115
- const cssPath = join(stylesDir, file.replace(/\.(scss|sass)$/, '.css'));
116
-
117
- const fileBuffer = await globalCache.getFile(srcPath);
118
- const cacheKey = `scss:${file}:${Buffer.from(fileBuffer).length}`;
119
- const cached = globalCache.get(cacheKey);
120
-
121
- if (cached && existsSync(cssPath)) {
122
- logger.debug(`⚡ Cached SCSS: ${file} → ${file.replace(/\.(scss|sass)$/, '.css')}`);
123
- continue;
124
- }
125
-
126
- const result = sass.compile(srcPath, {
127
- style: 'expanded',
128
- sourceMap: false,
129
- loadPaths: [stylesDir, join(root, 'node_modules')]
130
- });
131
-
132
- await Bun.write(cssPath, result.css);
133
- globalCache.set(cacheKey, true, { ttl: 30000 });
134
-
135
- logger.debug(` ${file} → ${file.replace(/\.(scss|sass)$/, '.css')}`);
136
- }
137
-
138
- logger.success(`✅ SCSS compilation complete`);
139
- } catch (error) {
140
- logger.warn(`SCSS processing skipped: ${error.message}`);
141
- }
142
- }
@@ -1,12 +0,0 @@
1
- // bertui/src/build/server-island-validator.js
2
- // Server Islands removed — all pages are client-rendered.
3
-
4
- export function validateServerIsland(sourceCode, filePath) {
5
- return { valid: true, errors: [] };
6
- }
7
-
8
- export function displayValidationErrors(filePath, errors) {}
9
-
10
- export async function validateAllServerIslands(routes) {
11
- return { serverIslands: [], validationResults: [] };
12
- }
package/src/build.js DELETED
@@ -1,266 +0,0 @@
1
- // bertui/src/build.js
2
- import { join } from 'path';
3
- import { existsSync, mkdirSync, rmSync, readdirSync } from 'fs';
4
- import logger from './logger/logger.js';
5
- import { loadEnvVariables } from './utils/env.js';
6
- import { globalCache } from './utils/cache.js';
7
-
8
- import { compileForBuild } from './build/compiler/index.js';
9
- import { buildAllCSS } from './build/processors/css-builder.js';
10
- import { copyAllStaticAssets } from './build/processors/asset-processor.js';
11
- import { generateProductionHTML } from './build/generators/html-generator.js';
12
- import { generateSitemap } from './build/generators/sitemap-generator.js';
13
- import { generateRobots } from './build/generators/robots-generator.js';
14
- import { compileLayouts } from './layouts/index.js';
15
- import { compileLoadingComponents } from './loading/index.js';
16
- import { analyzeRoutes } from './hydration/index.js';
17
- import { analyzeBuild } from './analyzer/index.js';
18
-
19
- const TOTAL_STEPS = 10;
20
-
21
- export async function buildProduction(options = {}) {
22
- const root = options.root || process.cwd();
23
- const buildDir = join(root, '.bertuibuild');
24
- const outDir = join(root, 'dist');
25
-
26
- process.env.NODE_ENV = 'production';
27
-
28
- logger.printHeader('BUILD');
29
-
30
- if (existsSync(buildDir)) rmSync(buildDir, { recursive: true, force: true });
31
- if (existsSync(outDir)) rmSync(outDir, { recursive: true, force: true });
32
- mkdirSync(buildDir, { recursive: true });
33
- mkdirSync(outDir, { recursive: true });
34
-
35
- let totalKB = '0';
36
-
37
- try {
38
- // ── Step 1: Env ──────────────────────────────────────────────────────────
39
- logger.step(1, TOTAL_STEPS, 'Loading env');
40
- const envVars = loadEnvVariables(root);
41
- const { loadConfig } = await import('./config/loadConfig.js');
42
- const config = await loadConfig(root);
43
- const importhow = config.importhow || {};
44
- logger.stepDone('Loading env', `${Object.keys(envVars).length} vars`);
45
-
46
- // ── Step 2: Compile ──────────────────────────────────────────────────────
47
- logger.step(2, TOTAL_STEPS, 'Compiling');
48
- const { routes } = await compileForBuild(root, buildDir, envVars, config);
49
- logger.stepDone('Compiling', `${routes.length} routes`);
50
-
51
- // ── Step 3: Layouts ──────────────────────────────────────────────────────
52
- logger.step(3, TOTAL_STEPS, 'Layouts');
53
- const layouts = await compileLayouts(root, buildDir);
54
- logger.stepDone('Layouts', `${Object.keys(layouts).length} found`);
55
-
56
- // ── Step 4: Loading states ───────────────────────────────────────────────
57
- logger.step(4, TOTAL_STEPS, 'Loading states');
58
- await compileLoadingComponents(root, buildDir);
59
- logger.stepDone('Loading states');
60
-
61
- // ── Step 5: Hydration analysis ───────────────────────────────────────────
62
- logger.step(5, TOTAL_STEPS, 'Hydration analysis');
63
- const analyzedRoutes = await analyzeRoutes(routes);
64
- logger.stepDone('Hydration analysis',
65
- `${analyzedRoutes.interactive.length} interactive · ${analyzedRoutes.static.length} static`);
66
-
67
- // ── Step 6: CSS ──────────────────────────────────────────────────────────
68
- logger.step(6, TOTAL_STEPS, 'Processing CSS');
69
- await buildAllCSS(root, outDir);
70
- logger.stepDone('Processing CSS');
71
-
72
- // ── Step 7: Static assets ────────────────────────────────────────────────
73
- logger.step(7, TOTAL_STEPS, 'Static assets');
74
- await copyAllStaticAssets(root, outDir);
75
- logger.stepDone('Static assets');
76
-
77
- // ── Step 8: Bundle JS ────────────────────────────────────────────────────
78
- logger.step(8, TOTAL_STEPS, 'Bundling JS');
79
- const buildEntry = join(buildDir, 'main.js');
80
- if (!existsSync(buildEntry)) {
81
- throw new Error('main.js not found in build dir — make sure src/main.jsx exists');
82
- }
83
- const result = await bundleJavaScript(buildEntry, outDir, envVars, buildDir, root, config);
84
- totalKB = (result.outputs.reduce((a, o) => a + (o.size || 0), 0) / 1024).toFixed(1);
85
- logger.stepDone('Bundling JS', `${totalKB} KB · tree-shaken`);
86
-
87
- // ── Step 9: HTML ─────────────────────────────────────────────────────────
88
- logger.step(9, TOTAL_STEPS, 'Generating HTML');
89
- await generateProductionHTML(root, outDir, result, routes, config);
90
- logger.stepDone('Generating HTML', `${routes.length} pages`);
91
-
92
- // ── Step 10: Sitemap + robots ────────────────────────────────────────────
93
- logger.step(10, TOTAL_STEPS, 'Sitemap & robots');
94
- await generateSitemap(routes, config, outDir);
95
- await generateRobots(config, outDir, routes);
96
- logger.stepDone('Sitemap & robots');
97
-
98
- if (existsSync(buildDir)) rmSync(buildDir, { recursive: true, force: true });
99
-
100
- try {
101
- await analyzeBuild(outDir, { outputFile: join(outDir, 'bundle-report.html') });
102
- } catch (reportErr) {
103
- logger.debug(`Bundle report generation skipped: ${reportErr.message}`);
104
- }
105
-
106
- logger.printSummary({
107
- routes: routes.length,
108
- interactive: analyzedRoutes.interactive.length,
109
- staticRoutes: analyzedRoutes.static.length,
110
- jsSize: `${totalKB} KB`,
111
- outDir: 'dist/',
112
- });
113
-
114
- logger.cleanup();
115
- return { success: true };
116
-
117
- } catch (error) {
118
- logger.stepFail('Build', error?.message || String(error));
119
- if (existsSync(buildDir)) rmSync(buildDir, { recursive: true, force: true });
120
- throw error;
121
- }
122
- }
123
-
124
- // ─────────────────────────────────────────────────────────────────────────────
125
-
126
- async function generateProductionImportMap(root, config) {
127
- const importMap = {
128
- 'react': 'https://esm.sh/react@18.2.0',
129
- 'react-dom': 'https://esm.sh/react-dom@18.2.0',
130
- 'react-dom/client': 'https://esm.sh/react-dom@18.2.0/client',
131
- 'react/jsx-runtime': 'https://esm.sh/react@18.2.0/jsx-runtime',
132
- '@bunnyx/api': '/bunnyx-api/api-client.js',
133
- };
134
-
135
- const nodeModulesDir = join(root, 'node_modules');
136
- if (!existsSync(nodeModulesDir)) return importMap;
137
-
138
- try {
139
- for (const pkg of readdirSync(nodeModulesDir)) {
140
- if (!pkg.startsWith('bertui-') || pkg.startsWith('.')) continue;
141
- const pkgDir = join(nodeModulesDir, pkg);
142
- const pkgJson = join(pkgDir, 'package.json');
143
- if (!existsSync(pkgJson)) continue;
144
- try {
145
- const p = JSON.parse(await Bun.file(pkgJson).text());
146
- for (const entry of [p.browser, p.module, p.main, 'dist/index.js', 'index.js'].filter(Boolean)) {
147
- if (existsSync(join(pkgDir, entry))) {
148
- importMap[pkg] = `/assets/node_modules/${pkg}/${entry}`;
149
- break;
150
- }
151
- }
152
- } catch { continue; }
153
- }
154
- } catch { /* ignore */ }
155
-
156
- return importMap;
157
- }
158
-
159
- async function copyNodeModulesToDist(root, outDir, importMap) {
160
- const { mkdirSync } = await import('fs');
161
- const dest = join(outDir, 'assets', 'node_modules');
162
- mkdirSync(dest, { recursive: true });
163
- const src = join(root, 'node_modules');
164
-
165
- for (const [, assetPath] of Object.entries(importMap)) {
166
- if (assetPath.startsWith('https://')) continue;
167
- const match = assetPath.match(/\/assets\/node_modules\/(.+)$/);
168
- if (!match) continue;
169
- const parts = match[1].split('/');
170
- const pkgName = parts[0];
171
- const subPath = parts.slice(1);
172
- const srcFile = join(src, pkgName, ...subPath);
173
- const destFile = join(dest, pkgName, ...subPath);
174
- mkdirSync(join(dest, pkgName, ...subPath.slice(0, -1)), { recursive: true });
175
- if (existsSync(srcFile)) await Bun.write(destFile, Bun.file(srcFile));
176
- }
177
- }
178
-
179
- async function bundleJavaScript(buildEntry, outDir, envVars, buildDir, root, config) {
180
- const originalCwd = process.cwd();
181
- process.chdir(buildDir);
182
-
183
- try {
184
- const importMap = await generateProductionImportMap(root, config);
185
- await Bun.write(join(outDir, 'import-map.json'), JSON.stringify({ imports: importMap }, null, 2));
186
- await copyNodeModulesToDist(root, outDir, importMap);
187
-
188
- const bunnyxSrc = join(root, 'bunnyx-api', 'api-client.js');
189
- if (existsSync(bunnyxSrc)) {
190
- const { mkdirSync } = await import('fs');
191
- mkdirSync(join(outDir, 'bunnyx-api'), { recursive: true });
192
- await Bun.write(join(outDir, 'bunnyx-api', 'api-client.js'), Bun.file(bunnyxSrc));
193
- }
194
-
195
- const cssModulePlugin = {
196
- name: 'css-modules',
197
- setup(build) {
198
- build.onLoad({ filter: /\.module\.css$/ }, () => ({
199
- contents: 'export default new Proxy({}, { get: (_, k) => k });',
200
- loader: 'js',
201
- }));
202
- build.onLoad({ filter: /\.css$/ }, () => ({
203
- contents: '',
204
- loader: 'js',
205
- }));
206
- },
207
- };
208
-
209
- let result;
210
- try {
211
- result = await Bun.build({
212
- entrypoints: [buildEntry],
213
- outdir: join(outDir, 'assets'),
214
- target: 'browser',
215
- format: 'esm',
216
- plugins: [cssModulePlugin],
217
- minify: {
218
- whitespace: true,
219
- syntax: true,
220
- identifiers: true,
221
- },
222
- splitting: true,
223
- sourcemap: 'external',
224
- metafile: true,
225
- naming: {
226
- entry: 'js/[name]-[hash].js',
227
- chunk: 'js/chunks/[name]-[hash].js',
228
- asset: 'assets/[name]-[hash].[ext]',
229
- },
230
- external: ['react', 'react-dom', 'react-dom/client', 'react/jsx-runtime', '@bunnyx/api'],
231
- define: {
232
- 'process.env.NODE_ENV': '"production"',
233
- ...Object.fromEntries(
234
- Object.entries(envVars).map(([k, v]) => [`process.env.${k}`, JSON.stringify(v)])
235
- ),
236
- },
237
- });
238
- } catch (err) {
239
- throw new Error(`Bun.build failed: ${err?.message || String(err)}`);
240
- }
241
-
242
- if (!result.success) {
243
- const msgs = (result.logs || []).map(l => l?.message || l?.text || JSON.stringify(l)).join('\n');
244
- throw new Error(`Bundle failed\n${msgs || 'Check your imports for .jsx extensions or unresolvable paths'}`);
245
- }
246
-
247
- if (result.metafile) {
248
- await Bun.write(join(outDir, 'metafile.json'), JSON.stringify(result.metafile, null, 2));
249
- }
250
-
251
- return result;
252
-
253
- } finally {
254
- process.chdir(originalCwd);
255
- }
256
- }
257
-
258
- export async function build(options = {}) {
259
- try {
260
- await buildProduction(options);
261
- process.exit(0);
262
- } catch (error) {
263
- console.error('Build error:', error?.message || String(error));
264
- process.exit(1);
265
- }
266
- }
package/src/cli.js DELETED
@@ -1,131 +0,0 @@
1
- // bertui/src/cli.js - WITH ALL COMMANDS
2
- import { startDev } from './dev.js';
3
- import { buildProduction } from './build.js';
4
- import { startPreviewServer } from './serve.js';
5
- import { scaffold, parseCreateArgs } from './scaffolder/index.js';
6
- import { analyzeBuild } from './analyzer/index.js';
7
- import logger from './logger/logger.js';
8
- import { join } from 'path';
9
-
10
- export function program() {
11
- const args = process.argv.slice(2);
12
- const command = args[0] || 'dev';
13
-
14
- switch (command) {
15
- case 'dev': {
16
- const devPort = getArg('--port', '-p') || 3000;
17
- startDev({
18
- port: parseInt(devPort),
19
- root: process.cwd(),
20
- });
21
- break;
22
- }
23
-
24
- case 'build': {
25
- buildProduction({ root: process.cwd() });
26
- break;
27
- }
28
-
29
- case 'serve':
30
- case 'preview': {
31
- const previewPort = getArg('--port', '-p') || 5000;
32
- startPreviewServer({
33
- port: parseInt(previewPort),
34
- root: process.cwd(),
35
- dir: 'dist',
36
- });
37
- break;
38
- }
39
-
40
- // ✅ NEW: Component/page/layout scaffolder
41
- case 'create': {
42
- const createArgs = args.slice(1);
43
- const parsed = parseCreateArgs(createArgs);
44
- if (parsed) {
45
- scaffold(parsed.type, parsed.name, { root: process.cwd() })
46
- .then(result => {
47
- if (!result) process.exit(1);
48
- })
49
- .catch(err => {
50
- logger.error(`Create failed: ${err.message}`);
51
- process.exit(1);
52
- });
53
- }
54
- break;
55
- }
56
-
57
- // ✅ NEW: Bundle analyzer
58
- case 'analyze': {
59
- const outDir = join(process.cwd(), 'dist');
60
- const open = args.includes('--open');
61
- analyzeBuild(outDir, { open })
62
- .then(result => {
63
- if (!result) {
64
- logger.error('No build found. Run: bertui build');
65
- process.exit(1);
66
- }
67
- })
68
- .catch(err => {
69
- logger.error(`Analyze failed: ${err.message}`);
70
- process.exit(1);
71
- });
72
- break;
73
- }
74
-
75
- case '--version':
76
- case '-v':
77
- console.log('bertui v1.2.0');
78
- break;
79
-
80
- case '--help':
81
- case '-h':
82
- showHelp();
83
- break;
84
-
85
- default:
86
- logger.error(`Unknown command: ${command}`);
87
- showHelp();
88
- }
89
- }
90
-
91
- function getArg(longForm, shortForm) {
92
- const args = process.argv.slice(2);
93
- const longIndex = args.indexOf(longForm);
94
- const shortIndex = args.indexOf(shortForm);
95
- const index = longIndex !== -1 ? longIndex : shortIndex;
96
- return index !== -1 && args[index + 1] ? args[index + 1] : null;
97
- }
98
-
99
- function showHelp() {
100
- logger.bigLog('BERTUI CLI', { color: 'blue' });
101
- console.log(`
102
- Commands:
103
- bertui dev [--port] Start development server (default: 3000)
104
- bertui build Build for production
105
- bertui serve [--port] Preview production build (default: 5000)
106
- bertui analyze [--open] Analyze bundle size (opens report in browser)
107
-
108
- bertui create component <Name> Scaffold a React component
109
- bertui create page <name> Scaffold a page (adds to file-based routing)
110
- bertui create layout <name> Scaffold a layout (default wraps all pages)
111
- bertui create loading <route> Scaffold a per-route loading state
112
- bertui create middleware Scaffold src/middleware.ts
113
-
114
- Options:
115
- --port, -p <number> Port for server
116
- --open Open browser after command
117
-
118
- Examples:
119
- bertui dev
120
- bertui dev --port 8080
121
- bertui build
122
- bertui analyze --open
123
- bertui create component Button
124
- bertui create page About
125
- bertui create page blog/[slug]
126
- bertui create layout default
127
- bertui create layout blog
128
- bertui create loading blog
129
- bertui create middleware
130
- `);
131
- }