bertui 1.2.2 → 1.2.4
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/index.js +1 -1
- package/package.json +43 -25
- package/src/build/compiler/file-transpiler.js +1 -0
- package/src/build/generators/html-generator.js +24 -9
- package/src/build.js +12 -3
- package/src/client/compiler.js +1 -0
- package/src/dev.js +49 -218
- package/src/server/dev-server-utils.js +2 -1
- package/types/bin/bertui.d.ts +3 -0
- package/types/bin/bertui.d.ts.map +1 -0
- package/types/error-overlay.d.ts +2 -0
- package/types/error-overlay.d.ts.map +1 -0
- package/types/index.d.ts +26 -177
- package/types/index.d.ts.map +1 -0
- package/types/scripts/fix-wasm-exports.d.ts +2 -0
- package/types/scripts/fix-wasm-exports.d.ts.map +1 -0
- package/types/src/analyzer/index.d.ts +8 -0
- package/types/src/analyzer/index.d.ts.map +1 -0
- package/types/src/build/compiler/file-transpiler.d.ts +5 -0
- package/types/src/build/compiler/file-transpiler.d.ts.map +1 -0
- package/types/src/build/compiler/index.d.ts +12 -0
- package/types/src/build/compiler/index.d.ts.map +1 -0
- package/types/src/build/compiler/route-discoverer.d.ts +2 -0
- package/types/src/build/compiler/route-discoverer.d.ts.map +1 -0
- package/types/src/build/compiler/router-generator.d.ts +2 -0
- package/types/src/build/compiler/router-generator.d.ts.map +1 -0
- package/types/src/build/css-builder.d.ts +18 -0
- package/types/src/build/css-builder.d.ts.map +1 -0
- package/types/src/build/generators/html-generator.d.ts +2 -0
- package/types/src/build/generators/html-generator.d.ts.map +1 -0
- package/types/src/build/generators/robots-generator.d.ts +11 -0
- package/types/src/build/generators/robots-generator.d.ts.map +1 -0
- package/types/src/build/generators/sitemap-generator.d.ts +5 -0
- package/types/src/build/generators/sitemap-generator.d.ts.map +1 -0
- package/types/src/build/image-optimizer.d.ts +11 -0
- package/types/src/build/image-optimizer.d.ts.map +1 -0
- package/types/src/build/processors/asset-processor.d.ts +2 -0
- package/types/src/build/processors/asset-processor.d.ts.map +1 -0
- package/types/src/build/processors/css-builder.d.ts +2 -0
- package/types/src/build/processors/css-builder.d.ts.map +1 -0
- package/types/src/build/server-island-validator.d.ts +27 -0
- package/types/src/build/server-island-validator.d.ts.map +1 -0
- package/types/src/build.d.ts +5 -0
- package/types/src/build.d.ts.map +1 -0
- package/types/src/cli.d.ts +2 -0
- package/types/src/cli.d.ts.map +1 -0
- package/types/src/client/compiler.d.ts +16 -0
- package/types/src/client/compiler.d.ts.map +1 -0
- package/types/src/client/fast-refresh.d.ts +3 -0
- package/types/src/client/fast-refresh.d.ts.map +1 -0
- package/types/src/client/hmr-runtime.d.ts +4 -0
- package/types/src/client/hmr-runtime.d.ts.map +1 -0
- package/types/src/compiler/index.d.ts +8 -0
- package/types/src/compiler/index.d.ts.map +1 -0
- package/types/src/compiler/router-generator-pure.d.ts +2 -0
- package/types/src/compiler/router-generator-pure.d.ts.map +1 -0
- package/types/src/compiler/transform.d.ts +36 -0
- package/types/src/compiler/transform.d.ts.map +1 -0
- package/types/src/config/defaultConfig.d.ts +26 -0
- package/types/src/config/defaultConfig.d.ts.map +1 -0
- package/types/src/config/index.d.ts +3 -0
- package/types/src/config/index.d.ts.map +1 -0
- package/types/src/config/loadConfig.d.ts +2 -0
- package/types/src/config/loadConfig.d.ts.map +1 -0
- package/types/src/css/index.d.ts +6 -0
- package/types/src/css/index.d.ts.map +1 -0
- package/types/src/css/processor.d.ts +23 -0
- package/types/src/css/processor.d.ts.map +1 -0
- package/types/src/dev.d.ts +2 -0
- package/types/src/dev.d.ts.map +1 -0
- package/types/src/hydration/index.d.ts +33 -0
- package/types/src/hydration/index.d.ts.map +1 -0
- package/types/src/image-optimizer/index.d.ts +24 -0
- package/types/src/image-optimizer/index.d.ts.map +1 -0
- package/types/src/images/index.d.ts +12 -0
- package/types/src/images/index.d.ts.map +1 -0
- package/types/src/images/processor.d.ts +30 -0
- package/types/src/images/processor.d.ts.map +1 -0
- package/types/src/layouts/index.d.ts +28 -0
- package/types/src/layouts/index.d.ts.map +1 -0
- package/types/src/loading/index.d.ts +28 -0
- package/types/src/loading/index.d.ts.map +1 -0
- package/types/src/logger/logger.d.ts +30 -0
- package/types/src/logger/logger.d.ts.map +1 -0
- package/types/src/middleware/index.d.ts +61 -0
- package/types/src/middleware/index.d.ts.map +1 -0
- package/types/src/router/Router.d.ts +16 -0
- package/types/src/router/Router.d.ts.map +1 -0
- package/types/src/router/SSRRouter.d.ts +20 -0
- package/types/src/router/SSRRouter.d.ts.map +1 -0
- package/types/src/router/index.d.ts +3 -0
- package/types/src/router/index.d.ts.map +1 -0
- package/types/src/scaffolder/index.d.ts +14 -0
- package/types/src/scaffolder/index.d.ts.map +1 -0
- package/types/src/serve.d.ts +3 -0
- package/types/src/serve.d.ts.map +1 -0
- package/types/src/server/dev-handler.d.ts +13 -0
- package/types/src/server/dev-handler.d.ts.map +1 -0
- package/types/src/server/dev-server-utils.d.ts +6 -0
- package/types/src/server/dev-server-utils.d.ts.map +1 -0
- package/types/src/server/dev-server.d.ts +18 -0
- package/types/src/server/dev-server.d.ts.map +1 -0
- package/types/src/server/hmr-handler.d.ts +19 -0
- package/types/src/server/hmr-handler.d.ts.map +1 -0
- package/types/src/server/index.d.ts +4 -0
- package/types/src/server/index.d.ts.map +1 -0
- package/types/src/server/request-handler.d.ts +19 -0
- package/types/src/server/request-handler.d.ts.map +1 -0
- package/types/src/server-islands/extractor.d.ts +16 -0
- package/types/src/server-islands/extractor.d.ts.map +1 -0
- package/types/src/server-islands/index.d.ts +3 -0
- package/types/src/server-islands/index.d.ts.map +1 -0
- package/types/src/utils/cache.d.ts +52 -0
- package/types/src/utils/cache.d.ts.map +1 -0
- package/types/src/utils/env.d.ts +20 -0
- package/types/src/utils/env.d.ts.map +1 -0
- package/types/src/utils/importhow.d.ts +15 -0
- package/types/src/utils/importhow.d.ts.map +1 -0
- package/types/src/utils/index.d.ts +3 -0
- package/types/src/utils/index.d.ts.map +1 -0
- package/types/src/utils/meta-extractor.d.ts +13 -0
- package/types/src/utils/meta-extractor.d.ts.map +1 -0
- package/types/config.d.ts +0 -33
- package/types/react.d.ts +0 -16
- package/types/router.d.ts +0 -79
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bertui",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.4",
|
|
4
4
|
"description": "Lightning-fast React dev server powered by Bun - Now with Rust image optimization (WASM, no Rust required for users)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -8,31 +8,49 @@
|
|
|
8
8
|
"bin": {
|
|
9
9
|
"bertui": "./bin/bertui.js"
|
|
10
10
|
},
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
"./hmr": {
|
|
18
|
-
"import": "./src/client/hmr-runtime.js"
|
|
19
|
-
},
|
|
20
|
-
"./image-optimizer": {
|
|
21
|
-
"import": "./src/image-optimizer/index.js"
|
|
22
|
-
},
|
|
23
|
-
"./router": {
|
|
24
|
-
"types": "./types/router.d.ts",
|
|
25
|
-
"import": "./src/router/index.js"
|
|
26
|
-
},
|
|
27
|
-
"./config": {
|
|
28
|
-
"types": "./types/config.d.ts",
|
|
29
|
-
"import": "./src/config/index.js"
|
|
30
|
-
},
|
|
31
|
-
"./logger": {
|
|
32
|
-
"import": "./src/logger/logger.js"
|
|
33
|
-
},
|
|
34
|
-
"./styles": "./src/styles/bertui.css"
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./types/index.d.ts",
|
|
14
|
+
"import": "./index.js",
|
|
15
|
+
"default": "./index.js"
|
|
35
16
|
},
|
|
17
|
+
"./hmr": {
|
|
18
|
+
"import": "./src/client/hmr-runtime.js"
|
|
19
|
+
},
|
|
20
|
+
"./image-optimizer": {
|
|
21
|
+
"import": "./src/image-optimizer/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./router": {
|
|
24
|
+
"types": "./types/router.d.ts",
|
|
25
|
+
"import": "./src/router/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./config": {
|
|
28
|
+
"types": "./types/config.d.ts",
|
|
29
|
+
"import": "./src/config/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./logger": {
|
|
32
|
+
"import": "./src/logger/logger.js"
|
|
33
|
+
},
|
|
34
|
+
"./styles": "./src/styles/bertui.css",
|
|
35
|
+
"./compiler": {
|
|
36
|
+
"import": "./src/client/compiler.js"
|
|
37
|
+
},
|
|
38
|
+
"./layouts": {
|
|
39
|
+
"import": "./src/layouts/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./loading": {
|
|
42
|
+
"import": "./src/loading/index.js"
|
|
43
|
+
},
|
|
44
|
+
"./hydration": {
|
|
45
|
+
"import": "./src/hydration/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./dev": {
|
|
48
|
+
"import": "./src/server/dev-server-utils.js"
|
|
49
|
+
},
|
|
50
|
+
"./build": {
|
|
51
|
+
"import": "./src/build.js"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
36
54
|
"files": [
|
|
37
55
|
"bin",
|
|
38
56
|
"src",
|
|
@@ -49,6 +49,7 @@ async function _compileDir(srcDir, buildDir, root, envVars, aliasMap) {
|
|
|
49
49
|
const stat = statSync(srcPath);
|
|
50
50
|
|
|
51
51
|
if (stat.isDirectory()) {
|
|
52
|
+
if (file === 'api') { logger.debug('⏭️ Skipping api/'); continue; }
|
|
52
53
|
const subBuildDir = join(buildDir, file);
|
|
53
54
|
mkdirSync(subBuildDir, { recursive: true });
|
|
54
55
|
await _compileDir(srcPath, subBuildDir, root, envVars, aliasMap);
|
|
@@ -17,7 +17,6 @@ export async function generateProductionHTML(root, outDir, buildResult, routes,
|
|
|
17
17
|
const bundlePath = relative(outDir, mainBundle.path).replace(/\\/g, '/');
|
|
18
18
|
const defaultMeta = config.meta || {};
|
|
19
19
|
|
|
20
|
-
// ✅ Copy bertui-icons AND bertui-animate to dist/
|
|
21
20
|
const bertuiPackages = await copyBertuiPackagesToProduction(root, outDir);
|
|
22
21
|
|
|
23
22
|
logger.info(`📄 Generating HTML for ${routes.length} routes...`);
|
|
@@ -36,12 +35,12 @@ export async function generateProductionHTML(root, outDir, buildResult, routes,
|
|
|
36
35
|
logger.success(`✅ HTML generation complete for ${routes.length} routes`);
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
// ✅ UPDATED: Copy ALL bertui-* packages to dist/
|
|
40
38
|
async function copyBertuiPackagesToProduction(root, outDir) {
|
|
41
39
|
const nodeModulesDir = join(root, 'node_modules');
|
|
42
40
|
const packages = {
|
|
43
41
|
bertuiIcons: false,
|
|
44
|
-
bertuiAnimate: false
|
|
42
|
+
bertuiAnimate: false,
|
|
43
|
+
elysiaEden: false
|
|
45
44
|
};
|
|
46
45
|
|
|
47
46
|
if (!existsSync(nodeModulesDir)) {
|
|
@@ -63,14 +62,13 @@ async function copyBertuiPackagesToProduction(root, outDir) {
|
|
|
63
62
|
}
|
|
64
63
|
}
|
|
65
64
|
|
|
66
|
-
//
|
|
65
|
+
// Copy bertui-animate CSS files
|
|
67
66
|
const bertuiAnimateSource = join(nodeModulesDir, 'bertui-animate', 'dist');
|
|
68
67
|
if (existsSync(bertuiAnimateSource)) {
|
|
69
68
|
try {
|
|
70
69
|
const bertuiAnimateDest = join(outDir, 'css');
|
|
71
70
|
mkdirSync(bertuiAnimateDest, { recursive: true });
|
|
72
71
|
|
|
73
|
-
// Copy minified CSS
|
|
74
72
|
const minCSSPath = join(bertuiAnimateSource, 'bertui-animate.min.css');
|
|
75
73
|
if (existsSync(minCSSPath)) {
|
|
76
74
|
cpSync(minCSSPath, join(bertuiAnimateDest, 'bertui-animate.min.css'));
|
|
@@ -81,6 +79,20 @@ async function copyBertuiPackagesToProduction(root, outDir) {
|
|
|
81
79
|
logger.error(`Failed to copy bertui-animate: ${error.message}`);
|
|
82
80
|
}
|
|
83
81
|
}
|
|
82
|
+
|
|
83
|
+
// Copy @elysiajs/eden
|
|
84
|
+
const elysiaEdenSource = join(nodeModulesDir, '@elysiajs', 'eden');
|
|
85
|
+
if (existsSync(elysiaEdenSource)) {
|
|
86
|
+
try {
|
|
87
|
+
const elysiaEdenDest = join(outDir, 'node_modules', '@elysiajs', 'eden');
|
|
88
|
+
mkdirSync(join(outDir, 'node_modules', '@elysiajs'), { recursive: true });
|
|
89
|
+
cpSync(elysiaEdenSource, elysiaEdenDest, { recursive: true });
|
|
90
|
+
logger.success('✅ Copied @elysiajs/eden to dist/node_modules/');
|
|
91
|
+
packages.elysiaEden = true;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
logger.error(`Failed to copy @elysiajs/eden: ${error.message}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
84
96
|
|
|
85
97
|
return packages;
|
|
86
98
|
}
|
|
@@ -261,7 +273,6 @@ async function extractStaticHTMLFromComponent(sourceCode, filePath) {
|
|
|
261
273
|
}
|
|
262
274
|
}
|
|
263
275
|
|
|
264
|
-
// ✅ UPDATED: Add bertui-animate CSS to production HTML
|
|
265
276
|
function generateHTML(meta, route, bundlePath, staticHTML = '', isServerIsland = false, bertuiPackages = {}) {
|
|
266
277
|
const rootContent = staticHTML
|
|
267
278
|
? `<div id="root">${staticHTML}</div>`
|
|
@@ -271,15 +282,18 @@ function generateHTML(meta, route, bundlePath, staticHTML = '', isServerIsland =
|
|
|
271
282
|
? '<!-- 🏝️ Server Island: Static content rendered at build time -->'
|
|
272
283
|
: '<!-- ⚡ Client-only: Content rendered by JavaScript -->';
|
|
273
284
|
|
|
274
|
-
// ✅ Add bertui-icons to import map
|
|
275
285
|
const bertuiIconsImport = bertuiPackages.bertuiIcons
|
|
276
286
|
? ',\n "bertui-icons": "/node_modules/bertui-icons/generated/index.js"'
|
|
277
287
|
: '';
|
|
278
288
|
|
|
279
|
-
// ✅ Add bertui-animate CSS link
|
|
280
289
|
const bertuiAnimateCSS = bertuiPackages.bertuiAnimate
|
|
281
290
|
? ' <link rel="stylesheet" href="/css/bertui-animate.min.css">'
|
|
282
291
|
: '';
|
|
292
|
+
|
|
293
|
+
// ✅ NEW: @elysiajs/eden local import map
|
|
294
|
+
const elysiaEdenImport = bertuiPackages.elysiaEden
|
|
295
|
+
? ',\n "@elysiajs/eden": "/node_modules/@elysiajs/eden/dist/index.mjs"'
|
|
296
|
+
: '';
|
|
283
297
|
|
|
284
298
|
return `<!DOCTYPE html>
|
|
285
299
|
<html lang="${meta.lang || 'en'}">
|
|
@@ -306,8 +320,9 @@ ${bertuiAnimateCSS}
|
|
|
306
320
|
"imports": {
|
|
307
321
|
"react": "https://esm.sh/react@18.2.0",
|
|
308
322
|
"react-dom": "https://esm.sh/react-dom@18.2.0",
|
|
323
|
+
"@bunnyx/api": "/bunnyx-api/api-client.js",
|
|
309
324
|
"react-dom/client": "https://esm.sh/react-dom@18.2.0/client",
|
|
310
|
-
"react/jsx-runtime": "https://esm.sh/react@18.2.0/jsx-runtime"${bertuiIconsImport}
|
|
325
|
+
"react/jsx-runtime": "https://esm.sh/react@18.2.0/jsx-runtime"${bertuiIconsImport}${elysiaEdenImport}
|
|
311
326
|
}
|
|
312
327
|
}
|
|
313
328
|
</script>
|
package/src/build.js
CHANGED
|
@@ -97,7 +97,8 @@ export async function buildProduction(options = {}) {
|
|
|
97
97
|
|
|
98
98
|
if (existsSync(buildDir)) rmSync(buildDir, { recursive: true, force: true });
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
// Fire-and-forget — don't let the report generator block process exit
|
|
101
|
+
analyzeBuild(outDir, { outputFile: join(outDir, 'bundle-report.html') }).catch(() => {});
|
|
101
102
|
|
|
102
103
|
// ── Summary ──────────────────────────────────────────────────────────────
|
|
103
104
|
logger.printSummary({
|
|
@@ -126,6 +127,7 @@ async function generateProductionImportMap(root, config) {
|
|
|
126
127
|
'react-dom': 'https://esm.sh/react-dom@18.2.0',
|
|
127
128
|
'react-dom/client': 'https://esm.sh/react-dom@18.2.0/client',
|
|
128
129
|
'react/jsx-runtime': 'https://esm.sh/react@18.2.0/jsx-runtime',
|
|
130
|
+
'@bunnyx/api': '/bunnyx-api/api-client.js',
|
|
129
131
|
};
|
|
130
132
|
|
|
131
133
|
const nodeModulesDir = join(root, 'node_modules');
|
|
@@ -183,6 +185,13 @@ async function bundleJavaScript(buildEntry, routerPath, outDir, envVars, buildDi
|
|
|
183
185
|
await Bun.write(join(outDir, 'import-map.json'), JSON.stringify({ imports: importMap }, null, 2));
|
|
184
186
|
await copyNodeModulesToDist(root, outDir, importMap);
|
|
185
187
|
|
|
188
|
+
// Copy @bunnyx/api client to dist so the importmap entry resolves
|
|
189
|
+
const bunnyxSrc = join(root, 'bunnyx-api', 'api-client.js');
|
|
190
|
+
if (existsSync(bunnyxSrc)) {
|
|
191
|
+
mkdirSync(join(outDir, 'bunnyx-api'), { recursive: true });
|
|
192
|
+
await Bun.write(join(outDir, 'bunnyx-api', 'api-client.js'), Bun.file(bunnyxSrc));
|
|
193
|
+
}
|
|
194
|
+
|
|
186
195
|
const result = await Bun.build({
|
|
187
196
|
entrypoints,
|
|
188
197
|
outdir: join(outDir, 'assets'),
|
|
@@ -201,7 +210,7 @@ async function bundleJavaScript(buildEntry, routerPath, outDir, envVars, buildDi
|
|
|
201
210
|
chunk: 'js/chunks/[name]-[hash].js',
|
|
202
211
|
asset: 'assets/[name]-[hash].[ext]',
|
|
203
212
|
},
|
|
204
|
-
external: ['react', 'react-dom', 'react-dom/client', 'react/jsx-runtime'],
|
|
213
|
+
external: ['react', 'react-dom', 'react-dom/client', 'react/jsx-runtime', '@bunnyx/api'],
|
|
205
214
|
define: {
|
|
206
215
|
'process.env.NODE_ENV': '"production"',
|
|
207
216
|
...Object.fromEntries(
|
|
@@ -228,9 +237,9 @@ async function bundleJavaScript(buildEntry, routerPath, outDir, envVars, buildDi
|
|
|
228
237
|
export async function build(options = {}) {
|
|
229
238
|
try {
|
|
230
239
|
await buildProduction(options);
|
|
231
|
-
process.exit(0);
|
|
232
240
|
} catch (error) {
|
|
233
241
|
console.error(error);
|
|
234
242
|
process.exit(1);
|
|
235
243
|
}
|
|
244
|
+
process.exit(0);
|
|
236
245
|
}
|
package/src/client/compiler.js
CHANGED
|
@@ -302,6 +302,7 @@ async function compileDirectory(srcDir, outDir, root, envVars, aliasMap) {
|
|
|
302
302
|
|
|
303
303
|
if (stat.isDirectory()) {
|
|
304
304
|
if (file === 'templates') { logger.debug('⏭️ Skipping src/templates/'); continue; }
|
|
305
|
+
if (file === 'api') { logger.debug('⏭️ Skipping src/api/'); continue; }
|
|
305
306
|
const subOutDir = join(outDir, file);
|
|
306
307
|
mkdirSync(subOutDir, { recursive: true });
|
|
307
308
|
const subStats = await compileDirectory(srcPath, subOutDir, root, envVars, aliasMap);
|
package/src/dev.js
CHANGED
|
@@ -1,237 +1,68 @@
|
|
|
1
|
-
// bertui/src/
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
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';
|
|
1
|
+
// bertui/src/dev.js
|
|
2
|
+
import { compileProject } from './client/compiler.js';
|
|
3
|
+
import { startDevServer } from './server/dev-server.js';
|
|
4
|
+
import { MiddlewareManager } from './middleware/index.js';
|
|
14
5
|
import { compileLayouts } from './layouts/index.js';
|
|
15
6
|
import { compileLoadingComponents } from './loading/index.js';
|
|
16
7
|
import { analyzeRoutes, logHydrationReport } from './hydration/index.js';
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
const TOTAL_STEPS = 10;
|
|
21
|
-
|
|
22
|
-
export async function buildProduction(options = {}) {
|
|
23
|
-
const root = options.root || process.cwd();
|
|
24
|
-
const buildDir = join(root, '.bertuibuild');
|
|
25
|
-
const outDir = join(root, 'dist');
|
|
26
|
-
|
|
27
|
-
process.env.NODE_ENV = 'production';
|
|
8
|
+
import logger from './logger/logger.js';
|
|
9
|
+
import { loadConfig } from './config/loadConfig.js';
|
|
28
10
|
|
|
29
|
-
|
|
11
|
+
const TOTAL_STEPS = 6;
|
|
30
12
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
mkdirSync(outDir, { recursive: true });
|
|
13
|
+
export async function startDev(options = {}) {
|
|
14
|
+
const root = options.root || process.cwd();
|
|
15
|
+
const port = options.port || 3000;
|
|
35
16
|
|
|
36
|
-
|
|
17
|
+
logger.printHeader('DEV');
|
|
37
18
|
|
|
38
19
|
try {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
logger.stepDone('
|
|
51
|
-
|
|
52
|
-
// ── Step 3:
|
|
53
|
-
logger.step(3, TOTAL_STEPS, '
|
|
54
|
-
const
|
|
55
|
-
logger.stepDone('Layouts', `${Object.keys(layouts).length} found`);
|
|
56
|
-
|
|
57
|
-
// ── Step 4: Loading states ───────────────────────────────────────────────
|
|
58
|
-
logger.step(4, TOTAL_STEPS, 'Loading states');
|
|
59
|
-
await compileLoadingComponents(root, buildDir);
|
|
20
|
+
const config = await loadConfig(root);
|
|
21
|
+
|
|
22
|
+
// ── Step 1: Compile ──────────────────────────────────────────────────────
|
|
23
|
+
logger.step(1, TOTAL_STEPS, 'Compiling');
|
|
24
|
+
const { routes, outDir } = await compileProject(root);
|
|
25
|
+
logger.stepDone('Compiling', `${routes.length} routes`);
|
|
26
|
+
|
|
27
|
+
// ── Step 2: Layouts ──────────────────────────────────────────────────────
|
|
28
|
+
logger.step(2, TOTAL_STEPS, 'Layouts');
|
|
29
|
+
const layouts = await compileLayouts(root, outDir);
|
|
30
|
+
const layoutCount = Object.keys(layouts).length;
|
|
31
|
+
logger.stepDone('Layouts', layoutCount > 0 ? `${layoutCount} found` : 'none');
|
|
32
|
+
|
|
33
|
+
// ── Step 3: Loading states ───────────────────────────────────────────────
|
|
34
|
+
logger.step(3, TOTAL_STEPS, 'Loading states');
|
|
35
|
+
const loadingComponents = await compileLoadingComponents(root, outDir);
|
|
60
36
|
logger.stepDone('Loading states');
|
|
61
37
|
|
|
62
|
-
// ── Step
|
|
63
|
-
logger.step(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
await buildAllCSS(root, outDir);
|
|
71
|
-
logger.stepDone('Processing CSS');
|
|
72
|
-
|
|
73
|
-
// ── Step 7: Static assets ────────────────────────────────────────────────
|
|
74
|
-
logger.step(7, TOTAL_STEPS, 'Static assets');
|
|
75
|
-
await copyAllStaticAssets(root, outDir);
|
|
76
|
-
logger.stepDone('Static assets');
|
|
77
|
-
|
|
78
|
-
// ── Step 8: Bundle JS ────────────────────────────────────────────────────
|
|
79
|
-
logger.step(8, TOTAL_STEPS, 'Bundling JS');
|
|
80
|
-
const buildEntry = join(buildDir, 'main.js');
|
|
81
|
-
const routerPath = join(buildDir, 'router.js');
|
|
82
|
-
if (!existsSync(buildEntry)) throw new Error('main.js not found in build dir');
|
|
83
|
-
const result = await bundleJavaScript(buildEntry, routerPath, outDir, envVars, buildDir, analyzedRoutes, importhow, 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, serverIslands, 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
|
-
// Fire-and-forget — don't let the report generator block process exit
|
|
101
|
-
analyzeBuild(outDir, { outputFile: join(outDir, 'bundle-report.html') }).catch(() => {});
|
|
102
|
-
|
|
103
|
-
// ── Summary ──────────────────────────────────────────────────────────────
|
|
104
|
-
logger.printSummary({
|
|
105
|
-
routes: routes.length,
|
|
106
|
-
serverIslands: serverIslands.length,
|
|
107
|
-
interactive: analyzedRoutes.interactive.length,
|
|
108
|
-
staticRoutes: analyzedRoutes.static.length,
|
|
109
|
-
jsSize: `${totalKB} KB`,
|
|
110
|
-
outDir: 'dist/',
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
return { success: true };
|
|
114
|
-
|
|
115
|
-
} catch (error) {
|
|
116
|
-
logger.stepFail('Build', error.message);
|
|
117
|
-
if (existsSync(buildDir)) rmSync(buildDir, { recursive: true, force: true });
|
|
118
|
-
throw error;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
123
|
-
|
|
124
|
-
async function generateProductionImportMap(root, config) {
|
|
125
|
-
const importMap = {
|
|
126
|
-
'react': 'https://esm.sh/react@18.2.0',
|
|
127
|
-
'react-dom': 'https://esm.sh/react-dom@18.2.0',
|
|
128
|
-
'react-dom/client': 'https://esm.sh/react-dom@18.2.0/client',
|
|
129
|
-
'react/jsx-runtime': 'https://esm.sh/react@18.2.0/jsx-runtime',
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const nodeModulesDir = join(root, 'node_modules');
|
|
133
|
-
if (!existsSync(nodeModulesDir)) return importMap;
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
for (const pkg of readdirSync(nodeModulesDir)) {
|
|
137
|
-
if (!pkg.startsWith('bertui-') || pkg.startsWith('.')) continue;
|
|
138
|
-
const pkgDir = join(nodeModulesDir, pkg);
|
|
139
|
-
const pkgJson = join(pkgDir, 'package.json');
|
|
140
|
-
if (!existsSync(pkgJson)) continue;
|
|
141
|
-
try {
|
|
142
|
-
const p = JSON.parse(await Bun.file(pkgJson).text());
|
|
143
|
-
for (const entry of [p.browser, p.module, p.main, 'dist/index.js', 'index.js'].filter(Boolean)) {
|
|
144
|
-
if (existsSync(join(pkgDir, entry))) {
|
|
145
|
-
importMap[pkg] = `/assets/node_modules/${pkg}/${entry}`;
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
} catch { continue; }
|
|
150
|
-
}
|
|
151
|
-
} catch { /* ignore */ }
|
|
152
|
-
|
|
153
|
-
return importMap;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async function copyNodeModulesToDist(root, outDir, importMap) {
|
|
157
|
-
const dest = join(outDir, 'assets', 'node_modules');
|
|
158
|
-
mkdirSync(dest, { recursive: true });
|
|
159
|
-
const src = join(root, 'node_modules');
|
|
160
|
-
|
|
161
|
-
for (const [, assetPath] of Object.entries(importMap)) {
|
|
162
|
-
if (assetPath.startsWith('https://')) continue;
|
|
163
|
-
const match = assetPath.match(/\/assets\/node_modules\/(.+)$/);
|
|
164
|
-
if (!match) continue;
|
|
165
|
-
const parts = match[1].split('/');
|
|
166
|
-
const pkgName = parts[0];
|
|
167
|
-
const subPath = parts.slice(1);
|
|
168
|
-
const srcFile = join(src, pkgName, ...subPath);
|
|
169
|
-
const destFile = join(dest, pkgName, ...subPath);
|
|
170
|
-
mkdirSync(join(dest, pkgName, ...subPath.slice(0, -1)), { recursive: true });
|
|
171
|
-
if (existsSync(srcFile)) await Bun.write(destFile, Bun.file(srcFile));
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async function bundleJavaScript(buildEntry, routerPath, outDir, envVars, buildDir, analyzedRoutes, importhow, root, config) {
|
|
176
|
-
const originalCwd = process.cwd();
|
|
177
|
-
process.chdir(buildDir);
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
const entrypoints = [buildEntry];
|
|
181
|
-
if (existsSync(routerPath)) entrypoints.push(routerPath);
|
|
182
|
-
|
|
183
|
-
const importMap = await generateProductionImportMap(root, config);
|
|
184
|
-
await Bun.write(join(outDir, 'import-map.json'), JSON.stringify({ imports: importMap }, null, 2));
|
|
185
|
-
await copyNodeModulesToDist(root, outDir, importMap);
|
|
186
|
-
|
|
187
|
-
const result = await Bun.build({
|
|
188
|
-
entrypoints,
|
|
189
|
-
outdir: join(outDir, 'assets'),
|
|
190
|
-
target: 'browser',
|
|
191
|
-
format: 'esm',
|
|
192
|
-
minify: {
|
|
193
|
-
whitespace: true,
|
|
194
|
-
syntax: true,
|
|
195
|
-
identifiers: true,
|
|
196
|
-
},
|
|
197
|
-
splitting: true,
|
|
198
|
-
sourcemap: 'external',
|
|
199
|
-
metafile: true,
|
|
200
|
-
naming: {
|
|
201
|
-
entry: 'js/[name]-[hash].js',
|
|
202
|
-
chunk: 'js/chunks/[name]-[hash].js',
|
|
203
|
-
asset: 'assets/[name]-[hash].[ext]',
|
|
204
|
-
},
|
|
205
|
-
external: ['react', 'react-dom', 'react-dom/client', 'react/jsx-runtime'],
|
|
206
|
-
define: {
|
|
207
|
-
'process.env.NODE_ENV': '"production"',
|
|
208
|
-
...Object.fromEntries(
|
|
209
|
-
Object.entries(envVars).map(([k, v]) => [`process.env.${k}`, JSON.stringify(v)])
|
|
210
|
-
),
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
if (!result.success) {
|
|
215
|
-
throw new Error(`Bundle failed\n${result.logs?.map(l => l.message).join('\n') || 'Unknown error'}`);
|
|
38
|
+
// ── Step 4: Hydration analysis ───────────────────────────────────────────
|
|
39
|
+
logger.step(4, TOTAL_STEPS, 'Hydration analysis');
|
|
40
|
+
if (routes && routes.length > 0) {
|
|
41
|
+
const analyzedRoutes = await analyzeRoutes(routes);
|
|
42
|
+
logger.stepDone('Hydration analysis',
|
|
43
|
+
`${analyzedRoutes.interactive.length} interactive · ${analyzedRoutes.static.length} static`);
|
|
44
|
+
} else {
|
|
45
|
+
logger.stepDone('Hydration analysis', 'no routes');
|
|
216
46
|
}
|
|
217
47
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
48
|
+
// ── Step 5: Middleware ───────────────────────────────────────────────────
|
|
49
|
+
logger.step(5, TOTAL_STEPS, 'Middleware');
|
|
50
|
+
const middlewareManager = new MiddlewareManager(root);
|
|
51
|
+
await middlewareManager.load();
|
|
52
|
+
middlewareManager.watch();
|
|
53
|
+
logger.stepDone('Middleware');
|
|
221
54
|
|
|
222
|
-
|
|
55
|
+
// ── Step 6: Dev server ───────────────────────────────────────────────────
|
|
56
|
+
logger.step(6, TOTAL_STEPS, 'Starting server');
|
|
57
|
+
await startDevServer({ root, port, middleware: middlewareManager, layouts, loadingComponents });
|
|
58
|
+
logger.stepDone('Starting server', `http://localhost:${port}`);
|
|
223
59
|
|
|
224
|
-
|
|
225
|
-
process.
|
|
226
|
-
}
|
|
227
|
-
}
|
|
60
|
+
// ── Ready ────────────────────────────────────────────────────────────────
|
|
61
|
+
process.stdout.write(`\n ${'\x1b[1m'}\x1b[32m▶ Ready on http://localhost:${port}\x1b[0m\n\n`);
|
|
228
62
|
|
|
229
|
-
export async function build(options = {}) {
|
|
230
|
-
try {
|
|
231
|
-
await buildProduction(options);
|
|
232
63
|
} catch (error) {
|
|
233
|
-
|
|
64
|
+
logger.stepFail('Dev server', error.message);
|
|
65
|
+
logger.error(error.stack || error.message);
|
|
234
66
|
process.exit(1);
|
|
235
67
|
}
|
|
236
|
-
process.exit(0);
|
|
237
68
|
}
|
|
@@ -77,8 +77,9 @@ export async function buildDevImportMap(root) {
|
|
|
77
77
|
'react-dom': 'https://esm.sh/react-dom@18.2.0',
|
|
78
78
|
'react-dom/client': 'https://esm.sh/react-dom@18.2.0/client',
|
|
79
79
|
'react/jsx-runtime': 'https://esm.sh/react@18.2.0/jsx-runtime',
|
|
80
|
+
'@bunnyx/api': '/bunnyx-api/api-client.js',
|
|
81
|
+
'@elysiajs/eden': '/node_modules/@elysiajs/eden/dist/index.mjs',
|
|
80
82
|
};
|
|
81
|
-
|
|
82
83
|
const SKIP = new Set(['react', 'react-dom', '.bin', '.cache', '.package-lock.json', '.yarn']);
|
|
83
84
|
|
|
84
85
|
if (existsSync(nodeModulesDir)) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bertui.d.ts","sourceRoot":"","sources":["../../bin/bertui.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-overlay.d.ts","sourceRoot":"","sources":["../error-overlay.js"],"names":[],"mappings":""}
|