bertui 0.1.4 → 0.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/index.js CHANGED
@@ -1,25 +1,23 @@
1
- // index.js - Main BertUI package exports
1
+ // index.js
2
2
  import logger from "./src/logger/logger.js";
3
3
  import { defaultConfig } from "./src/config/defaultConfig.js";
4
+ import { loadConfig } from "./src/config/loadConfig.js";
4
5
  import { startDev } from "./src/dev.js";
5
6
  import { buildProduction } from "./src/build.js";
6
7
  import { compileProject } from "./src/client/compiler.js";
8
+ import { buildCSS, copyCSS } from "./src/build/css-builder.js";
7
9
  import { program } from "./src/cli.js";
8
10
 
9
- // Router exports - these will be available after compilation
10
- // Users import these from 'bertui/router'
11
- // export { Link, navigate, Router } from './src/router/router.js';
12
- // reason commnedt out is In JavaScript/TypeScript modules, if you define functions/components inside a file, you must explicitly use the export keyword for them to be available to other files that import them.
13
-
14
- // Your router.js file contains a function, generateRouterCode(routes), which internally defines the Link, Maps, and Router components/functions as strings within a template
15
-
16
- // Named exports for CLI and build tools
11
+ // Named exports
17
12
  export {
18
13
  logger,
19
14
  defaultConfig,
15
+ loadConfig,
20
16
  startDev,
21
17
  buildProduction,
22
18
  compileProject,
19
+ buildCSS,
20
+ copyCSS,
23
21
  program
24
22
  };
25
23
 
@@ -27,9 +25,12 @@ export {
27
25
  export default {
28
26
  logger,
29
27
  defaultConfig,
28
+ loadConfig,
30
29
  startDev,
31
30
  buildProduction,
32
31
  compileProject,
32
+ buildCSS,
33
+ copyCSS,
33
34
  program,
34
- version: "0.1.4"
35
+ version: "0.1.5"
35
36
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bertui",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Lightning-fast React dev server powered by Bun and Elysia",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -8,22 +8,16 @@
8
8
  "bertui": "./bin/bertui.js"
9
9
  },
10
10
  "exports": {
11
- ".": {
12
- "import": "./index.js",
13
- "require": "./index.js"
14
- },
11
+ ".": "./index.js",
15
12
  "./styles": "./src/styles/bertui.css",
16
- "./logger": "./src/logger/logger.js",
17
- "./router": {
18
- "import": "./src/router/client-exports.js",
19
- "require": "./src/router/client-exports.js"
20
- }
13
+ "./logger": "./src/logger/logger.js"
21
14
  },
22
15
  "files": [
23
16
  "bin",
24
17
  "src",
25
18
  "index.js",
26
- "README.md"
19
+ "README.md",
20
+ "LICENSE"
27
21
  ],
28
22
  "scripts": {
29
23
  "dev": "bun bin/bertui.js dev",
@@ -38,10 +32,10 @@
38
32
  "elysia",
39
33
  "build-tool",
40
34
  "bundler",
41
- "routing",
42
- "file-based-routing"
35
+ "fast",
36
+ "hmr"
43
37
  ],
44
- "author": "Your Name",
38
+ "author": "Pease Ernest",
45
39
  "license": "MIT",
46
40
  "repository": {
47
41
  "type": "git",
@@ -49,11 +43,17 @@
49
43
  },
50
44
  "dependencies": {
51
45
  "elysia": "^1.0.0",
52
- "ernest-logger": "latest"
46
+ "ernest-logger": "latest",
47
+ "postcss": "^8.4.32",
48
+ "autoprefixer": "^10.4.16",
49
+ "cssnano": "^6.0.2"
53
50
  },
54
51
  "peerDependencies": {
55
52
  "react": "^18.0.0 || ^19.0.0",
56
53
  "react-dom": "^18.0.0 || ^19.0.0",
57
54
  "bun": ">=1.0.0"
55
+ },
56
+ "engines": {
57
+ "bun": ">=1.0.0"
58
58
  }
59
59
  }
