vaderjs 2.3.14 → 2.3.15

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/main.js DELETED
@@ -1,750 +0,0 @@
1
- #!/usr/bin/env bun
2
-
3
- import { build, serve } from "bun";
4
- import fs from "fs/promises";
5
- import fsSync from "fs";
6
- import path from "path";
7
- import { initProject, addPlugin, listPlugins, removePlugin } from "./cli";
8
-
9
- // --- UTILITIES for a Sleek CLI ---
10
-
11
- const colors = {
12
- reset: "\x1b[0m",
13
- red: "\x1b[31m",
14
- green: "\x1b[32m",
15
- yellow: "\x1b[33m",
16
- blue: "\x1b[34m",
17
- magenta: "\x1b[35m",
18
- cyan: "\x1b[36m",
19
- };
20
-
21
- const logger = {
22
- _log: (color, ...args) => console.log(color, ...args, colors.reset),
23
- info: (...args) => logger._log(colors.cyan, "ℹ", ...args),
24
- success: (...args) => logger._log(colors.green, "✅", ...args),
25
- warn: (...args) => logger._log(colors.yellow, "⚠️", ...args),
26
- error: (...args) => logger._log(colors.red, "❌", ...args),
27
- step: (...args) => logger._log(colors.magenta, "\n🚀", ...args),
28
- };
29
-
30
- async function timedStep(name, fn) {
31
- logger.step(`${name}...`);
32
- const start = performance.now();
33
- try {
34
- await fn();
35
- const duration = (performance.now() - start).toFixed(2);
36
- logger.success(`Finished '${name}' in ${duration}ms`);
37
- } catch (e) {
38
- logger.error(`Error during '${name}':`, e);
39
- if (!isDev) process.exit(1);
40
- }
41
- }
42
-
43
- // --- CONSTANTS ---
44
-
45
- const PROJECT_ROOT = process.cwd();
46
- const APP_DIR = path.join(PROJECT_ROOT, "app");
47
- const PUBLIC_DIR = path.join(PROJECT_ROOT, "public");
48
- const DIST_DIR = path.join(PROJECT_ROOT, "dist");
49
- const SRC_DIR = path.join(PROJECT_ROOT, "src");
50
- const VADER_SRC_PATH = path.join(PROJECT_ROOT, "node_modules", "vaderjs", "index.ts");
51
- const TEMP_SRC_DIR = path.join(PROJECT_ROOT, ".vader_temp_src");
52
-
53
- // --- SIMPLIFIED WATCHER ---
54
-
55
- class FileWatcher {
56
- constructor() {
57
- this.watchers = new Map();
58
- this.onChangeCallbacks = [];
59
- this.isRebuilding = false;
60
- this.lastRebuildTime = 0;
61
- this.REBUILD_COOLDOWN = 1000; // 1 second cooldown between rebuilds
62
- }
63
-
64
- shouldIgnorePath(filePath) {
65
- const normalized = path.normalize(filePath);
66
- // Ignore dist folder and its contents
67
- if (normalized.includes(path.normalize(DIST_DIR))) {
68
- return true;
69
- }
70
- // Ignore node_modules
71
- if (normalized.includes(path.normalize('node_modules'))) {
72
- return true;
73
- }
74
- // Ignore .git folder
75
- if (normalized.includes(path.normalize('.git'))) {
76
- return true;
77
- }
78
- // Ignore the temporary source directory
79
- if (normalized.includes(path.normalize(TEMP_SRC_DIR))) {
80
- return true;
81
- }
82
- return false;
83
- }
84
-
85
- async watchDirectory(dirPath, recursive = true) {
86
- // Skip if directory should be ignored
87
- if (this.shouldIgnorePath(dirPath) || !fsSync.existsSync(dirPath)) {
88
- return;
89
- }
90
-
91
- try {
92
- // Close existing watcher if any
93
- if (this.watchers.has(dirPath)) {
94
- try {
95
- this.watchers.get(dirPath).close();
96
- } catch (err) {
97
- // Ignore close errors
98
- }
99
- }
100
-
101
- // Create new watcher
102
- const watcher = fsSync.watch(dirPath, { recursive }, (eventType, filename) => {
103
- if (!filename) return;
104
-
105
- const changedFile = path.join(dirPath, filename);
106
- const normalizedChanged = path.normalize(changedFile);
107
-
108
- // Skip if file should be ignored
109
- if (this.shouldIgnorePath(normalizedChanged)) {
110
- return;
111
- }
112
-
113
- // Check if this is a file we care about
114
- if (this.shouldTriggerRebuild(normalizedChanged)) {
115
- logger.info(`File changed: ${path.relative(PROJECT_ROOT, normalizedChanged)}`);
116
-
117
- // Only trigger if not already rebuilding and cooldown has passed
118
- const now = Date.now();
119
- if (!this.isRebuilding && (now - this.lastRebuildTime) > this.REBUILD_COOLDOWN) {
120
- this.triggerChange(normalizedChanged);
121
- } else if (this.isRebuilding) {
122
- logger.info(`Skipping rebuild - already rebuilding`);
123
- } else {
124
- logger.info(`Skipping rebuild - cooldown period`);
125
- }
126
- }
127
- });
128
-
129
- watcher.on('error', (err) => {
130
- logger.warn(`Watcher error on ${dirPath}:`, err.message);
131
- });
132
-
133
- this.watchers.set(dirPath, watcher);
134
-
135
- logger.info(`Watching directory: ${path.relative(PROJECT_ROOT, dirPath)}`);
136
- } catch (err) {
137
- logger.warn(`Could not watch directory ${dirPath}:`, err.message);
138
- }
139
- }
140
-
141
- shouldTriggerRebuild(filePath) {
142
- // Only trigger rebuild for specific file types
143
- const ext = path.extname(filePath).toLowerCase();
144
- const triggerExtensions = ['.js', '.jsx', '.ts', '.tsx', '.css', '.html', '.json', '.config.js', '.config.ts'];
145
- return triggerExtensions.includes(ext) || ext === '';
146
- }
147
-
148
- triggerChange(filePath) {
149
- for (const callback of this.onChangeCallbacks) {
150
- try {
151
- callback(filePath);
152
- } catch (err) {
153
- logger.error("Change callback error:", err);
154
- }
155
- }
156
- }
157
-
158
- onChange(callback) {
159
- this.onChangeCallbacks.push(callback);
160
- return () => {
161
- const index = this.onChangeCallbacks.indexOf(callback);
162
- if (index > -1) this.onChangeCallbacks.splice(index, 1);
163
- };
164
- }
165
-
166
- setRebuilding(state) {
167
- this.isRebuilding = state;
168
- if (state) {
169
- this.lastRebuildTime = Date.now();
170
- }
171
- }
172
-
173
- clear() {
174
- for (const [dir, watcher] of this.watchers) {
175
- try {
176
- watcher.close();
177
- } catch (err) {
178
- // Ignore close errors
179
- }
180
- }
181
- this.watchers.clear();
182
- this.onChangeCallbacks = [];
183
- this.isRebuilding = false;
184
- }
185
- }
186
-
187
- const watcher = new FileWatcher();
188
-
189
- // --- CONFIG & PLUGIN SYSTEM ---
190
-
191
- let config = {};
192
- let htmlInjections = [];
193
-
194
- const vaderAPI = {
195
- runCommand: async (cmd) => {
196
- if (typeof cmd === "string") cmd = cmd.split(" ");
197
- const p = Bun.spawn(cmd);
198
- await p.exited;
199
- },
200
- injectHTML: (content) => htmlInjections.push(content),
201
- log: {
202
- warn: (msg) => logger.warn(msg),
203
- info: (msg) => logger.info(msg),
204
- success: (msg) => logger.success(msg),
205
- step: (msg) => logger.step(msg)
206
- },
207
- getProjectRoot: () => PROJECT_ROOT,
208
- getDistDir: () => DIST_DIR,
209
- getPublicDir: () => PUBLIC_DIR,
210
- };
211
-
212
- async function loadConfig() {
213
- try {
214
- const configModule = await import(path.join(PROJECT_ROOT, "vaderjs.config.js"));
215
- return configModule.default || configModule;
216
- } catch {
217
- logger.warn("No 'vaderjs.config.js' found, using defaults.");
218
- return {};
219
- }
220
- }
221
-
222
- export function defineConfig(config) {
223
- return config;
224
- }
225
-
226
- async function runPluginHook(hookName) {
227
- if (!config.plugins) return;
228
- for (const plugin of config.plugins) {
229
- if (typeof plugin[hookName] === "function") {
230
- try {
231
- await plugin[hookName](vaderAPI);
232
- } catch (e) {
233
- logger.error(`Plugin hook error (${hookName} in ${plugin.name || 'anonymous'}):`, e);
234
- }
235
- }
236
- }
237
- }
238
-
239
- // --- BUILD LOGIC ---
240
-
241
- /**
242
- * Step 1: Transpile and bundle the core vaderjs library.
243
- */
244
- async function buildVaderCore() {
245
- if (!fsSync.existsSync(VADER_SRC_PATH)) {
246
- logger.error("VaderJS source not found:", VADER_SRC_PATH);
247
- throw new Error("Missing vaderjs dependency.");
248
- }
249
-
250
- await build({
251
- entrypoints: [VADER_SRC_PATH],
252
- outdir: path.join(DIST_DIR, "src", "vader"),
253
- target: "browser",
254
- minify: false,
255
- sourcemap: "external",
256
- jsxFactory: "e",
257
- jsxFragment: "Fragment",
258
- jsxImportSource: "vaderjs",
259
- });
260
- }
261
-
262
- /**
263
- * Step 2: Patches source code to remove server-side hook imports.
264
- */
265
- function patchHooksUsage(code) {
266
- return code.replace(/import\s+{[^}]*use(State|Effect|Memo|Navigation)[^}]*}\s+from\s+['"]vaderjs['"];?\n?/g, "");
267
- }
268
-
269
- function publicAssetPlugin() {
270
- return {
271
- name: "public-asset-replacer",
272
- setup(build) {
273
- build.onLoad({ filter: /\.(js|ts|jsx|tsx|html)$/ }, async (args) => {
274
- let code = await fs.readFile(args.path, "utf8");
275
-
276
- code = code.replace(/\{\{public:(.+?)\}\}/g, (_, relPath) => {
277
- const absPath = path.join(PUBLIC_DIR, relPath.trim());
278
- if (fsSync.existsSync(absPath)) {
279
- return "/" + relPath.trim().replace(/\\/g, "/");
280
- }
281
- logger.warn(`Public asset not found: ${relPath}`);
282
- return relPath;
283
- });
284
-
285
- return {
286
- contents: code,
287
- loader: args.path.endsWith(".html")
288
- ? "text"
289
- : args.path.endsWith(".tsx")
290
- ? "tsx"
291
- : args.path.endsWith(".jsx")
292
- ? "jsx"
293
- : args.path.endsWith(".ts")
294
- ? "ts"
295
- : "js",
296
- };
297
- });
298
- },
299
- };
300
- }
301
-
302
- /**
303
- * Step 3: Pre-processes all files in `/src` into a temporary directory.
304
- */
305
- async function preprocessSources(srcDir, tempDir) {
306
- await fs.mkdir(tempDir, { recursive: true });
307
- for (const entry of await fs.readdir(srcDir, { withFileTypes: true })) {
308
- const srcPath = path.join(srcDir, entry.name);
309
- const destPath = path.join(tempDir, entry.name);
310
-
311
- if (entry.isDirectory()) {
312
- await preprocessSources(srcPath, destPath);
313
- } else if (/\.(tsx|jsx|ts|js)$/.test(entry.name)) {
314
- let content = await fs.readFile(srcPath, "utf8");
315
- content = patchHooksUsage(content);
316
- await fs.writeFile(destPath, content);
317
- } else {
318
- await fs.copyFile(srcPath, destPath);
319
- }
320
- }
321
- }
322
-
323
- /**
324
- * Step 4: Build the application's source code from the preprocessed temp directory.
325
- */
326
- async function buildSrc() {
327
- if (!fsSync.existsSync(SRC_DIR)) return;
328
-
329
- if (fsSync.existsSync(TEMP_SRC_DIR)) {
330
- await fs.rm(TEMP_SRC_DIR, { recursive: true, force: true });
331
- }
332
- await preprocessSources(SRC_DIR, TEMP_SRC_DIR);
333
-
334
- const entrypoints = fsSync.readdirSync(TEMP_SRC_DIR, { recursive: true })
335
- .map(file => path.join(TEMP_SRC_DIR, file))
336
- .filter(file => /\.(ts|tsx|js|jsx)$/.test(file));
337
-
338
- if (entrypoints.length === 0) {
339
- logger.info("No source files found in /src to build.");
340
- return;
341
- }
342
-
343
- await build({
344
- entrypoints,
345
- outdir: path.join(DIST_DIR, "src"),
346
- root: TEMP_SRC_DIR,
347
- naming: { entry: "[dir]/[name].js" },
348
- jsxFactory: "e",
349
- jsxFragment: "Fragment",
350
- jsxImportSource: "vaderjs",
351
- target: "browser",
352
- minify: false,
353
- plugins: [
354
- publicAssetPlugin(),
355
- ],
356
- external: ["vaderjs"],
357
- });
358
- }
359
-
360
- /**
361
- * Step 5: Copy all assets from the `/public` directory to `/dist`.
362
- */
363
- async function copyPublicAssets() {
364
- if (!fsSync.existsSync(PUBLIC_DIR)) return;
365
- // Copy contents of public into dist, not the public folder itself
366
- for (const item of await fs.readdir(PUBLIC_DIR)) {
367
- await fs.cp(path.join(PUBLIC_DIR, item), path.join(DIST_DIR, item), { recursive: true });
368
- }
369
- }
370
-
371
- async function buildAppEntrypoint(entryPath, name, isDev = false) {
372
- const outDir = path.join(DIST_DIR, name === 'index' ? '' : name);
373
- const outJsPath = path.join(outDir, 'index.js');
374
- await fs.mkdir(outDir, { recursive: true });
375
-
376
- // --- CSS HANDLING ---
377
- const cssLinks = [];
378
- let content = await fs.readFile(entryPath, "utf8");
379
- const cssImports = [...content.matchAll(/import\s+['"](.*\.css)['"]/g)];
380
- for (const match of cssImports) {
381
- const cssImportPath = match[1];
382
- const sourceCssPath = path.resolve(path.dirname(entryPath), cssImportPath);
383
- if (fsSync.existsSync(sourceCssPath)) {
384
- const relativeCssPath = path.relative(APP_DIR, sourceCssPath);
385
- const destCssPath = path.join(DIST_DIR, relativeCssPath);
386
- await fs.mkdir(path.dirname(destCssPath), { recursive: true });
387
- await fs.copyFile(sourceCssPath, destCssPath);
388
- const htmlRelativePath = path.relative(outDir, destCssPath).replace(/\\/g, '/');
389
- cssLinks.push(`<link rel="stylesheet" href="${htmlRelativePath}">`);
390
- } else {
391
- logger.warn(`CSS file not found: ${sourceCssPath}`);
392
- }
393
- }
394
-
395
- const devClientScript = isDev
396
- ? `<script>
397
- new WebSocket("ws://" + location.host + "/__hmr").onmessage = (msg) => {
398
- if (msg.data === "reload") location.reload();
399
- };
400
- </script>`
401
- : "";
402
-
403
- // --- HTML GENERATION ---
404
- let htmlContent = `<!DOCTYPE html>
405
- <html lang="en">
406
- <head>
407
- <meta charset="UTF-8" />
408
- <title>VaderJS App - ${name}</title>
409
- <meta name="viewport" content="width=device-width, initial-scale=1" />
410
- ${cssLinks.join("\n ")}
411
- ${htmlInjections.join("\n ")}
412
- </head>
413
- <body>
414
- <div id="app"></div>
415
- <script type="module">
416
- import App from '${name !== 'index' ? "/" + name : ''}/index.js';
417
- import * as Vader from '/src/vader/index.js';
418
- window.Vader = Vader;
419
- Vader.render(Vader.createElement(App, null), document.getElementById("app"));
420
- </script>
421
- ${devClientScript}
422
- </body>
423
- </html>`;
424
-
425
- // Helper to resolve any asset path from /public
426
- function resolvePublicPath(p) {
427
- const assetPath = p.replace(/^(\.\/|\/)/, ""); // strip leading ./ or /
428
- const absPath = path.join(PUBLIC_DIR, assetPath);
429
- if (fsSync.existsSync(absPath)) {
430
- return "/" + assetPath.replace(/\\/g, "/");
431
- }
432
- return p; // leave unchanged if not in public
433
- }
434
-
435
- // --- FIX ASSET PATHS IN HTML ---
436
- htmlContent = htmlContent.replace(
437
- /(["'(])([^"'()]+?\.(png|jpe?g|gif|svg|webp|ico))(["')])/gi,
438
- (match, p1, assetPath, ext, p4) => p1 + resolvePublicPath(assetPath) + p4
439
- );
440
-
441
- await fs.writeFile(path.join(outDir, "index.html"), htmlContent);
442
-
443
- // --- JS BUILD ---
444
- await build({
445
- entrypoints: [entryPath],
446
- outdir: outDir,
447
- target: "browser",
448
- minify: false,
449
- sourcemap: "external",
450
- external: ["vaderjs"],
451
- jsxFactory: "e",
452
- jsxFragment: "Fragment",
453
- plugins: [
454
- publicAssetPlugin(),
455
- ],
456
- jsxImportSource: "vaderjs",
457
- });
458
-
459
- // --- FIX IMPORT PATHS IN JS ---
460
- let jsContent = await fs.readFile(outJsPath, "utf8");
461
-
462
- // Vader import fix
463
- jsContent = jsContent.replace(/from\s+['"]vaderjs['"]/g, `from '/src/vader/index.js'`);
464
-
465
- // Asset path fix for JS
466
- jsContent = jsContent.replace(
467
- /(["'(])([^"'()]+?\.(png|jpe?g|gif|svg|webp|ico))(["')])/gi,
468
- (match, p1, assetPath, ext, p4) => p1 + resolvePublicPath(assetPath) + p4
469
- );
470
-
471
- await fs.writeFile(outJsPath, jsContent);
472
- }
473
-
474
- async function buildAppEntrypoints(isDev = false) {
475
- if (!fsSync.existsSync(APP_DIR)) {
476
- logger.warn("No '/app' directory found, skipping app entrypoint build.");
477
- return;
478
- }
479
-
480
- if (!fsSync.existsSync(DIST_DIR)) {
481
- await fs.mkdir(DIST_DIR, { recursive: true });
482
- }
483
-
484
- // Find all index.jsx/tsx files in app directory
485
- const entries = fsSync.readdirSync(APP_DIR, { recursive: true })
486
- .filter(file => /index\.(jsx|tsx)$/.test(file))
487
- .map(file => ({
488
- name: path.dirname(file) === '.' ? 'index' : path.dirname(file).replace(/\\/g, '/'),
489
- path: path.join(APP_DIR, file)
490
- }));
491
-
492
- for (const { name, path: entryPath } of entries) {
493
- await buildAppEntrypoint(entryPath, name, isDev);
494
- }
495
- }
496
-
497
- async function buildAll(isDev = false) {
498
- logger.info(`Starting VaderJS ${isDev ? 'development' : 'production'} build...`);
499
- const totalTime = performance.now();
500
-
501
- htmlInjections = [];
502
-
503
- // Ensure dist directory exists before cleaning
504
- if (fsSync.existsSync(DIST_DIR)) {
505
- await fs.rm(DIST_DIR, { recursive: true, force: true });
506
- }
507
-
508
- // Create the dist directory if it doesn't exist
509
- await fs.mkdir(DIST_DIR, { recursive: true });
510
-
511
- await runPluginHook("onBuildStart");
512
-
513
- // Build the components in steps and handle errors properly
514
- await timedStep("Building VaderJS Core", buildVaderCore);
515
- await timedStep("Building App Source (/src)", buildSrc);
516
- await timedStep("Copying Public Assets", copyPublicAssets);
517
- await timedStep("Building App Entrypoints (/app)", () => buildAppEntrypoints(isDev));
518
-
519
- await runPluginHook("onBuildFinish");
520
-
521
- // Calculate the total duration and log it
522
- const duration = (performance.now() - totalTime).toFixed(2);
523
- logger.success(`Total build finished in ${duration}ms. Output is in /dist.`);
524
- }
525
-
526
- async function runDevServer() {
527
- // Initial build
528
- await buildAll(true);
529
-
530
- const clients = new Set();
531
- const port = config.port || 3000;
532
-
533
- logger.info(`Starting dev server at http://localhost:${port}`);
534
-
535
- // Set up watchers for all important directories
536
- logger.info("Setting up file watchers...");
537
-
538
- // Clear any existing watchers
539
- watcher.clear();
540
-
541
- // Watch app directory (excluding dist)
542
- if (fsSync.existsSync(APP_DIR)) {
543
- await watcher.watchDirectory(APP_DIR, true);
544
- }
545
-
546
- // Watch src directory (excluding dist)
547
- if (fsSync.existsSync(SRC_DIR)) {
548
- await watcher.watchDirectory(SRC_DIR, true);
549
- }
550
-
551
- // Watch public directory (excluding dist)
552
- if (fsSync.existsSync(PUBLIC_DIR)) {
553
- await watcher.watchDirectory(PUBLIC_DIR, true);
554
- }
555
-
556
- // Watch config files by watching their directory
557
- const configPath = path.join(PROJECT_ROOT, "vaderjs.config.js");
558
- const configPathTs = path.join(PROJECT_ROOT, "vaderjs.config.ts");
559
-
560
- // Watch the project root for config files
561
- await watcher.watchDirectory(PROJECT_ROOT, false);
562
-
563
- const server = serve({
564
- port,
565
- fetch(req, server) {
566
- const url = new URL(req.url);
567
- if (url.pathname === "/__hmr" && server.upgrade(req)) {
568
- return;
569
- }
570
- let filePath = path.join(DIST_DIR, url.pathname);
571
- if (!path.extname(filePath)) {
572
- filePath = path.join(filePath, "index.html");
573
- }
574
- const file = Bun.file(filePath);
575
- return file.exists().then(exists =>
576
- exists ? new Response(file) : new Response("Not Found", { status: 404 })
577
- );
578
- },
579
- websocket: {
580
- open: (ws) => clients.add(ws),
581
- close: (ws) => clients.delete(ws),
582
- },
583
- });
584
-
585
- const rebuild = async (changedFile) => {
586
- try {
587
- watcher.setRebuilding(true);
588
-
589
- logger.info(`Rebuilding due to: ${path.relative(PROJECT_ROOT, changedFile)}`);
590
-
591
- // Reload config if config file changed
592
- if (changedFile.includes('vaderjs.config.')) {
593
- config = await loadConfig();
594
- }
595
-
596
- // Always rebuild when something changes in development
597
- await buildAll(true);
598
-
599
- // Send reload signal to all clients
600
- for (const client of clients) {
601
- client.send("reload");
602
- }
603
-
604
- logger.success("Rebuild complete");
605
- } catch (e) {
606
- logger.error("Rebuild failed:", e);
607
- } finally {
608
- watcher.setRebuilding(false);
609
- }
610
- };
611
-
612
- // Set up file change listener
613
- const removeListener = watcher.onChange((changedFile) => {
614
- rebuild(changedFile);
615
- });
616
-
617
- // Cleanup on exit
618
- const cleanup = () => {
619
- removeListener();
620
- watcher.clear();
621
- server.stop();
622
- process.exit(0);
623
- };
624
-
625
- process.on('SIGINT', cleanup);
626
- process.on('SIGTERM', cleanup);
627
- process.on('exit', cleanup);
628
- }
629
-
630
- async function runProdServer() {
631
- const port = config.port || 3000;
632
- logger.info(`Serving production build from /dist on http://localhost:${port}`);
633
- serve({
634
- port,
635
- fetch(req) {
636
- const url = new URL(req.url);
637
- let filePath = path.join(DIST_DIR, url.pathname);
638
- if (!path.extname(filePath)) {
639
- filePath = path.join(filePath, "index.html");
640
- }
641
- const file = Bun.file(filePath);
642
- return file.exists().then(exists =>
643
- exists ? new Response(file) : new Response("Not Found", { status: 404 })
644
- );
645
- },
646
- });
647
- }
648
-
649
- // --- SCRIPT ENTRYPOINT ---
650
-
651
- async function main() {
652
- const banner = `${colors.magenta}
653
- __ __ ____ ____ _______ __
654
- | | / |/ __ \\ / __ \\ / ____/ |/ /
655
- | | / / / / // /_/ // /___ | /
656
- | | / / /_/ / \\____// /___ / |
657
- |____/____/_____/ /_____/ |_| |_|
658
- ${colors.reset}`;
659
-
660
- console.log(banner);
661
-
662
- const command = process.argv[2];
663
- const arg = process.argv[3];
664
-
665
- try {
666
- // Commands that don't require config
667
- if (command === "init") {
668
- await initProject(arg);
669
- return;
670
- }
671
-
672
- if (command === "add") {
673
- if (!arg) {
674
- logger.error("Please specify a plugin to add.");
675
- process.exit(1);
676
- }
677
- await addPlugin(arg);
678
- return;
679
- }
680
-
681
- // Load config for runtime commands
682
- config = await loadConfig();
683
- config.port ||= 3000;
684
-
685
- switch (command) {
686
- case "add":
687
- if (!arg) {
688
- logger.error("Please specify a plugin to add.");
689
- process.exit(1);
690
- }
691
- await addPlugin(arg);
692
- return;
693
- case "list_plugins":
694
- await listPlugins();
695
- return;
696
- case "remove":
697
- if (!arg) {
698
- logger.error("Please specify a plugin to remove.");
699
- process.exit(1);
700
- }
701
- await removePlugin(arg);
702
- return;
703
-
704
- case "dev":
705
- globalThis.isDev = true;
706
- await runDevServer();
707
- break;
708
-
709
- case "build":
710
- await buildAll(false);
711
- break;
712
-
713
- case "serve":
714
- await buildAll(false);
715
- await runProdServer();
716
- break;
717
-
718
- default:
719
- logger.error(`Unknown command: '${command ?? ""}'`);
720
- logger.info(`
721
- Available commands:
722
- dev Start dev server
723
- build Build for production
724
- serve Build + serve production
725
- init [dir] Create a new Vader project
726
- add <plugin> Add a Vader plugin
727
- remove <plugin> Remove a Vader plugin
728
- list_plugins List currently installed Vaderjs plugins
729
- `.trim());
730
- process.exit(1);
731
- }
732
- } catch (err) {
733
- logger.error("Command failed");
734
- console.error(err);
735
- process.exit(1);
736
- }
737
- }
738
-
739
- main().catch(err => {
740
- logger.error("An unexpected error occurred:", err);
741
- process.exit(1);
742
- });
743
-
744
- process.on("unhandledRejection", (err) => {
745
- logger.error("Unhandled Promise rejection:", err);
746
- });
747
-
748
- process.on("uncaughtException", (err) => {
749
- logger.error("Uncaught Exception:", err);
750
- });