bertui 0.2.3 → 0.2.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/index.js +1 -1
- package/package.json +1 -1
- package/src/client/compiler.js +15 -10
- package/src/server/dev-server.js +51 -11
package/index.js
CHANGED
package/package.json
CHANGED
package/src/client/compiler.js
CHANGED
|
@@ -111,7 +111,7 @@ async function generateRouter(routes, outDir, root) {
|
|
|
111
111
|
return ` { path: '${route.route}', component: ${componentName}, type: '${route.type}' }`;
|
|
112
112
|
}).join(',\n');
|
|
113
113
|
|
|
114
|
-
const routerComponentCode = `import { useState, useEffect, createContext, useContext
|
|
114
|
+
const routerComponentCode = `import React, { useState, useEffect, createContext, useContext } from 'react';
|
|
115
115
|
|
|
116
116
|
const RouterContext = createContext(null);
|
|
117
117
|
|
|
@@ -185,10 +185,10 @@ export function Router({ routes }) {
|
|
|
185
185
|
|
|
186
186
|
const Component = currentRoute?.component;
|
|
187
187
|
|
|
188
|
-
return createElement(
|
|
188
|
+
return React.createElement(
|
|
189
189
|
RouterContext.Provider,
|
|
190
190
|
{ value: routerValue },
|
|
191
|
-
Component ? createElement(Component, { params }) : createElement(NotFound, null)
|
|
191
|
+
Component ? React.createElement(Component, { params }) : React.createElement(NotFound, null)
|
|
192
192
|
);
|
|
193
193
|
}
|
|
194
194
|
|
|
@@ -200,11 +200,11 @@ export function Link({ to, children, ...props }) {
|
|
|
200
200
|
navigate(to);
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
return createElement('a', { href: to, onClick: handleClick, ...props }, children);
|
|
203
|
+
return React.createElement('a', { href: to, onClick: handleClick, ...props }, children);
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
function NotFound() {
|
|
207
|
-
return createElement(
|
|
207
|
+
return React.createElement(
|
|
208
208
|
'div',
|
|
209
209
|
{
|
|
210
210
|
style: {
|
|
@@ -216,9 +216,9 @@ function NotFound() {
|
|
|
216
216
|
fontFamily: 'system-ui'
|
|
217
217
|
}
|
|
218
218
|
},
|
|
219
|
-
createElement('h1', { style: { fontSize: '6rem', margin: 0 } }, '404'),
|
|
220
|
-
createElement('p', { style: { fontSize: '1.5rem', color: '#666' } }, 'Page not found'),
|
|
221
|
-
createElement('a', {
|
|
219
|
+
React.createElement('h1', { style: { fontSize: '6rem', margin: 0 } }, '404'),
|
|
220
|
+
React.createElement('p', { style: { fontSize: '1.5rem', color: '#666' } }, 'Page not found'),
|
|
221
|
+
React.createElement('a', {
|
|
222
222
|
href: '/',
|
|
223
223
|
style: { color: '#10b981', textDecoration: 'none', fontSize: '1.2rem' }
|
|
224
224
|
}, 'Go home')
|
|
@@ -290,13 +290,18 @@ async function compileFile(srcPath, outDir, filename, relativePath) {
|
|
|
290
290
|
loader,
|
|
291
291
|
tsconfig: {
|
|
292
292
|
compilerOptions: {
|
|
293
|
-
jsx: 'react
|
|
294
|
-
|
|
293
|
+
jsx: 'react',
|
|
294
|
+
jsxFactory: 'React.createElement',
|
|
295
|
+
jsxFragmentFactory: 'React.Fragment'
|
|
295
296
|
}
|
|
296
297
|
}
|
|
297
298
|
});
|
|
298
299
|
let compiled = await transpiler.transform(code);
|
|
299
300
|
|
|
301
|
+
if (!compiled.includes('import React') && (compiled.includes('React.createElement') || compiled.includes('React.Fragment'))) {
|
|
302
|
+
compiled = `import React from 'react';\n${compiled}`;
|
|
303
|
+
}
|
|
304
|
+
|
|
300
305
|
compiled = fixRelativeImports(compiled);
|
|
301
306
|
|
|
302
307
|
const outFilename = filename.replace(/\.(jsx|tsx|ts)$/, '.js');
|
package/src/server/dev-server.js
CHANGED
|
@@ -4,12 +4,15 @@ import { join, extname } from 'path';
|
|
|
4
4
|
import { existsSync } from 'fs';
|
|
5
5
|
import logger from '../logger/logger.js';
|
|
6
6
|
import { compileProject } from '../client/compiler.js';
|
|
7
|
+
import { loadConfig } from '../config/loadConfig.js';
|
|
7
8
|
|
|
8
9
|
export async function startDevServer(options = {}) {
|
|
9
10
|
const port = parseInt(options.port) || 3000;
|
|
10
11
|
const root = options.root || process.cwd();
|
|
11
12
|
const compiledDir = join(root, '.bertui', 'compiled');
|
|
12
13
|
|
|
14
|
+
const config = await loadConfig(root);
|
|
15
|
+
|
|
13
16
|
const clients = new Set();
|
|
14
17
|
let hasRouter = false;
|
|
15
18
|
|
|
@@ -21,7 +24,7 @@ export async function startDevServer(options = {}) {
|
|
|
21
24
|
|
|
22
25
|
const app = new Elysia()
|
|
23
26
|
.get('/', async () => {
|
|
24
|
-
return serveHTML(root, hasRouter);
|
|
27
|
+
return serveHTML(root, hasRouter, config);
|
|
25
28
|
})
|
|
26
29
|
|
|
27
30
|
.get('/*', async ({ params, set }) => {
|
|
@@ -45,11 +48,21 @@ export async function startDevServer(options = {}) {
|
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
|
|
51
|
+
if (path.startsWith('public/')) {
|
|
52
|
+
const publicDir = join(root, 'public');
|
|
53
|
+
const filepath = join(publicDir, path.replace('public/', ''));
|
|
54
|
+
const file = Bun.file(filepath);
|
|
55
|
+
|
|
56
|
+
if (await file.exists()) {
|
|
57
|
+
return new Response(file);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
48
61
|
set.status = 404;
|
|
49
62
|
return 'File not found';
|
|
50
63
|
}
|
|
51
64
|
|
|
52
|
-
return serveHTML(root, hasRouter);
|
|
65
|
+
return serveHTML(root, hasRouter, config);
|
|
53
66
|
})
|
|
54
67
|
|
|
55
68
|
.get('/hmr-client.js', () => {
|
|
@@ -141,21 +154,34 @@ ws.onclose = () => {
|
|
|
141
154
|
logger.success(`🚀 Server running at http://localhost:${port}`);
|
|
142
155
|
logger.info(`📁 Serving: ${root}`);
|
|
143
156
|
|
|
144
|
-
setupWatcher(root, compiledDir, clients, () => {
|
|
157
|
+
setupWatcher(root, compiledDir, clients, async () => {
|
|
145
158
|
hasRouter = existsSync(join(compiledDir, 'router.js'));
|
|
146
159
|
});
|
|
147
160
|
|
|
148
161
|
return app;
|
|
149
162
|
}
|
|
150
163
|
|
|
151
|
-
function serveHTML(root, hasRouter) {
|
|
164
|
+
function serveHTML(root, hasRouter, config) {
|
|
165
|
+
const meta = config.meta || {};
|
|
166
|
+
|
|
152
167
|
const html = `
|
|
153
168
|
<!DOCTYPE html>
|
|
154
|
-
<html lang="en">
|
|
169
|
+
<html lang="${meta.lang || 'en'}">
|
|
155
170
|
<head>
|
|
156
171
|
<meta charset="UTF-8">
|
|
157
172
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
158
|
-
<title
|
|
173
|
+
<title>${meta.title || 'BertUI App'}</title>
|
|
174
|
+
|
|
175
|
+
${meta.description ? `<meta name="description" content="${meta.description}">` : ''}
|
|
176
|
+
${meta.keywords ? `<meta name="keywords" content="${meta.keywords}">` : ''}
|
|
177
|
+
${meta.author ? `<meta name="author" content="${meta.author}">` : ''}
|
|
178
|
+
${meta.themeColor ? `<meta name="theme-color" content="${meta.themeColor}">` : ''}
|
|
179
|
+
|
|
180
|
+
${meta.ogTitle ? `<meta property="og:title" content="${meta.ogTitle || meta.title}">` : ''}
|
|
181
|
+
${meta.ogDescription ? `<meta property="og:description" content="${meta.ogDescription || meta.description}">` : ''}
|
|
182
|
+
${meta.ogImage ? `<meta property="og:image" content="${meta.ogImage}">` : ''}
|
|
183
|
+
|
|
184
|
+
<link rel="icon" type="image/svg+xml" href="/public/favicon.svg">
|
|
159
185
|
|
|
160
186
|
<script type="importmap">
|
|
161
187
|
{
|
|
@@ -182,10 +208,7 @@ function serveHTML(root, hasRouter) {
|
|
|
182
208
|
<body>
|
|
183
209
|
<div id="root"></div>
|
|
184
210
|
<script type="module" src="/hmr-client.js"></script>
|
|
185
|
-
|
|
186
|
-
? '<script type="module" src="/compiled/main.js"></script>'
|
|
187
|
-
: '<script type="module" src="/compiled/main.js"></script>'
|
|
188
|
-
}
|
|
211
|
+
<script type="module" src="/compiled/main.js"></script>
|
|
189
212
|
</body>
|
|
190
213
|
</html>`;
|
|
191
214
|
|
|
@@ -214,6 +237,7 @@ function getContentType(ext) {
|
|
|
214
237
|
|
|
215
238
|
function setupWatcher(root, compiledDir, clients, onRecompile) {
|
|
216
239
|
const srcDir = join(root, 'src');
|
|
240
|
+
const configPath = join(root, 'bertui.config.js');
|
|
217
241
|
|
|
218
242
|
if (!existsSync(srcDir)) {
|
|
219
243
|
logger.warn('src/ directory not found');
|
|
@@ -241,7 +265,7 @@ function setupWatcher(root, compiledDir, clients, onRecompile) {
|
|
|
241
265
|
await compileProject(root);
|
|
242
266
|
|
|
243
267
|
if (onRecompile) {
|
|
244
|
-
onRecompile();
|
|
268
|
+
await onRecompile();
|
|
245
269
|
}
|
|
246
270
|
|
|
247
271
|
for (const client of clients) {
|
|
@@ -256,4 +280,20 @@ function setupWatcher(root, compiledDir, clients, onRecompile) {
|
|
|
256
280
|
}
|
|
257
281
|
}
|
|
258
282
|
});
|
|
283
|
+
|
|
284
|
+
if (existsSync(configPath)) {
|
|
285
|
+
watch(configPath, async (eventType) => {
|
|
286
|
+
if (eventType === 'change') {
|
|
287
|
+
logger.info('📝 Config changed, reloading...');
|
|
288
|
+
|
|
289
|
+
for (const client of clients) {
|
|
290
|
+
try {
|
|
291
|
+
client.send(JSON.stringify({ type: 'reload', file: 'bertui.config.js' }));
|
|
292
|
+
} catch (e) {
|
|
293
|
+
clients.delete(client);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
259
299
|
}
|