@@ -0,0 +1,84 @@
1
+ // src/build/css-builder.js
2
+ import { join } from 'path';
3
+ import { existsSync, mkdirSync } from 'fs';
4
+ import postcss from 'postcss';
5
+ import autoprefixer from 'autoprefixer';
6
+ import cssnano from 'cssnano';
7
+ import logger from '../logger/logger.js';
8
+
9
+ /**
10
+ * Build and minify CSS for production
11
+ * @param {string} srcPath - Source CSS file path
12
+ * @param {string} destPath - Destination CSS file path
13
+ */
14
+ export async function buildCSS(srcPath, destPath) {
15
+ try {
16
+ logger.info('Processing CSS...');
17
+
18
+ // Ensure destination directory exists
19
+ const destDir = join(destPath, '..');
20
+ if (!existsSync(destDir)) {
21
+ mkdirSync(destDir, { recursive: true });
22
+ }
23
+
24
+ // Read source CSS
25
+ const css = await Bun.file(srcPath).text();
26
+
27
+ // Process with PostCSS
28
+ const result = await postcss([
29
+ autoprefixer(),
30
+ cssnano({
31
+ preset: ['default', {
32
+ discardComments: { removeAll: true },
33
+ normalizeWhitespace: true,
34
+ colormin: true,
35
+ minifyFontValues: true,
36
+ minifySelectors: true,
37
+ }]
38
+ })
39
+ ]).process(css, { from: srcPath, to: destPath });
40
+
41
+ // Write minified CSS
42
+ await Bun.write(destPath, result.css);
43
+
44
+ // Calculate size reduction
45
+ const originalSize = (Buffer.byteLength(css) / 1024).toFixed(2);
46
+ const minifiedSize = (Buffer.byteLength(result.css) / 1024).toFixed(2);
47
+ const reduction = ((1 - Buffer.byteLength(result.css) / Buffer.byteLength(css)) * 100).toFixed(1);
48
+
49
+ logger.success(`CSS minified: ${originalSize}KB → ${minifiedSize}KB (-${reduction}%)`);
50
+
51
+ if (result.warnings().length > 0) {
52
+ result.warnings().forEach(warn => {
53
+ logger.warn(warn.toString());
54
+ });
55
+ }
56
+
57
+ return { success: true, size: minifiedSize };
58
+ } catch (error) {
59
+ logger.error(`CSS build failed: ${error.message}`);
60
+ throw error;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Copy CSS without minification (for dev)
66
+ * @param {string} srcPath - Source CSS file path
67
+ * @param {string} destPath - Destination CSS file path
68
+ */
69
+ export async function copyCSS(srcPath, destPath) {
70
+ try {
71
+ const destDir = join(destPath, '..');
72
+ if (!existsSync(destDir)) {
73
+ mkdirSync(destDir, { recursive: true });
74
+ }
75
+
76
+ await Bun.write(destPath, Bun.file(srcPath));
77
+ logger.info('CSS copied for development');
78
+
79
+ return { success: true };
80
+ } catch (error) {
81
+ logger.error(`CSS copy failed: ${error.message}`);
82
+ throw error;
83
+ }
84
+ }
package/src/build.js CHANGED
@@ -1,7 +1,8 @@
1
1
  // src/build.js
2
2
  import { join } from 'path';
3
- import { existsSync, mkdirSync, rmSync } from 'fs';
3
+ import { existsSync, mkdirSync, rmSync, cpSync } from 'fs';
4
4
  import logger from './logger/logger.js';
5
+ import { buildCSS } from './build/css-builder.js';
5
6
 
6
7
  export async function buildProduction(options = {}) {
7
8
  const root = options.root || process.cwd();
@@ -19,10 +20,34 @@ export async function buildProduction(options = {}) {
19
20
  const startTime = Date.now();
20
21
 
21
22
  try {
22
- // Build with Bun's bundler
23
+ // Step 1: Build CSS from BertUI library
24
+ logger.info('Step 1: Building CSS...');
25
+ const bertuiCssSource = join(import.meta.dir, 'styles/bertui.css');
26
+ const bertuiCssDest = join(outDir, 'styles/bertui.min.css');
27
+ await buildCSS(bertuiCssSource, bertuiCssDest);
28
+
29
+ // Step 2: Copy public assets if they exist
30
+ const publicDir = join(root, 'public');
31
+ if (existsSync(publicDir)) {
32
+ logger.info('Step 2: Copying public assets...');
33
+ cpSync(publicDir, outDir, { recursive: true });
34
+ logger.success('Public assets copied');
35
+ } else {
36
+ logger.info('Step 2: No public directory found, skipping...');
37
+ }
38
+
39
+ // Step 3: Build JavaScript with Bun's bundler
40
+ logger.info('Step 3: Bundling JavaScript...');
41
+ const mainEntry = join(root, 'src/main.jsx');
42
+
43
+ if (!existsSync(mainEntry)) {
44
+ logger.error('Entry point not found: src/main.jsx');
45
+ process.exit(1);
46
+ }
47
+
23
48
  const result = await Bun.build({
24
- entrypoints: [join(root, 'src/main.jsx')],
25
- outdir: outDir,
49
+ entrypoints: [mainEntry],
50
+ outdir: join(outDir, 'assets'),
26
51
  target: 'browser',
27
52
  minify: true,
28
53
  splitting: true,
@@ -30,35 +55,38 @@ export async function buildProduction(options = {}) {
30
55
  naming: {
31
56
  entry: '[name]-[hash].js',
32
57
  chunk: 'chunks/[name]-[hash].js',
33
- asset: 'assets/[name]-[hash].[ext]'
34
- }
58
+ asset: '[name]-[hash].[ext]'
59
+ },
60
+ external: [] // Don't externalize anything for browser builds
35
61
  });
36
62
 
37
63
  if (!result.success) {
38
- logger.error('Build failed!');
64
+ logger.error('JavaScript build failed!');
39
65
  result.logs.forEach(log => logger.error(log.message));
40
66
  process.exit(1);
41
67
  }
42
68
 
43
- // Copy BertUI CSS to dist
44
- const bertuiCss = join(import.meta.dir, 'styles/bertui.css');
45
- const destCss = join(outDir, 'bertui.css');
46
- await Bun.write(destCss, Bun.file(bertuiCss));
47
- logger.info('Copied BertUI CSS');
69
+ logger.success('JavaScript bundled');
48
70
 
49
- // Generate index.html
71
+ // Step 4: Generate index.html
72
+ logger.info('Step 4: Generating index.html...');
50
73
  await generateProductionHTML(root, outDir, result);
51
74
 
52
75
  const duration = Date.now() - startTime;
53
- logger.success(`Build complete in ${duration}ms`);
54
- logger.info(`Output: ${outDir}`);
76
+ logger.success(`✨ Build complete in ${duration}ms`);
77
+ logger.info(`📦 Output: ${outDir}`);
78
+
79
+ // Display build stats
55
80
  logger.table(result.outputs.map(o => ({
56
- file: o.path,
81
+ file: o.path.replace(outDir, ''),
57
82
  size: `${(o.size / 1024).toFixed(2)} KB`
58
83
  })));
59
84
 
60
85
  } catch (error) {
61
86
  logger.error(`Build failed: ${error.message}`);
87
+ if (error.stack) {
88
+ logger.error(error.stack);
89
+ }
62
90
  process.exit(1);
63
91
  }
64
92
  }
@@ -70,25 +98,26 @@ async function generateProductionHTML(root, outDir, buildResult) {
70
98
  );
71
99
 
72
100
  if (!mainBundle) {
73
- throw new Error('Could not find main bundle');
101
+ throw new Error('Could not find main bundle in build output');
74
102
  }
75
103
 
76
- const bundleName = mainBundle.path.split('/').pop();
104
+ const bundlePath = mainBundle.path.replace(outDir, '').replace(/^\//, '');
77
105
 
78
106
  const html = `<!DOCTYPE html>
79
107
  <html lang="en">
80
108
  <head>
81
109
  <meta charset="UTF-8">
82
110
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
111
+ <meta name="description" content="Built with BertUI - Lightning fast React development">
83
112
  <title>BertUI App</title>
84
- <link rel="stylesheet" href="/bertui.css">
113
+ <link rel="stylesheet" href="/styles/bertui.min.css">
85
114
  </head>
86
115
  <body>
87
116
  <div id="root"></div>
88
- <script type="module" src="/${bundleName}"></script>
117
+ <script type="module" src="/${bundlePath}"></script>
89
118
  </body>
90
119
  </html>`;
91
120
 
92
121
  await Bun.write(join(outDir, 'index.html'), html);
93
- logger.info('Generated index.html');
122
+ logger.success('Generated index.html');
94
123
  }
@@ -51,40 +51,39 @@ export async function compileProject(root) {
51
51
  }
52
52
  }
53
53
 
54
- // Transpile with Bun
55
- const result = await Bun.build({
56
- entrypoints: [entryPoint],
57
- outdir: compiledDir,
58
- target: 'browser',
59
- format: 'esm',
60
- splitting: true,
61
- naming: {
62
- entry: '[name].js',
63
- chunk: 'chunks/[name]-[hash].js'
64
- },
65
- external: ['react', 'react-dom'],
66
- define: {
67
- 'process.env.NODE_ENV': '"development"'
54
+ // Update the Bun.build section in buildProduction function
55
+
56
+ // Build with Bun's bundler
57
+ const result = await Bun.build({
58
+ entrypoints: [join(root, 'src/main.jsx')],
59
+ outdir: outDir,
60
+ target: 'browser',
61
+ minify: true,
62
+ splitting: true,
63
+ sourcemap: 'external',
64
+ naming: {
65
+ entry: '[name]-[hash].js',
66
+ chunk: 'chunks/[name]-[hash].js',
67
+ asset: 'assets/[name]-[hash].[ext]'
68
+ }
69
+ });
70
+
71
+ if (!result.success) {
72
+ logger.error('Build failed!');
73
+
74
+ // Log detailed errors
75
+ if (result.logs && result.logs.length > 0) {
76
+ logger.error('Detailed errors:');
77
+ result.logs.forEach((log, index) => {
78
+ logger.error(` [${index + 1}] ${log.message}`);
79
+ if (log.location) {
80
+ logger.error(` at ${log.location.file}:${log.location.line}:${log.location.column}`);
68
81
  }
69
82
  });
70
-
71
- if (!result.success) {
72
- logger.error('Compilation failed!');
73
- result.logs.forEach(log => logger.error(log.message));
74
- throw new Error('Build failed');
75
- }
76
-
77
- // Copy BertUI CSS
78
- const bertuiCss = join(import.meta.dir, '../styles/bertui.css');
79
- if (existsSync(bertuiCss)) {
80
- await Bun.write(join(compiledDir, 'bertui.css'), Bun.file(bertuiCss));
81
- }
82
-
83
- const duration = Date.now() - startTime;
84
- logger.success(`Compiled in ${duration}ms`);
85
-
86
- return { success: true, routes };
87
-
83
+ }
84
+
85
+ process.exit(1);
86
+ }
88
87
  } catch (error) {
89
88
  logger.error(`Compilation error: ${error.message}`);
90
89
  throw error;
@@ -1,7 +1,8 @@
1
+ // src/config/loadConfig.js
1
2
  import { join } from 'path';
2
3
  import { existsSync } from 'fs';
3
4
  import { defaultConfig } from './defaultConfig.js';
4
- import logger from '../utils/logger.js';
5
+ import logger from '../logger/logger.js';
5
6
 
6
7
  export async function loadConfig(root) {
7
8
  const configPath = join(root, 'bertui.config.js');
@@ -15,7 +16,7 @@ export async function loadConfig(root) {
15
16
  // Merge user config with defaults
16
17
  return mergeConfig(defaultConfig, userConfig.default || userConfig);
17
18
  } catch (error) {
18
- logger.error(`Failed to load config make sure the file bertui.config.js is in the root directory of the app if not create it : ${error.message}`);
19
+ logger.error(`Failed to load config. Make sure bertui.config.js is in the root directory: ${error.message}`);
19
20
  return defaultConfig;
20
21
  }
21
22
  }
@@ -26,7 +27,7 @@ export async function loadConfig(root) {
26
27
 
27
28
  function mergeConfig(defaults, user) {
28
29
  return {
29
- meta: { ...defaults.meta, ...user.meta },
30
- appShell: { ...defaults.appShell, ...user.appShell }
30
+ meta: { ...defaults.meta, ...(user.meta || {}) },
31
+ appShell: { ...defaults.appShell, ...(user.appShell || {}) }
31
32
  };
32
33
  }
@@ -12,40 +12,22 @@ export async function startDevServer(options = {}) {
12
12
  const compiledDir = join(root, '.bertui', 'compiled');
13
13
 
14
14
  const clients = new Set();
15
- let currentRoutes = [];
16
15
 
17
16
  const app = new Elysia()
18
- // Serve index.html for all routes (SPA mode)
19
- .get('/*', async ({ params }) => {
20
- // Check if it's requesting a file
21
- const path = params['*'] || '';
22
-
23
- if (path.includes('.')) {
24
- // It's a file request, handle it separately
25
- return await serveFile(compiledDir, path);
26
- }
27
-
28
- // Serve the SPA HTML for all routes
17
+ .get('/', async () => {
29
18
  const html = `
30
19
  <!DOCTYPE html>
31
20
  <html lang="en">
32
21
  <head>
33
22
  <meta charset="UTF-8">
34
23
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
35
- <title>BertUI App</title>
36
- <link rel="stylesheet" href="/compiled/bertui.css">
24
+ <title>BertUI App - Dev</title>
25
+ <link rel="stylesheet" href="/styles/bertui.css">
37
26
  </head>
38
27
  <body>
39
28
  <div id="root"></div>
40
29
  <script type="module" src="/hmr-client.js"></script>
41
- <script type="module">
42
- // Provide React and ReactDOM from CDN for dev
43
- import React from 'https://esm.sh/react@18.2.0';
44
- import ReactDOM from 'https://esm.sh/react-dom@18.2.0';
45
- window.React = React;
46
- window.ReactDOM = ReactDOM;
47
- </script>
48
- <script type="module" src="/compiled/main-entry.js"></script>
30
+ <script type="module" src="/compiled/main.js"></script>
49
31
  </body>
50
32
  </html>`;
51
33
 
@@ -66,28 +48,21 @@ ws.onmessage = (event) => {
66
48
  const data = JSON.parse(event.data);
67
49
 
68
50
  if (data.type === 'reload') {
69
- console.log('%c🔄 Hot reloading...', 'color: #f59e0b');
51
+ console.log('%c🔄 Reloading...', 'color: #f59e0b');
70
52
  window.location.reload();
71
53
  }
72
54
 
73
55
  if (data.type === 'recompiling') {
74
56
  console.log('%c⚙️ Recompiling...', 'color: #3b82f6');
75
57
  }
76
-
77
- if (data.type === 'routes-updated') {
78
- console.log('%c📍 Routes updated:', 'color: #8b5cf6; font-weight: bold');
79
- data.routes.forEach(r => {
80
- console.log(\` \${r.path} → \${r.file}\`);
81
- });
82
- }
83
58
  };
84
59
 
85
60
  ws.onerror = (error) => {
86
- console.error('HMR connection error:', error);
61
+ console.error('%c❌ HMR connection error', 'color: #ef4444', error);
87
62
  };
88
63
 
89
64
  ws.onclose = () => {
90
- console.log('%c HMR disconnected. Refresh to reconnect.', 'color: #ef4444');
65
+ console.log('%c⚠️ HMR disconnected. Refresh to reconnect.', 'color: #f59e0b');
91
66
  };
92
67
  `;
93
68
 
@@ -100,18 +75,29 @@ ws.onclose = () => {
100
75
  open(ws) {
101
76
  clients.add(ws);
102
77
  logger.info('Client connected to HMR');
103
-
104
- // Send current routes on connection
105
- if (currentRoutes.length > 0) {
106
- ws.send(JSON.stringify({
107
- type: 'routes-updated',
108
- routes: currentRoutes
109
- }));
110
- }
111
78
  },
112
79
  close(ws) {
113
80
  clients.delete(ws);
81
+ logger.info('Client disconnected from HMR');
82
+ }
83
+ })
84
+
85
+ // Serve BertUI CSS
86
+ .get('/styles/bertui.css', async ({ set }) => {
87
+ const cssPath = join(import.meta.dir, '../styles/bertui.css');
88
+ const file = Bun.file(cssPath);
89
+
90
+ if (!await file.exists()) {
91
+ set.status = 404;
92
+ return 'CSS file not found';
114
93
  }
94
+
95
+ return new Response(await file.text(), {
96
+ headers: {
97
+ 'Content-Type': 'text/css',
98
+ 'Cache-Control': 'no-store'
99
+ }
100
+ });
115
101
  })
116
102
 
117
103
  // Serve compiled files
@@ -125,7 +111,9 @@ ws.onclose = () => {
125
111
  }
126
112
 
127
113
  const ext = extname(filepath);
128
- const contentType = getContentType(ext);
114
+ const contentType = ext === '.js' ? 'application/javascript' :
115
+ ext === '.css' ? 'text/css' :
116
+ 'text/plain';
129
117
 
130
118
  return new Response(await file.text(), {
131
119
  headers: {
@@ -135,6 +123,20 @@ ws.onclose = () => {
135
123
  });
136
124
  })
137
125
 
126
+ // Serve public assets
127
+ .get('/public/*', async ({ params, set }) => {
128
+ const publicDir = join(root, 'public');
129
+ const filepath = join(publicDir, params['*']);
130
+ const file = Bun.file(filepath);
131
+
132
+ if (!await file.exists()) {
133
+ set.status = 404;
134
+ return 'File not found';
135
+ }
136
+
137
+ return new Response(file);
138
+ })
139
+
138
140
  .listen(port);
139
141
 
140
142
  if (!app.server) {
@@ -142,50 +144,16 @@ ws.onclose = () => {
142
144
  process.exit(1);
143
145
  }
144
146
 
145
- logger.success(`Server running at http://localhost:${port}`);
146
- logger.info('Press Ctrl+C to stop');
147
+ logger.success(`🚀 Server running at http://localhost:${port}`);
148
+ logger.info(`📁 Serving: ${root}`);
147
149
 
148
150
  // Watch for file changes
149
- setupWatcher(root, clients, (routes) => {
150
- currentRoutes = routes;
151
- });
151
+ setupWatcher(root, compiledDir, clients);
152
152
 
153
153
  return app;
154
154
  }
155
155
 
156
- async function serveFile(compiledDir, path) {
157
- const filepath = join(compiledDir, path);
158
- const file = Bun.file(filepath);
159
-
160
- if (!await file.exists()) {
161
- return new Response('File not found', { status: 404 });
162
- }
163
-
164
- const ext = extname(filepath);
165
- const contentType = getContentType(ext);
166
-
167
- return new Response(await file.text(), {
168
- headers: {
169
- 'Content-Type': contentType,
170
- 'Cache-Control': 'no-store'
171
- }
172
- });
173
- }
174
-
175
- function getContentType(ext) {
176
- const types = {
177
- '.js': 'application/javascript',
178
- '.css': 'text/css',
179
- '.html': 'text/html',
180
- '.json': 'application/json',
181
- '.png': 'image/png',
182
- '.jpg': 'image/jpeg',
183
- '.svg': 'image/svg+xml'
184
- };
185
- return types[ext] || 'text/plain';
186
- }
187
-
188
- function setupWatcher(root, clients, onRoutesUpdate) {
156
+ function setupWatcher(root, compiledDir, clients) {
189
157
  const srcDir = join(root, 'src');
190
158
 
191
159
  if (!existsSync(srcDir)) {
@@ -195,15 +163,11 @@ function setupWatcher(root, clients, onRoutesUpdate) {
195
163
 
196
164
  logger.info(`👀 Watching: ${srcDir}`);
197
165
 
198
- let isRecompiling = false;
199
-
200
166
  watch(srcDir, { recursive: true }, async (eventType, filename) => {
201
- if (!filename || isRecompiling) return;
167
+ if (!filename) return;
202
168
 
203
169
  const ext = extname(filename);
204
170
  if (['.js', '.jsx', '.ts', '.tsx', '.css'].includes(ext)) {
205
- isRecompiling = true;
206
-
207
171
  logger.info(`📝 File changed: ${filename}`);
208
172
 
209
173
  // Notify clients that recompilation is starting
@@ -217,23 +181,7 @@ function setupWatcher(root, clients, onRoutesUpdate) {
217
181
 
218
182
  // Recompile the project
219
183
  try {
220
- const result = await compileProject(root);
221
-
222
- // Notify about route changes
223
- if (result.routes && result.routes.length > 0) {
224
- onRoutesUpdate(result.routes);
225
-
226
- for (const client of clients) {
227
- try {
228
- client.send(JSON.stringify({
229
- type: 'routes-updated',
230
- routes: result.routes
231
- }));
232
- } catch (e) {
233
- clients.delete(client);
234
- }
235
- }
236
- }
184
+ await compileProject(root);
237
185
 
238
186
  // Notify clients to reload
239
187
  for (const client of clients) {
@@ -245,8 +193,6 @@ function setupWatcher(root, clients, onRoutesUpdate) {
245
193
  }
246
194
  } catch (error) {
247
195
  logger.error(`Recompilation failed: ${error.message}`);
248
- } finally {
249
- isRecompiling = false;
250
196
  }
251
197
  }
252
198
  });