vaderjs 2.3.6 → 2.3.8

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/cli.ts CHANGED
@@ -5,224 +5,262 @@ import fsSync from "fs";
5
5
  import path from "path";
6
6
  import readline from "readline";
7
7
 
8
+ const cwd = process.cwd();
9
+
10
+ /* ---------------------------------- utils --------------------------------- */
11
+
8
12
  function ask(question) {
9
- const rl = readline.createInterface({
10
- input: process.stdin,
11
- output: process.stdout,
12
- });
13
- return new Promise((resolve) =>
14
- rl.question(question + " ", (answer) => {
15
- rl.close();
16
- resolve(answer.trim());
17
- })
18
- );
13
+ const rl = readline.createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout,
16
+ });
17
+ return new Promise((resolve) =>
18
+ rl.question(question + " ", (answer) => {
19
+ rl.close();
20
+ resolve(answer.trim());
21
+ })
22
+ );
19
23
  }
20
24
 
21
- async function run(cmd: string, args: string[] = []) {
22
- try {
23
- const proc = Bun.spawn([cmd, ...args], {
24
- stdout: "inherit",
25
- stderr: "inherit",
26
- });
27
-
28
- const status = await proc.exited;
29
- if (status !== 0) {
30
- console.error(`Command failed: ${cmd} ${args.join(" ")}`);
31
- process.exit(1);
32
- }
33
- } catch (error) {
34
- console.error(`Error executing command: ${error}`);
35
- process.exit(1);
36
- }
25
+ async function run(cmd, args = []) {
26
+ const proc = Bun.spawn([cmd, ...args], {
27
+ stdout: "inherit",
28
+ stderr: "inherit",
29
+ });
30
+
31
+ const status = await proc.exited;
32
+ if (status !== 0) process.exit(status);
37
33
  }
38
34
 
39
- export async function init() {
40
- console.log("🚀 Welcome to Vader.js project initializer!");
35
+ function logSection(title) {
36
+ console.log(`\n${title}`);
37
+ console.log("─".repeat(title.length));
38
+ }
41
39
 
42
- const cwd = process.cwd();
43
- let projectDir = await ask(
44
- `Enter the directory to initialize the project (default: current dir):`
45
- );
46
- if (!projectDir) projectDir = ".";
40
+ function getFlags() {
41
+ return new Set(process.argv.slice(2));
42
+ }
47
43
 
48
- projectDir = path.resolve(cwd, projectDir);
49
- if (!fsSync.existsSync(projectDir)) {
50
- await fs.mkdir(projectDir, { recursive: true });
51
- console.log(`Created directory: ${projectDir}`);
52
- }
44
+ /* ---------------------------------- init ---------------------------------- */
53
45
 
54
- // Confirm Tailwind usage
55
- let useTailwind = await ask("Include TailwindCSS v4 support? (y/n):");
56
- while (!["y", "n", "yes", "no"].includes(useTailwind)) {
57
- useTailwind = await ask("Please answer 'y' or 'n':");
58
- }
59
- const wantsTailwind = useTailwind === "y" || useTailwind === "yes";
60
-
61
- // Create folders: app, src, public
62
- const appDir = path.join(projectDir, "app");
63
- const srcDir = path.join(projectDir, "src");
64
- const publicDir = path.join(projectDir, "public");
65
-
66
- for (const dir of [appDir, srcDir, publicDir]) {
67
- if (!fsSync.existsSync(dir)) {
68
- await fs.mkdir(dir, { recursive: true });
69
- console.log(`Created folder: ${dir}`);
70
- }
46
+ export async function initProject(dir) {
47
+ const flags = getFlags();
48
+ const autoYes = flags.has("--yes");
49
+
50
+ console.log("🚀 Initializing Vader.js project");
51
+
52
+ const projectDir = path.resolve(cwd, dir || ".");
53
+ if (!fsSync.existsSync(projectDir)) {
54
+ await fs.mkdir(projectDir, { recursive: true });
55
+ }
56
+
57
+ const files = fsSync.readdirSync(projectDir);
58
+ if (files.length && !autoYes) {
59
+ const confirm = await ask("Directory is not empty. Continue? (y/n):");
60
+ if (confirm !== "y") process.exit(0);
61
+ }
62
+
63
+ logSection("📁 Creating folders");
64
+
65
+ for (const d of ["app", "public"]) {
66
+ const p = path.join(projectDir, d);
67
+ if (!fsSync.existsSync(p)) {
68
+ await fs.mkdir(p, { recursive: true });
69
+ console.log(`created ${d}/`);
71
70
  }
71
+ }
72
+
73
+ logSection("🧱 Writing files");
74
+
75
+ await fs.writeFile(
76
+ path.join(projectDir, "app/index.jsx"),
77
+ `import { component, useState } from "vaderjs";
72
78
 
73
- // Create example app/index.jsx with counter
74
- const counterCode = wantsTailwind
75
- ? `import { useState } from "vaderjs";
79
+ export default component(() => {
80
+ const [count, setCount] = useState(0);
76
81
 
77
- export default function Counter() {
78
- let [count, setCount] = useState(0);
79
82
  return (
80
- <div class="max-w-md mx-auto p-6 bg-gray-100 rounded shadow text-center">
81
- <h1 class="text-2xl font-bold mb-4">Counter Example</h1>
82
- <p class="text-xl mb-4">Count: {count}</p>
83
- <button
84
- class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
85
- onClick={() => setCount(count + 1)}
86
- >
87
- Increment
88
- </button>
89
- </div>
83
+ <button onClick={() => setCount(c => c + 1)}>
84
+ Count: {count}
85
+ </button>
90
86
  );
91
- }
87
+ });
92
88
  `
93
- : `import { useState } from "vaderjs";
89
+ );
94
90
 
95
- export default function Counter() {
96
- let [count, setCount] = useState(0);
97
- return (
98
- <div style={{ maxWidth: "300px", margin: "auto", padding: "1rem", background: "#eee", borderRadius: "8px", textAlign: "center" }}>
99
- <h1 style={{ fontWeight: "bold", marginBottom: "1rem" }}>Counter Example</h1>
100
- <p style={{ fontSize: "1.25rem", marginBottom: "1rem" }}>Count: {count}</p>
101
- <button onClick={() => setCount(count + 1)}>Increment</button>
102
- </div>
91
+ await fs.writeFile(
92
+ path.join(projectDir, "public/styles.css"),
93
+ `/* Global styles (optional) */`
94
+ );
95
+
96
+ await fs.writeFile(
97
+ path.join(projectDir, "vaderjs.config.ts"),
98
+ `import defineConfig from "vaderjs/config";
99
+
100
+ export default defineConfig({
101
+ port: 3000,
102
+ plugins: [],
103
+ });
104
+ `
103
105
  );
106
+
107
+ if (!fsSync.existsSync(path.join(projectDir, "package.json"))) {
108
+ await fs.writeFile(
109
+ path.join(projectDir, "package.json"),
110
+ JSON.stringify(
111
+ {
112
+ name: path.basename(projectDir),
113
+ private: true,
114
+ scripts: {
115
+ dev: "vaderjs dev",
116
+ build: "vaderjs build",
117
+ start: "vaderjs serve",
118
+ },
119
+ dependencies: {
120
+ vaderjs: "latest",
121
+ },
122
+ },
123
+ null,
124
+ 2
125
+ )
126
+ );
127
+ }
128
+
129
+ logSection("📦 Installing dependencies");
130
+ await run("bun", ["install", "--force"]);
131
+
132
+ console.log("\n✅ Project ready");
133
+ console.log("Run `bun run dev` to start");
104
134
  }
105
- `;
106
135
 
107
- await fs.writeFile(path.join(appDir, "index.jsx"), counterCode);
108
- console.log(`Created example route: ${path.join("app", "index.jsx")}`);
136
+ /* ---------------------------------- add ----------------------------------- */
109
137
 
110
- // Create public/styles.css
111
- if (wantsTailwind) {
112
- await fs.writeFile(path.join(publicDir, "styles.css"), `@import 'tailwindcss';\n`);
113
- } else {
114
- await fs.writeFile(path.join(publicDir, "styles.css"), `/* Add your styles here */\n`);
115
- }
116
- console.log(`Created public/styles.css`);
138
+ export async function addPlugin(name) {
139
+ if (!name) {
140
+ console.error("Please specify a plugin to add.");
141
+ process.exit(1);
142
+ }
117
143
 
118
- // Create minimal package.json if not exist
144
+ const flags = getFlags();
145
+ const force = flags.has("--force");
119
146
 
147
+ const pkgName = name.startsWith("vaderjs-") ? name : `vaderjs-${name}`;
148
+ const importName = pkgName.replace(/^vaderjs-/, "").replace(/-/g, "_");
120
149
 
121
- // Install dependencies: vaderjs + optionally tailwindcss, postcss plugins, autoprefixer
122
- console.log("Installing dependencies with Bun...");
123
- const deps = ["vaderjs", "autoprefixer"];
124
- if (wantsTailwind) {
125
- deps.push("tailwindcss@4", "@tailwindcss/postcss", "postcss-cli");
126
- }
127
- await run("bun", ["install", ...deps]);
128
- console.log("✅ Dependencies installed.");
129
-
130
- // If Tailwind requested, create minimal tailwind.config.cjs and postcss.config.cjs
131
- if (wantsTailwind) {
132
- const tailwindConfig = `module.exports = {
133
- content: ["./app/**/*.{js,jsx,ts,tsx}"],
134
- theme: {
135
- extend: {},
136
- },
137
- plugins: [],
138
- };`;
139
- await fs.writeFile(path.join(projectDir, "tailwind.config.cjs"), tailwindConfig);
140
- console.log("Created tailwind.config.cjs");
141
-
142
- const postcssConfig = `export default {
143
- plugins: {
144
- "@tailwindcss/postcss": {},
145
- autoprefixer: {},
150
+ logSection(`➕ Adding plugin: ${pkgName}`);
151
+
152
+ const args = ["add", pkgName];
153
+ if (force) args.push("--force");
154
+
155
+ await run("bun", args);
156
+
157
+ const configPath = path.join(cwd, "vaderjs.config.ts");
158
+ if (!fsSync.existsSync(configPath)) {
159
+ console.warn("⚠️ vaderjs.config.ts not found, skipping registration");
160
+ return;
146
161
  }
147
- };`;
148
- await fs.writeFile(path.join(projectDir, "postcss.config.cjs"), postcssConfig);
149
- console.log("Created postcss.config.cjs");
150
- }
151
162
 
152
- // Create vaderjs.config.ts regardless, add Tailwind plugin if needed
153
- const vaderConfig = `import defineConfig from "vaderjs/config";
154
- ${wantsTailwind ? 'import tailwind from "vaderjs/plugins/tailwind";' : ''}
155
-
156
- export default defineConfig({
157
- port: 3000,
158
- plugins: [${wantsTailwind ? "tailwind" : ""}],
159
- });`;
160
-
161
- await fs.writeFile(path.join(projectDir, "vaderjs.config.ts"), vaderConfig);
162
- console.log("Created vaderjs.config.ts");
163
-
164
- // Create jsconfig.json for VSCode/IDE support
165
- const jsConfig = {
166
- compilerOptions: {
167
- jsx: "react",
168
- jsxFactory: "Vader.createElement",
169
- jsxFragmentFactory: "Fragment",
170
- },
171
- };
172
- await fs.writeFile(path.join(projectDir, "jsconfig.json"), JSON.stringify(jsConfig, null, 2));
173
- console.log("Created jsconfig.json");
174
-
175
- // Final instructions
176
- const pkgJsonPath = path.join(projectDir, "package.json");
177
-
178
- if (!fsSync.existsSync(pkgJsonPath)) {
179
- // If package.json doesn't exist, create it with basic content
180
- const pkg = {
181
- name: path.basename(projectDir),
182
- version: "1.0.0",
183
- scripts: {
184
- start: "bun run vaderjs build && bun run vaderjs serve",
185
- build: "bun run vaderjs build",
186
- dev: "bun run vaderjs dev",
187
- },
188
- dependencies: {
189
- vaderjs: "latest",
190
- },
191
- };
192
-
193
- // If Tailwind is requested, add it to the dependencies
194
- if (wantsTailwind) {
195
- pkg.dependencies.tailwindcss = "latest";
196
- pkg.dependencies["@tailwindcss/postcss"] = "latest";
197
- pkg.dependencies.postcss = "latest";
198
- pkg.dependencies.autoprefixer = "latest";
199
- }
200
-
201
- await fs.writeFile(pkgJsonPath, JSON.stringify(pkg, null, 2));
202
- console.log(`Created package.json`);
203
- } else {
204
- // If package.json exists, update it by adding Tailwind if it's not there
205
- const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, "utf8"));
206
-
207
- // Only update the dependencies and scripts if Tailwind is enabled
208
- if (wantsTailwind && !pkgJson.dependencies.tailwindcss) {
209
- pkgJson.dependencies.tailwindcss = "latest";
210
- pkgJson.dependencies["@tailwindcss/postcss"] = "latest";
211
- pkgJson.dependencies.postcss = "latest";
212
- pkgJson.dependencies.autoprefixer = "latest";
213
- }
214
-
215
- // Ensure the scripts are in place (if they're not there already)
216
- if (!pkgJson.scripts) pkgJson.scripts = {};
217
- pkgJson.scripts.start = pkgJson.scripts.start || "bun run vaderjs build && bun run vaderjs serve";
218
- pkgJson.scripts.build = pkgJson.scripts.build || "bun run vaderjs build";
219
- pkgJson.scripts.dev = pkgJson.scripts.dev || "bun run vaderjs dev";
220
-
221
- await fs.writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
222
- console.log(`Updated package.json`);
223
- }
163
+ let config = await fs.readFile(configPath, "utf8");
164
+
165
+ if (config.includes(`from "${pkgName}"`)) {
166
+ console.log("ℹ️ Plugin already registered");
167
+ return;
168
+ }
169
+
170
+ config =
171
+ `import ${importName} from "${pkgName}";\n` +
172
+ config.replace(/plugins:\s*\[/, `plugins: [${importName}, `);
173
+
174
+ await fs.writeFile(configPath, config);
175
+ console.log("✔ Plugin registered");
176
+ }
177
+
178
+ /* -------------------------------- remove ---------------------------------- */
179
+
180
+ export async function removePlugin(name) {
181
+ if (!name) {
182
+ console.error("Please specify a plugin to remove.");
183
+ process.exit(1);
184
+ }
185
+
186
+ const pkgName = name.startsWith("vaderjs-") ? name : `vaderjs-${name}`;
187
+ const importName = pkgName.replace(/^vaderjs-/, "").replace(/-/g, "_");
188
+
189
+ logSection(`➖ Removing plugin: ${pkgName}`);
190
+
191
+ await run("bun", ["remove", pkgName]);
192
+
193
+ const configPath = path.join(cwd, "vaderjs.config.ts");
194
+ if (!fsSync.existsSync(configPath)) return;
195
+
196
+ let config = await fs.readFile(configPath, "utf8");
197
+
198
+ config = config
199
+ .replace(new RegExp(`import ${importName} from ".*?";\\n?`, "g"), "")
200
+ .replace(new RegExp(`\\b${importName},?\\s*`, "g"), "");
201
+
202
+ await fs.writeFile(configPath, config);
203
+ console.log("✔ Plugin removed");
204
+ }
205
+
206
+ /* ---------------------------------- list ---------------------------------- */
207
+
208
+ export async function listPlugins() {
209
+ const pkgPath = path.join(cwd, "package.json");
210
+ if (!fsSync.existsSync(pkgPath)) {
211
+ console.log("No package.json found.");
212
+ return;
213
+ }
214
+
215
+ const pkg = JSON.parse(await fs.readFile(pkgPath, "utf8"));
216
+ const deps = Object.keys(pkg.dependencies || {}).filter((d) =>
217
+ d.startsWith("vaderjs-")
218
+ );
219
+
220
+ if (!deps.length) {
221
+ console.log("No Vader plugins installed.");
222
+ return;
223
+ }
224
+
225
+ logSection("🔌 Installed Vader plugins");
226
+ deps.forEach((d) => console.log("•", d));
227
+ }
228
+
229
+ /* ---------------------------------- cli ----------------------------------- */
230
+
231
+ const [, , command, arg] = process.argv;
232
+
233
+ switch (command) {
234
+ case "init":
235
+ await initProject(arg);
236
+ break;
237
+
238
+ case "add":
239
+ await addPlugin(arg);
240
+ break;
241
+
242
+ case "remove":
243
+ await removePlugin(arg);
244
+ break;
245
+
246
+ case "list":
247
+ await listPlugins();
248
+ break;
249
+
250
+ default:
251
+ console.log(`
252
+ Vader CLI
253
+
254
+ Commands:
255
+ vader init [dir] [--yes]
256
+ vader add <plugin> [--force]
257
+ vader remove <plugin>
258
+ vader list
224
259
 
225
- console.log(`\n🎉 Vader.js project initialized at:\n${projectDir}`);
226
- console.log(`Run cd ${projectDir} to navigate into the project folder`);
227
- console.log("Run `bun run dev` or your build script to get started.");
260
+ Examples:
261
+ vader init my-app --yes
262
+ vader add bootstrap
263
+ vader remove bootstrap
264
+ vader list
265
+ `);
228
266
  }
package/index.ts CHANGED
@@ -104,9 +104,16 @@ function createDom(fiber: Fiber): Node {
104
104
  }
105
105
 
106
106
  updateDom(dom, {}, fiber.props);
107
+
108
+ // Assign ref if this fiber has a ref prop
109
+ if (fiber.props && fiber.props.ref) {
110
+ fiber.props.ref.current = dom;
111
+ }
112
+
107
113
  return dom;
108
114
  }
109
115
 
116
+
110
117
  function isSvgElement(fiber: Fiber): boolean {
111
118
  // Check if the fiber is an <svg> itself or inside an <svg>
112
119
  let parent = fiber.parent;
@@ -126,11 +133,19 @@ function isSvgElement(fiber: Fiber): boolean {
126
133
  * @param {object} nextProps - The new properties.
127
134
  */
128
135
  function updateDom(dom: Node, prevProps: any, nextProps: any): void {
129
- prevProps = prevProps || {};
136
+ prevProps = prevProps || {};
130
137
  nextProps = nextProps || {};
131
138
 
132
139
  const isSvg = dom instanceof SVGElement;
133
140
 
141
+ // Handle ref updates
142
+ if (prevProps.ref && prevProps.ref !== nextProps.ref) {
143
+ prevProps.ref.current = null;
144
+ }
145
+ if (nextProps.ref && nextProps.ref !== prevProps.ref) {
146
+ nextProps.ref.current = dom;
147
+ }
148
+
134
149
  // Remove old or changed event listeners
135
150
  Object.keys(prevProps)
136
151
  .filter(isEvent)
@@ -231,18 +246,31 @@ function commitRoot(): void {
231
246
  * @param {Fiber} fiber - The fiber to commit.
232
247
  */
233
248
  function commitWork(fiber: Fiber | null): void {
234
- if (!fiber) {
235
- return;
236
- }
249
+ if (!fiber) return;
237
250
 
238
251
  let domParentFiber = fiber.parent;
239
252
  while (domParentFiber && !domParentFiber.dom) {
240
253
  domParentFiber = domParentFiber.parent;
241
254
  }
242
- const domParent = domParentFiber ? domParentFiber.dom : null;
255
+ const domParent = domParentFiber?.dom ?? null;
243
256
 
244
257
  if (fiber.effectTag === "PLACEMENT" && fiber.dom != null) {
245
258
  if (domParent) domParent.appendChild(fiber.dom);
259
+
260
+ // ⚡ Assign refs immediately when DOM is placed
261
+ if (fiber.props && fiber.props.ref) {
262
+ fiber.props.ref.current = fiber.dom;
263
+ }
264
+
265
+ // Also check for useRef hooks in this fiber
266
+ if (fiber.hooks) {
267
+ for (const hook of fiber.hooks) {
268
+ if ("current" in hook && !hook._isRef && fiber.dom) {
269
+ // This is likely a DOM ref hook
270
+ hook.current = fiber.dom;
271
+ }
272
+ }
273
+ }
246
274
  } else if (fiber.effectTag === "UPDATE" && fiber.dom != null) {
247
275
  updateDom(fiber.dom, fiber.alternate?.props ?? {}, fiber.props);
248
276
  } else if (fiber.effectTag === "DELETION") {
@@ -253,14 +281,21 @@ function commitWork(fiber: Fiber | null): void {
253
281
  commitWork(fiber.sibling);
254
282
  }
255
283
 
284
+
256
285
  /**
257
286
  * Recursively removes a fiber and its children from the DOM.
258
287
  * @param {Fiber} fiber - The fiber to remove.
259
288
  */
260
- function commitDeletion(fiber: Fiber | null): void {
289
+ function commitDeletion(fiber: Fiber | null): void {
261
290
  if (!fiber) {
262
291
  return;
263
292
  }
293
+
294
+ // Clear refs when element is removed
295
+ if (fiber.props && fiber.props.ref) {
296
+ fiber.props.ref.current = null;
297
+ }
298
+
264
299
  if (fiber.dom) {
265
300
  if (fiber.dom.parentNode) {
266
301
  fiber.dom.parentNode.removeChild(fiber.dom);
@@ -641,7 +676,7 @@ export function useRef<T>(initial: T): { current: T } {
641
676
 
642
677
  let hook = wipFiber.hooks[hookIndex];
643
678
  if (!hook) {
644
- hook = { current: initial };
679
+ hook = { current: initial, _isRef: true };
645
680
  wipFiber.hooks[hookIndex] = hook;
646
681
  }
647
682
 
package/main.js CHANGED
@@ -5,7 +5,7 @@ import { build, serve } from "bun";
5
5
  import fs from "fs/promises";
6
6
  import fsSync from "fs";
7
7
  import path from "path";
8
- import { init } from "./cli";
8
+ import { initProject, addPlugin, listPlugins, removePlugin} from "./cli";
9
9
 
10
10
  // --- UTILITIES for a Sleek CLI ---
11
11
 
@@ -403,6 +403,7 @@ async function copyPublicAssets() {
403
403
  }
404
404
 
405
405
  async function runDevServer() {
406
+ // Initial build
406
407
  await buildAll(true);
407
408
 
408
409
  const clients = new Set();
@@ -432,9 +433,14 @@ async function runDevServer() {
432
433
  },
433
434
  });
434
435
 
435
- const debouncedBuild = debounce(async () => {
436
+ const debouncedBuild = debounce(async (event, filename) => {
437
+ logger.info(`File change detected: ${filename || 'unknown'}`);
436
438
  try {
439
+ // Reload config in case plugins or ports changed
440
+ config = await loadConfig();
441
+
437
442
  await buildAll(true);
443
+
438
444
  for (const client of clients) {
439
445
  client.send("reload");
440
446
  }
@@ -443,12 +449,24 @@ async function runDevServer() {
443
449
  }
444
450
  }, 200);
445
451
 
446
- const watchDirs = [APP_DIR, SRC_DIR, PUBLIC_DIR].filter(fsSync.existsSync);
447
- for (const dir of watchDirs) {
448
- safeWatch(dir, debouncedBuild);
452
+ // --- IMPROVED WATCHER ---
453
+ const configPath = path.join(PROJECT_ROOT, "vaderjs.config.js");
454
+ const configPathTs = path.join(PROJECT_ROOT, "vaderjs.config.ts");
455
+
456
+ const watchTargets = [
457
+ APP_DIR,
458
+ SRC_DIR,
459
+ PUBLIC_DIR,
460
+ configPath,
461
+ configPathTs
462
+ ].filter(p => fsSync.existsSync(p));
463
+
464
+ logger.info(`Watching for changes in: ${watchTargets.map(p => path.basename(p)).join(", ")}`);
465
+
466
+ for (const target of watchTargets) {
467
+ safeWatch(target, debouncedBuild);
449
468
  }
450
469
  }
451
-
452
470
  async function runProdServer() {
453
471
  const port = config.port || 3000;
454
472
  logger.info(`Serving production build from /dist on http://localhost:${port}`);
@@ -481,42 +499,92 @@ function debounce(fn, delay) {
481
499
  async function main() {
482
500
  const banner = `${colors.magenta}
483
501
  __ __ ____ ____ _______ __
484
- | | / |/ __ \ / __ \ / ____/ |/ /
502
+ | | / |/ __ \\ / __ \\ / ____/ |/ /
485
503
  | | / / / / // /_/ // /___ | /
486
- | | / / /_/ / \____// /___ / |
504
+ | | / / /_/ / \\____// /___ / |
487
505
  |____/____/_____/ /_____/ |_| |_|
488
506
  ${colors.reset}`;
489
507
 
490
- console.log(banner);
491
-
492
-
493
- config = await loadConfig();
494
- config.port = config.port || 3000;
508
+ console.log(banner);
495
509
 
496
510
  const command = process.argv[2];
511
+ const arg = process.argv[3];
497
512
 
498
- if (command === "dev") {
499
- globalThis.isDev = true
500
- await runDevServer();
501
- } else if (command === "build") {
502
- await buildAll(false);
503
- } else if (command === "serve") {
504
- await buildAll(false);
505
- await runProdServer();
506
- }
507
- else if(command === "init"){
508
- init().catch((e) => {
509
- console.error("Initialization failed:", e);
510
- process.exit(1);
511
- });
513
+ try {
514
+ // Commands that don't require config
515
+ if (command === "init") {
516
+ await initProject(arg);
517
+ return;
518
+ }
519
+
520
+ if (command === "add") {
521
+ if (!arg) {
522
+ logger.error("Please specify a plugin to add.");
523
+ process.exit(1);
524
+ }
525
+ await addPlugin(arg)
526
+ return;
527
+ }
528
+
529
+ // Load config for runtime commands
530
+ const config = await loadConfig();
531
+ config.port ||= 3000;
512
532
 
513
- } else {
514
- logger.error(`Unknown command: '${command}'.`);
515
- logger.info("Available commands: 'dev', 'build', 'serve'");
533
+ switch (command) {
534
+ case "add":
535
+ if (!arg) {
536
+ logger.error("Please specify a plugin to add.");
537
+ process.exit(1);
538
+ }
539
+ await addPlugin(arg)
540
+ return;
541
+ case "list_plugins":
542
+ await listPlugins()
543
+ return
544
+ case "remove":
545
+ if (!arg) {
546
+ logger.error("Please specify a plugin to remove.");
547
+ process.exit(1);
548
+ }
549
+ await removePlugin(arg)
550
+ return
551
+
552
+ case "dev":
553
+ globalThis.isDev = true;
554
+ await runDevServer();
555
+ break;
556
+
557
+ case "build":
558
+ await buildAll(false);
559
+ break;
560
+
561
+ case "serve":
562
+ await buildAll(false);
563
+ await runProdServer();
564
+ break;
565
+
566
+ default:
567
+ logger.error(`Unknown command: '${command ?? ""}'`);
568
+ logger.info(`
569
+ Available commands:
570
+ dev Start dev server
571
+ build Build for production
572
+ serve Build + serve production
573
+ init [dir] Create a new Vader project
574
+ add <plugin> Add a Vader plugin
575
+ remove <plugin> Remove a Vader plugin
576
+ list_plugins List currently installed Vaderjs plugins
577
+ `.trim());
578
+ process.exit(1);
579
+ }
580
+ } catch (err) {
581
+ logger.error("Command failed");
582
+ console.error(err);
516
583
  process.exit(1);
517
584
  }
518
585
  }
519
586
 
587
+
520
588
  main().catch(err => {
521
589
  logger.error("An unexpected error occurred:", err);
522
590
  process.exit(1);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vaderjs",
3
- "version": "2.3.6",
4
- "description": "A simple and powerful JavaScript library for building modern web applications.",
3
+ "version": "2.3.8",
4
+ "description": "A simple and powerful JavaScript library for building modern web applications.",
5
5
  "bin": {
6
6
  "vaderjs": "./main.js"
7
7
  },
@@ -9,7 +9,7 @@
9
9
  "type": "git",
10
10
  "url": "https://github.com/Postr-Inc/Vader.js"
11
11
  },
12
- "license":"MIT",
12
+ "license": "MIT",
13
13
  "dependencies": {
14
14
  "ansi-colors": "latest"
15
15
  }
@@ -1,53 +0,0 @@
1
- //@ts-nocheck
2
- import fs from 'fs'
3
- import path from 'path'
4
-
5
- import type { VaderPlugin, VaderAPI } from "vaderjs/plugins";
6
- function checkIfTailwindInstalled() {
7
- try {
8
- //@ts-ignore
9
- require.resolve('tailwindcss')
10
- require.resolve('postcss')
11
- return true
12
- } catch (e) {
13
- return false
14
- }
15
- }
16
-
17
- function initTailwind() {
18
- const postcssConfig = path.resolve(process.cwd(), 'postcss.config.mjs')
19
- const tailwindCssFile = path.join(process.cwd(), '/public/styles.css')
20
- if(!fs.existsSync(tailwindCssFile)){
21
- fs.writeFileSync(tailwindCssFile, `@import "tailwindcss"`)
22
- }
23
- if (!fs.existsSync(postcssConfig)) {
24
- fs.writeFileSync(postcssConfig, `export default { plugins: { "@tailwindcss/postcss": {}, }}`)
25
-
26
- }
27
-
28
- }
29
-
30
-
31
- export default {
32
- name: 'tailwindcss',
33
- description: 'TailwindCSS plugin for Vader.js',
34
- version: '0.0.2',
35
- onBuildStart: async (vader) => {
36
- if (!checkIfTailwindInstalled()) {
37
- console.error('TailwindCSS is not installed. Please install it using `bun install tailwindcss @tailwindcss/postcss postcss-cli`\n more info: https://tailwindcss.com/docs/installation/using-postcss`')
38
- process.exit(1)
39
- }else{
40
- initTailwind()
41
- console.log('Building TailwindCSS...')
42
- await vader.runCommand(['bun', 'run', 'postcss', './public/styles.css', '-o', 'dist/public/tailwind.css'])
43
- vader.injectHTML(`<link rel="stylesheet" href="/public/tailwind.css">`)
44
-
45
- }
46
-
47
- return
48
- },
49
- onBuildFinish: async (vader) => {
50
- console.log('TailwindCSS plugin finished building')
51
- },
52
-
53
- }