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 +233 -195
- package/index.ts +42 -7
- package/main.js +98 -30
- package/package.json +3 -3
- package/plugins/tailwind.ts +0 -53
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
40
|
-
|
|
35
|
+
function logSection(title) {
|
|
36
|
+
console.log(`\n${title}`);
|
|
37
|
+
console.log("─".repeat(title.length));
|
|
38
|
+
}
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
);
|
|
46
|
-
if (!projectDir) projectDir = ".";
|
|
40
|
+
function getFlags() {
|
|
41
|
+
return new Set(process.argv.slice(2));
|
|
42
|
+
}
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
if (!fsSync.existsSync(projectDir)) {
|
|
50
|
-
await fs.mkdir(projectDir, { recursive: true });
|
|
51
|
-
console.log(`Created directory: ${projectDir}`);
|
|
52
|
-
}
|
|
44
|
+
/* ---------------------------------- init ---------------------------------- */
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
74
|
-
|
|
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
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
89
|
+
);
|
|
94
90
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
108
|
-
console.log(`Created example route: ${path.join("app", "index.jsx")}`);
|
|
136
|
+
/* ---------------------------------- add ----------------------------------- */
|
|
109
137
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
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
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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.
|
|
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
|
}
|
package/plugins/tailwind.ts
DELETED
|
@@ -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
|
-
}
|