bertui 1.1.4 → 1.1.5
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,4 +1,4 @@
|
|
|
1
|
-
// bertui/src/build/generators/html-generator.js - FIXED
|
|
1
|
+
// bertui/src/build/generators/html-generator.js - FIXED CSS BUILD
|
|
2
2
|
import { join, relative } from 'path';
|
|
3
3
|
import { mkdirSync, existsSync, cpSync } from 'fs';
|
|
4
4
|
import logger from '../../logger/logger.js';
|
|
@@ -17,53 +17,75 @@ 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
|
-
// ✅
|
|
21
|
-
const
|
|
20
|
+
// ✅ Copy bertui-icons AND bertui-animate to dist/
|
|
21
|
+
const bertuiPackages = await copyBertuiPackagesToProduction(root, outDir);
|
|
22
22
|
|
|
23
23
|
logger.info(`📄 Generating HTML for ${routes.length} routes...`);
|
|
24
24
|
|
|
25
|
-
// Process in batches to avoid Bun crashes
|
|
26
25
|
const BATCH_SIZE = 5;
|
|
27
26
|
|
|
28
27
|
for (let i = 0; i < routes.length; i += BATCH_SIZE) {
|
|
29
28
|
const batch = routes.slice(i, i + BATCH_SIZE);
|
|
30
29
|
logger.debug(`Processing batch ${Math.floor(i/BATCH_SIZE) + 1}/${Math.ceil(routes.length/BATCH_SIZE)}`);
|
|
31
30
|
|
|
32
|
-
// Process batch sequentially
|
|
33
31
|
for (const route of batch) {
|
|
34
|
-
await processSingleRoute(route, serverIslands, config, defaultMeta, bundlePath, outDir,
|
|
32
|
+
await processSingleRoute(route, serverIslands, config, defaultMeta, bundlePath, outDir, bertuiPackages);
|
|
35
33
|
}
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
logger.success(`✅ HTML generation complete for ${routes.length} routes`);
|
|
39
37
|
}
|
|
40
38
|
|
|
41
|
-
// ✅
|
|
42
|
-
async function
|
|
39
|
+
// ✅ UPDATED: Copy ALL bertui-* packages to dist/
|
|
40
|
+
async function copyBertuiPackagesToProduction(root, outDir) {
|
|
43
41
|
const nodeModulesDir = join(root, 'node_modules');
|
|
44
|
-
const
|
|
42
|
+
const packages = {
|
|
43
|
+
bertuiIcons: false,
|
|
44
|
+
bertuiAnimate: false
|
|
45
|
+
};
|
|
45
46
|
|
|
46
|
-
if (!existsSync(
|
|
47
|
-
logger.debug('
|
|
48
|
-
return
|
|
47
|
+
if (!existsSync(nodeModulesDir)) {
|
|
48
|
+
logger.debug('node_modules not found, skipping package copy');
|
|
49
|
+
return packages;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
52
|
+
// Copy bertui-icons
|
|
53
|
+
const bertuiIconsSource = join(nodeModulesDir, 'bertui-icons');
|
|
54
|
+
if (existsSync(bertuiIconsSource)) {
|
|
55
|
+
try {
|
|
56
|
+
const bertuiIconsDest = join(outDir, 'node_modules', 'bertui-icons');
|
|
57
|
+
mkdirSync(join(outDir, 'node_modules'), { recursive: true });
|
|
58
|
+
cpSync(bertuiIconsSource, bertuiIconsDest, { recursive: true });
|
|
59
|
+
logger.success('✅ Copied bertui-icons to dist/node_modules/');
|
|
60
|
+
packages.bertuiIcons = true;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
logger.error(`Failed to copy bertui-icons: ${error.message}`);
|
|
63
|
+
}
|
|
63
64
|
}
|
|
65
|
+
|
|
66
|
+
// ✅ NEW: Copy ONLY bertui-animate CSS files (not the whole package)
|
|
67
|
+
const bertuiAnimateSource = join(nodeModulesDir, 'bertui-animate', 'dist');
|
|
68
|
+
if (existsSync(bertuiAnimateSource)) {
|
|
69
|
+
try {
|
|
70
|
+
const bertuiAnimateDest = join(outDir, 'css');
|
|
71
|
+
mkdirSync(bertuiAnimateDest, { recursive: true });
|
|
72
|
+
|
|
73
|
+
// Copy minified CSS
|
|
74
|
+
const minCSSPath = join(bertuiAnimateSource, 'bertui-animate.min.css');
|
|
75
|
+
if (existsSync(minCSSPath)) {
|
|
76
|
+
cpSync(minCSSPath, join(bertuiAnimateDest, 'bertui-animate.min.css'));
|
|
77
|
+
logger.success('✅ Copied bertui-animate.min.css to dist/css/');
|
|
78
|
+
packages.bertuiAnimate = true;
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
logger.error(`Failed to copy bertui-animate: ${error.message}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return packages;
|
|
64
86
|
}
|
|
65
87
|
|
|
66
|
-
async function processSingleRoute(route, serverIslands, config, defaultMeta, bundlePath, outDir,
|
|
88
|
+
async function processSingleRoute(route, serverIslands, config, defaultMeta, bundlePath, outDir, bertuiPackages) {
|
|
67
89
|
try {
|
|
68
90
|
const sourceCode = await Bun.file(route.path).text();
|
|
69
91
|
const pageMeta = extractMetaFromSource(sourceCode);
|
|
@@ -84,7 +106,7 @@ async function processSingleRoute(route, serverIslands, config, defaultMeta, bun
|
|
|
84
106
|
}
|
|
85
107
|
}
|
|
86
108
|
|
|
87
|
-
const html = generateHTML(meta, route, bundlePath, staticHTML, isServerIsland,
|
|
109
|
+
const html = generateHTML(meta, route, bundlePath, staticHTML, isServerIsland, bertuiPackages);
|
|
88
110
|
|
|
89
111
|
let htmlPath;
|
|
90
112
|
if (route.route === '/') {
|
|
@@ -239,8 +261,8 @@ async function extractStaticHTMLFromComponent(sourceCode, filePath) {
|
|
|
239
261
|
}
|
|
240
262
|
}
|
|
241
263
|
|
|
242
|
-
// ✅
|
|
243
|
-
function generateHTML(meta, route, bundlePath, staticHTML = '', isServerIsland = false,
|
|
264
|
+
// ✅ UPDATED: Add bertui-animate CSS to production HTML
|
|
265
|
+
function generateHTML(meta, route, bundlePath, staticHTML = '', isServerIsland = false, bertuiPackages = {}) {
|
|
244
266
|
const rootContent = staticHTML
|
|
245
267
|
? `<div id="root">${staticHTML}</div>`
|
|
246
268
|
: '<div id="root"></div>';
|
|
@@ -249,11 +271,16 @@ function generateHTML(meta, route, bundlePath, staticHTML = '', isServerIsland =
|
|
|
249
271
|
? '<!-- 🏝️ Server Island: Static content rendered at build time -->'
|
|
250
272
|
: '<!-- ⚡ Client-only: Content rendered by JavaScript -->';
|
|
251
273
|
|
|
252
|
-
// ✅
|
|
253
|
-
const bertuiIconsImport =
|
|
274
|
+
// ✅ Add bertui-icons to import map
|
|
275
|
+
const bertuiIconsImport = bertuiPackages.bertuiIcons
|
|
254
276
|
? ',\n "bertui-icons": "/node_modules/bertui-icons/generated/index.js"'
|
|
255
277
|
: '';
|
|
256
278
|
|
|
279
|
+
// ✅ Add bertui-animate CSS link
|
|
280
|
+
const bertuiAnimateCSS = bertuiPackages.bertuiAnimate
|
|
281
|
+
? ' <link rel="stylesheet" href="/css/bertui-animate.min.css">'
|
|
282
|
+
: '';
|
|
283
|
+
|
|
257
284
|
return `<!DOCTYPE html>
|
|
258
285
|
<html lang="${meta.lang || 'en'}">
|
|
259
286
|
<head>
|
|
@@ -271,6 +298,7 @@ function generateHTML(meta, route, bundlePath, staticHTML = '', isServerIsland =
|
|
|
271
298
|
${meta.ogImage ? `<meta property="og:image" content="${meta.ogImage}">` : ''}
|
|
272
299
|
|
|
273
300
|
<link rel="stylesheet" href="/styles/bertui.min.css">
|
|
301
|
+
${bertuiAnimateCSS}
|
|
274
302
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
275
303
|
|
|
276
304
|
<script type="importmap">
|
package/src/server/dev-server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// bertui/src/server/dev-server.js - FIXED:
|
|
1
|
+
// bertui/src/server/dev-server.js - FIXED: CSS Module Loading
|
|
2
2
|
import { join, extname, dirname } from 'path';
|
|
3
3
|
import { existsSync, readdirSync } from 'fs';
|
|
4
4
|
import logger from '../logger/logger.js';
|
|
@@ -15,7 +15,6 @@ export async function startDevServer(options = {}) {
|
|
|
15
15
|
|
|
16
16
|
const config = await loadConfig(root);
|
|
17
17
|
|
|
18
|
-
// ✅ Track connected WebSocket clients
|
|
19
18
|
const clients = new Set();
|
|
20
19
|
|
|
21
20
|
let hasRouter = false;
|
|
@@ -25,30 +24,29 @@ export async function startDevServer(options = {}) {
|
|
|
25
24
|
logger.info('File-based routing enabled');
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
// ✅ Use Bun.serve() with WebSocket support
|
|
29
27
|
const server = Bun.serve({
|
|
30
28
|
port,
|
|
31
29
|
|
|
32
30
|
async fetch(req, server) {
|
|
33
31
|
const url = new URL(req.url);
|
|
34
32
|
|
|
35
|
-
//
|
|
33
|
+
// WebSocket upgrade for HMR
|
|
36
34
|
if (url.pathname === '/__hmr') {
|
|
37
35
|
const success = server.upgrade(req);
|
|
38
36
|
if (success) {
|
|
39
|
-
return undefined;
|
|
37
|
+
return undefined;
|
|
40
38
|
}
|
|
41
39
|
return new Response('WebSocket upgrade failed', { status: 500 });
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
//
|
|
42
|
+
// Serve HTML
|
|
45
43
|
if (url.pathname === '/' || (!url.pathname.includes('.') && !url.pathname.startsWith('/compiled'))) {
|
|
46
44
|
return new Response(await serveHTML(root, hasRouter, config, port), {
|
|
47
45
|
headers: { 'Content-Type': 'text/html' }
|
|
48
46
|
});
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
//
|
|
49
|
+
// Serve compiled JavaScript
|
|
52
50
|
if (url.pathname.startsWith('/compiled/')) {
|
|
53
51
|
const filepath = join(compiledDir, url.pathname.replace('/compiled/', ''));
|
|
54
52
|
const file = Bun.file(filepath);
|
|
@@ -66,7 +64,22 @@ export async function startDevServer(options = {}) {
|
|
|
66
64
|
}
|
|
67
65
|
}
|
|
68
66
|
|
|
69
|
-
// ✅ Serve CSS
|
|
67
|
+
// ✅ Serve bertui-animate CSS
|
|
68
|
+
if (url.pathname === '/bertui-animate.css') {
|
|
69
|
+
const bertuiAnimatePath = join(root, 'node_modules/bertui-animate/dist/bertui-animate.min.css');
|
|
70
|
+
const file = Bun.file(bertuiAnimatePath);
|
|
71
|
+
|
|
72
|
+
if (await file.exists()) {
|
|
73
|
+
return new Response(file, {
|
|
74
|
+
headers: {
|
|
75
|
+
'Content-Type': 'text/css',
|
|
76
|
+
'Cache-Control': 'no-store'
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Serve CSS
|
|
70
83
|
if (url.pathname.startsWith('/styles/')) {
|
|
71
84
|
const filepath = join(stylesDir, url.pathname.replace('/styles/', ''));
|
|
72
85
|
const file = Bun.file(filepath);
|
|
@@ -81,7 +94,7 @@ export async function startDevServer(options = {}) {
|
|
|
81
94
|
}
|
|
82
95
|
}
|
|
83
96
|
|
|
84
|
-
//
|
|
97
|
+
// Serve images from src/images/
|
|
85
98
|
if (url.pathname.startsWith('/images/')) {
|
|
86
99
|
const filepath = join(srcDir, 'images', url.pathname.replace('/images/', ''));
|
|
87
100
|
const file = Bun.file(filepath);
|
|
@@ -99,7 +112,7 @@ export async function startDevServer(options = {}) {
|
|
|
99
112
|
}
|
|
100
113
|
}
|
|
101
114
|
|
|
102
|
-
//
|
|
115
|
+
// Serve from public/
|
|
103
116
|
if (url.pathname.startsWith('/public/')) {
|
|
104
117
|
const filepath = join(publicDir, url.pathname.replace('/public/', ''));
|
|
105
118
|
const file = Bun.file(filepath);
|
|
@@ -111,14 +124,23 @@ export async function startDevServer(options = {}) {
|
|
|
111
124
|
}
|
|
112
125
|
}
|
|
113
126
|
|
|
114
|
-
// ✅ Serve node_modules
|
|
127
|
+
// ✅ FIX: Serve node_modules with proper MIME types
|
|
115
128
|
if (url.pathname.startsWith('/node_modules/')) {
|
|
116
129
|
const filepath = join(root, 'node_modules', url.pathname.replace('/node_modules/', ''));
|
|
117
130
|
const file = Bun.file(filepath);
|
|
118
131
|
|
|
119
132
|
if (await file.exists()) {
|
|
120
133
|
const ext = extname(filepath).toLowerCase();
|
|
121
|
-
|
|
134
|
+
|
|
135
|
+
// ✅ Proper MIME type detection
|
|
136
|
+
let contentType;
|
|
137
|
+
if (ext === '.css') {
|
|
138
|
+
contentType = 'text/css';
|
|
139
|
+
} else if (ext === '.js' || ext === '.mjs') {
|
|
140
|
+
contentType = 'application/javascript; charset=utf-8';
|
|
141
|
+
} else {
|
|
142
|
+
contentType = getContentType(ext);
|
|
143
|
+
}
|
|
122
144
|
|
|
123
145
|
return new Response(file, {
|
|
124
146
|
headers: {
|
|
@@ -132,7 +154,6 @@ export async function startDevServer(options = {}) {
|
|
|
132
154
|
return new Response('Not found', { status: 404 });
|
|
133
155
|
},
|
|
134
156
|
|
|
135
|
-
// ✅ WebSocket handler for HMR
|
|
136
157
|
websocket: {
|
|
137
158
|
open(ws) {
|
|
138
159
|
clients.add(ws);
|
|
@@ -156,7 +177,6 @@ export async function startDevServer(options = {}) {
|
|
|
156
177
|
logger.info(`📦 Public: /public/* → public/`);
|
|
157
178
|
logger.info(`⚡ BertUI Packages: /node_modules/* → node_modules/`);
|
|
158
179
|
|
|
159
|
-
// ✅ Setup file watcher
|
|
160
180
|
setupFileWatcher(root, compiledDir, clients, async () => {
|
|
161
181
|
hasRouter = existsSync(join(compiledDir, 'router.js'));
|
|
162
182
|
});
|
|
@@ -179,6 +199,14 @@ async function serveHTML(root, hasRouter, config, port) {
|
|
|
179
199
|
}
|
|
180
200
|
}
|
|
181
201
|
|
|
202
|
+
// ✅ FIX: Auto-detect bertui-animate CSS (bundled version)
|
|
203
|
+
let bertuiAnimateStylesheet = '';
|
|
204
|
+
const bertuiAnimatePath = join(root, 'node_modules/bertui-animate/dist/bertui-animate.min.css');
|
|
205
|
+
if (existsSync(bertuiAnimatePath)) {
|
|
206
|
+
bertuiAnimateStylesheet = ' <link rel="stylesheet" href="/bertui-animate.css">';
|
|
207
|
+
logger.info('✅ bertui-animate detected');
|
|
208
|
+
}
|
|
209
|
+
|
|
182
210
|
// Build import map
|
|
183
211
|
const importMap = {
|
|
184
212
|
"react": "https://esm.sh/react@18.2.0",
|
|
@@ -186,7 +214,7 @@ async function serveHTML(root, hasRouter, config, port) {
|
|
|
186
214
|
"react-dom/client": "https://esm.sh/react-dom@18.2.0/client"
|
|
187
215
|
};
|
|
188
216
|
|
|
189
|
-
// Auto-detect bertui-* packages
|
|
217
|
+
// Auto-detect bertui-* JavaScript packages
|
|
190
218
|
const nodeModulesDir = join(root, 'node_modules');
|
|
191
219
|
|
|
192
220
|
if (existsSync(nodeModulesDir)) {
|
|
@@ -255,6 +283,7 @@ async function serveHTML(root, hasRouter, config, port) {
|
|
|
255
283
|
<link rel="icon" type="image/svg+xml" href="/public/favicon.svg">
|
|
256
284
|
|
|
257
285
|
${userStylesheets}
|
|
286
|
+
${bertuiAnimateStylesheet}
|
|
258
287
|
|
|
259
288
|
<script type="importmap">
|
|
260
289
|
${JSON.stringify({ imports: importMap }, null, 2)}
|
|
@@ -274,9 +303,7 @@ ${userStylesheets}
|
|
|
274
303
|
<body>
|
|
275
304
|
<div id="root"></div>
|
|
276
305
|
|
|
277
|
-
<!-- ✅ Bun Native HMR Script -->
|
|
278
306
|
<script type="module">
|
|
279
|
-
// WebSocket-based HMR (no polling!)
|
|
280
307
|
const ws = new WebSocket('ws://localhost:${port}/__hmr');
|
|
281
308
|
|
|
282
309
|
ws.onopen = () => {
|
|
@@ -358,7 +385,6 @@ function getContentType(ext) {
|
|
|
358
385
|
return types[ext] || 'text/plain';
|
|
359
386
|
}
|
|
360
387
|
|
|
361
|
-
// ✅ File watcher with proper debouncing
|
|
362
388
|
function setupFileWatcher(root, compiledDir, clients, onRecompile) {
|
|
363
389
|
const srcDir = join(root, 'src');
|
|
364
390
|
const configPath = join(root, 'bertui.config.js');
|
|
@@ -374,7 +400,6 @@ function setupFileWatcher(root, compiledDir, clients, onRecompile) {
|
|
|
374
400
|
let recompileTimeout = null;
|
|
375
401
|
const watchedExtensions = ['.js', '.jsx', '.ts', '.tsx', '.css', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.avif'];
|
|
376
402
|
|
|
377
|
-
// Notify all clients
|
|
378
403
|
function notifyClients(message) {
|
|
379
404
|
for (const client of clients) {
|
|
380
405
|
try {
|
|
@@ -395,7 +420,6 @@ function setupFileWatcher(root, compiledDir, clients, onRecompile) {
|
|
|
395
420
|
|
|
396
421
|
logger.info(`📝 File changed: ${filename}`);
|
|
397
422
|
|
|
398
|
-
// ✅ Clear previous timeout and debounce
|
|
399
423
|
clearTimeout(recompileTimeout);
|
|
400
424
|
|
|
401
425
|
recompileTimeout = setTimeout(async () => {
|
|
@@ -414,7 +438,6 @@ function setupFileWatcher(root, compiledDir, clients, onRecompile) {
|
|
|
414
438
|
logger.success('✅ Recompiled successfully');
|
|
415
439
|
notifyClients({ type: 'compiled' });
|
|
416
440
|
|
|
417
|
-
// ✅ Wait 100ms before triggering reload (let compilation finish)
|
|
418
441
|
setTimeout(() => {
|
|
419
442
|
notifyClients({ type: 'reload' });
|
|
420
443
|
}, 100);
|
|
@@ -424,10 +447,9 @@ function setupFileWatcher(root, compiledDir, clients, onRecompile) {
|
|
|
424
447
|
} finally {
|
|
425
448
|
isRecompiling = false;
|
|
426
449
|
}
|
|
427
|
-
}, 150);
|
|
450
|
+
}, 150);
|
|
428
451
|
});
|
|
429
452
|
|
|
430
|
-
// Watch config file
|
|
431
453
|
if (existsSync(configPath)) {
|
|
432
454
|
watch(configPath, async (eventType) => {
|
|
433
455
|
if (eventType === 'change') {
|