bertui 0.1.7 → 0.1.9
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/README.md +1 -1
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/client/compiler.js +29 -21
- package/src/server/dev-server.js +27 -44
package/README.md
CHANGED
package/index.js
CHANGED
package/package.json
CHANGED
package/src/client/compiler.js
CHANGED
|
@@ -33,9 +33,6 @@ export async function compileProject(root) {
|
|
|
33
33
|
file: r.file,
|
|
34
34
|
type: r.type
|
|
35
35
|
})));
|
|
36
|
-
|
|
37
|
-
await generateRouter(routes, outDir, root);
|
|
38
|
-
logger.info('Generated router.js');
|
|
39
36
|
}
|
|
40
37
|
}
|
|
41
38
|
|
|
@@ -43,6 +40,12 @@ export async function compileProject(root) {
|
|
|
43
40
|
const stats = await compileDirectory(srcDir, outDir, root);
|
|
44
41
|
const duration = Date.now() - startTime;
|
|
45
42
|
|
|
43
|
+
// Generate router AFTER compilation
|
|
44
|
+
if (routes.length > 0) {
|
|
45
|
+
await generateRouter(routes, outDir, root);
|
|
46
|
+
logger.info('Generated router.js');
|
|
47
|
+
}
|
|
48
|
+
|
|
46
49
|
logger.success(`Compiled ${stats.files} files in ${duration}ms`);
|
|
47
50
|
logger.info(`Output: ${outDir}`);
|
|
48
51
|
|
|
@@ -77,7 +80,7 @@ async function discoverRoutes(pagesDir) {
|
|
|
77
80
|
|
|
78
81
|
routes.push({
|
|
79
82
|
route: route === '' ? '/' : route,
|
|
80
|
-
file: relativePath,
|
|
83
|
+
file: relativePath.replace(/\\/g, '/'),
|
|
81
84
|
path: fullPath,
|
|
82
85
|
type
|
|
83
86
|
});
|
|
@@ -101,7 +104,7 @@ async function discoverRoutes(pagesDir) {
|
|
|
101
104
|
async function generateRouter(routes, outDir, root) {
|
|
102
105
|
const imports = routes.map((route, i) => {
|
|
103
106
|
const componentName = `Page${i}`;
|
|
104
|
-
const importPath = `./pages/${route.file.replace(
|
|
107
|
+
const importPath = `./pages/${route.file.replace(/\.(jsx|tsx|ts)$/, '.js')}`;
|
|
105
108
|
return `import ${componentName} from '${importPath}';`;
|
|
106
109
|
}).join('\n');
|
|
107
110
|
|
|
@@ -192,13 +195,16 @@ async function compileFile(srcPath, outDir, filename, relativePath) {
|
|
|
192
195
|
const loader = ext === '.tsx' ? 'tsx' : ext === '.ts' ? 'ts' : 'jsx';
|
|
193
196
|
|
|
194
197
|
try {
|
|
195
|
-
const transpiler = new Bun.Transpiler({ loader });
|
|
196
198
|
let code = await Bun.file(srcPath).text();
|
|
197
199
|
|
|
198
|
-
//
|
|
199
|
-
code =
|
|
200
|
+
// Remove bertui/styles imports
|
|
201
|
+
code = code.replace(/import\s+['"]bertui\/styles['"]\s*;?\s*/g, '');
|
|
202
|
+
|
|
203
|
+
const transpiler = new Bun.Transpiler({ loader });
|
|
204
|
+
let compiled = await transpiler.transform(code);
|
|
200
205
|
|
|
201
|
-
|
|
206
|
+
// CRITICAL FIX: Add .js extensions to all relative imports
|
|
207
|
+
compiled = fixRelativeImports(compiled);
|
|
202
208
|
|
|
203
209
|
const outFilename = filename.replace(/\.(jsx|tsx|ts)$/, '.js');
|
|
204
210
|
const outPath = join(outDir, outFilename);
|
|
@@ -211,18 +217,20 @@ async function compileFile(srcPath, outDir, filename, relativePath) {
|
|
|
211
217
|
}
|
|
212
218
|
}
|
|
213
219
|
|
|
214
|
-
function
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
/
|
|
224
|
-
|
|
225
|
-
|
|
220
|
+
function fixRelativeImports(code) {
|
|
221
|
+
// Match import statements with relative paths that don't already have extensions
|
|
222
|
+
// Matches: import X from './path' or import X from '../path'
|
|
223
|
+
// But NOT: import X from './path.js' or import X from 'package'
|
|
224
|
+
|
|
225
|
+
const importRegex = /from\s+['"](\.\.[\/\\]|\.\/)((?:[^'"]+?)(?<!\.js|\.jsx|\.ts|\.tsx|\.json))['"];?/g;
|
|
226
|
+
|
|
227
|
+
code = code.replace(importRegex, (match, prefix, path) => {
|
|
228
|
+
// Don't add .js if path already has an extension or ends with /
|
|
229
|
+
if (path.endsWith('/') || /\.\w+$/.test(path)) {
|
|
230
|
+
return match;
|
|
231
|
+
}
|
|
232
|
+
return `from '${prefix}${path}.js';`;
|
|
233
|
+
});
|
|
226
234
|
|
|
227
235
|
return code;
|
|
228
236
|
}
|
package/src/server/dev-server.js
CHANGED
|
@@ -14,7 +14,6 @@ export async function startDevServer(options = {}) {
|
|
|
14
14
|
const clients = new Set();
|
|
15
15
|
let hasRouter = false;
|
|
16
16
|
|
|
17
|
-
// Check if router exists
|
|
18
17
|
const routerPath = join(compiledDir, 'router.js');
|
|
19
18
|
if (existsSync(routerPath)) {
|
|
20
19
|
hasRouter = true;
|
|
@@ -22,28 +21,21 @@ export async function startDevServer(options = {}) {
|
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
const app = new Elysia()
|
|
25
|
-
// Main HTML route - serves all pages
|
|
26
24
|
.get('/', async () => {
|
|
27
25
|
return serveHTML(root, hasRouter);
|
|
28
26
|
})
|
|
29
27
|
|
|
30
|
-
// Catch-all route for SPA routing
|
|
31
28
|
.get('/*', async ({ params, set }) => {
|
|
32
29
|
const path = params['*'];
|
|
33
30
|
|
|
34
|
-
// Check if it's a file request
|
|
35
31
|
if (path.includes('.')) {
|
|
36
|
-
// Try to serve compiled files
|
|
37
32
|
if (path.startsWith('compiled/')) {
|
|
38
33
|
const filePath = join(compiledDir, path.replace('compiled/', ''));
|
|
39
34
|
const file = Bun.file(filePath);
|
|
40
35
|
|
|
41
36
|
if (await file.exists()) {
|
|
42
37
|
const ext = extname(path);
|
|
43
|
-
|
|
44
|
-
const contentType = ext === '.js' || ext === '.jsx'
|
|
45
|
-
? 'application/javascript'
|
|
46
|
-
: getContentType(ext);
|
|
38
|
+
const contentType = ext === '.js' ? 'application/javascript' : getContentType(ext);
|
|
47
39
|
|
|
48
40
|
return new Response(await file.text(), {
|
|
49
41
|
headers: {
|
|
@@ -58,7 +50,6 @@ export async function startDevServer(options = {}) {
|
|
|
58
50
|
return 'File not found';
|
|
59
51
|
}
|
|
60
52
|
|
|
61
|
-
// For non-file routes, serve the main HTML (SPA mode)
|
|
62
53
|
return serveHTML(root, hasRouter);
|
|
63
54
|
})
|
|
64
55
|
|
|
@@ -108,25 +99,6 @@ ws.onclose = () => {
|
|
|
108
99
|
}
|
|
109
100
|
})
|
|
110
101
|
|
|
111
|
-
// Serve BertUI CSS
|
|
112
|
-
.get('/styles/bertui.css', async ({ set }) => {
|
|
113
|
-
const cssPath = join(import.meta.dir, '../styles/bertui.css');
|
|
114
|
-
const file = Bun.file(cssPath);
|
|
115
|
-
|
|
116
|
-
if (!await file.exists()) {
|
|
117
|
-
set.status = 404;
|
|
118
|
-
return 'CSS file not found';
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return new Response(await file.text(), {
|
|
122
|
-
headers: {
|
|
123
|
-
'Content-Type': 'text/css',
|
|
124
|
-
'Cache-Control': 'no-store'
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
// Serve compiled files with correct MIME types
|
|
130
102
|
.get('/compiled/*', async ({ params, set }) => {
|
|
131
103
|
const filepath = join(compiledDir, params['*']);
|
|
132
104
|
const file = Bun.file(filepath);
|
|
@@ -137,10 +109,7 @@ ws.onclose = () => {
|
|
|
137
109
|
}
|
|
138
110
|
|
|
139
111
|
const ext = extname(filepath);
|
|
140
|
-
|
|
141
|
-
const contentType = ext === '.js'
|
|
142
|
-
? 'application/javascript'
|
|
143
|
-
: getContentType(ext);
|
|
112
|
+
const contentType = ext === '.js' ? 'application/javascript' : getContentType(ext);
|
|
144
113
|
|
|
145
114
|
return new Response(await file.text(), {
|
|
146
115
|
headers: {
|
|
@@ -150,7 +119,6 @@ ws.onclose = () => {
|
|
|
150
119
|
});
|
|
151
120
|
})
|
|
152
121
|
|
|
153
|
-
// Serve public assets
|
|
154
122
|
.get('/public/*', async ({ params, set }) => {
|
|
155
123
|
const publicDir = join(root, 'public');
|
|
156
124
|
const filepath = join(publicDir, params['*']);
|
|
@@ -174,7 +142,6 @@ ws.onclose = () => {
|
|
|
174
142
|
logger.success(`🚀 Server running at http://localhost:${port}`);
|
|
175
143
|
logger.info(`📁 Serving: ${root}`);
|
|
176
144
|
|
|
177
|
-
// Watch for file changes
|
|
178
145
|
setupWatcher(root, compiledDir, clients, () => {
|
|
179
146
|
hasRouter = existsSync(join(compiledDir, 'router.js'));
|
|
180
147
|
});
|
|
@@ -190,7 +157,30 @@ function serveHTML(root, hasRouter) {
|
|
|
190
157
|
<meta charset="UTF-8">
|
|
191
158
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
192
159
|
<title>BertUI App - Dev</title>
|
|
193
|
-
|
|
160
|
+
|
|
161
|
+
<!-- Import Map for React and dependencies -->
|
|
162
|
+
<script type="importmap">
|
|
163
|
+
{
|
|
164
|
+
"imports": {
|
|
165
|
+
"react": "https://esm.sh/react@18.2.0",
|
|
166
|
+
"react-dom": "https://esm.sh/react-dom@18.2.0",
|
|
167
|
+
"react-dom/client": "https://esm.sh/react-dom@18.2.0/client",
|
|
168
|
+
"bertui/router": "/compiled/router.js"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
</script>
|
|
172
|
+
|
|
173
|
+
<style>
|
|
174
|
+
/* Inline basic styles since we're skipping CSS for now */
|
|
175
|
+
* {
|
|
176
|
+
margin: 0;
|
|
177
|
+
padding: 0;
|
|
178
|
+
box-sizing: border-box;
|
|
179
|
+
}
|
|
180
|
+
body {
|
|
181
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
182
|
+
}
|
|
183
|
+
</style>
|
|
194
184
|
</head>
|
|
195
185
|
<body>
|
|
196
186
|
<div id="root"></div>
|
|
@@ -220,11 +210,7 @@ function getContentType(ext) {
|
|
|
220
210
|
'.jpeg': 'image/jpeg',
|
|
221
211
|
'.gif': 'image/gif',
|
|
222
212
|
'.svg': 'image/svg+xml',
|
|
223
|
-
'.ico': 'image/x-icon'
|
|
224
|
-
'.woff': 'font/woff',
|
|
225
|
-
'.woff2': 'font/woff2',
|
|
226
|
-
'.ttf': 'font/ttf',
|
|
227
|
-
'.eot': 'application/vnd.ms-fontobject'
|
|
213
|
+
'.ico': 'image/x-icon'
|
|
228
214
|
};
|
|
229
215
|
|
|
230
216
|
return types[ext] || 'text/plain';
|
|
@@ -247,7 +233,6 @@ function setupWatcher(root, compiledDir, clients, onRecompile) {
|
|
|
247
233
|
if (['.js', '.jsx', '.ts', '.tsx', '.css'].includes(ext)) {
|
|
248
234
|
logger.info(`📝 File changed: ${filename}`);
|
|
249
235
|
|
|
250
|
-
// Notify clients
|
|
251
236
|
for (const client of clients) {
|
|
252
237
|
try {
|
|
253
238
|
client.send(JSON.stringify({ type: 'recompiling' }));
|
|
@@ -256,7 +241,6 @@ function setupWatcher(root, compiledDir, clients, onRecompile) {
|
|
|
256
241
|
}
|
|
257
242
|
}
|
|
258
243
|
|
|
259
|
-
// Recompile
|
|
260
244
|
try {
|
|
261
245
|
await compileProject(root);
|
|
262
246
|
|
|
@@ -264,7 +248,6 @@ function setupWatcher(root, compiledDir, clients, onRecompile) {
|
|
|
264
248
|
onRecompile();
|
|
265
249
|
}
|
|
266
250
|
|
|
267
|
-
// Notify reload
|
|
268
251
|
for (const client of clients) {
|
|
269
252
|
try {
|
|
270
253
|
client.send(JSON.stringify({ type: 'reload', file: filename }));
|