vaderjs 1.6.9 → 1.7.0
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/README.MD +2 -2
- package/bundler/index.js +109 -97
- package/index.ts +181 -73
- package/main.js +41 -39
- package/package.json +1 -1
package/README.MD
CHANGED
|
@@ -20,10 +20,10 @@ export default function(){
|
|
|
20
20
|
return(
|
|
21
21
|
<div>
|
|
22
22
|
<Switch>
|
|
23
|
-
<Match when={count
|
|
23
|
+
<Match when={count > 10}>
|
|
24
24
|
<h1>Count is greater than 10 </h1>
|
|
25
25
|
</Match>
|
|
26
|
-
<Match when={count
|
|
26
|
+
<Match when={count < 10}>
|
|
27
27
|
<h1>Count is less than 10 </h1>
|
|
28
28
|
</Match>
|
|
29
29
|
</Switch>
|
package/bundler/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
Component,
|
|
3
|
+
e,
|
|
4
|
+
useState,
|
|
5
|
+
useEffect,
|
|
6
|
+
useFetch,
|
|
7
|
+
useAsyncState,
|
|
8
|
+
Fragment,
|
|
9
9
|
} from "vaderjs";
|
|
10
10
|
import { document } from "vaderjs/document";
|
|
11
11
|
import fs from "fs";
|
|
@@ -14,10 +14,10 @@ import path from "path";
|
|
|
14
14
|
let path2 = require("path");
|
|
15
15
|
globalThis.Fragment = Fragment;
|
|
16
16
|
globalThis.window = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
location: {
|
|
18
|
+
hash: "",
|
|
19
|
+
host: "",
|
|
20
|
+
},
|
|
21
21
|
};
|
|
22
22
|
globalThis.Component = Component;
|
|
23
23
|
globalThis.e = e;
|
|
@@ -26,87 +26,99 @@ globalThis.useEffect = useEffect;
|
|
|
26
26
|
globalThis.useAsyncState = useAsyncState;
|
|
27
27
|
globalThis.useState = useState;
|
|
28
28
|
globalThis.genKey = () => {
|
|
29
|
-
|
|
29
|
+
return crypto.randomUUID();
|
|
30
30
|
};
|
|
31
31
|
globalThis.document = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
createElement: (tag) => {},
|
|
33
|
+
getElementById: (id) => {},
|
|
34
|
+
querySelector: (query) => {},
|
|
35
35
|
};
|
|
36
36
|
await Bun.build({
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
entrypoints: [process.env.ENTRYPOINT],
|
|
38
|
+
minify: false,
|
|
39
|
+
root: process.cwd() + "/dist/",
|
|
40
|
+
outdir: process.cwd() + "/dist/",
|
|
41
|
+
|
|
42
|
+
format: "esm",
|
|
43
|
+
...(process.env.DEV ? { sourcemap: "inline" } : {}),
|
|
44
|
+
external: ["*.jsx", "*.js", "*.ts"],
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
let builtCode = fs.readFileSync(
|
|
48
|
-
|
|
47
|
+
let builtCode = fs.readFileSync(
|
|
48
|
+
path.join(process.cwd(), "dist", process.env.filePath),
|
|
49
|
+
"utf-8",
|
|
50
|
+
);
|
|
51
|
+
|
|
49
52
|
function handleReplacements(code) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
53
|
+
let lines = code.split("\n");
|
|
54
|
+
let newLines = [];
|
|
55
|
+
for (let line of lines) {
|
|
56
|
+
let hasImport = line.includes("import");
|
|
57
|
+
if (hasImport && line.includes("from") && !newLines.includes(line)) {
|
|
58
|
+
try {
|
|
59
|
+
let url = line.includes("'") ? line.split("'")[1] : line.split('"')[1];
|
|
60
|
+
line = line.replace(
|
|
61
|
+
url,
|
|
62
|
+
url.replace(".jsx", ".js").replace(".tsx", ".js"),
|
|
63
|
+
);
|
|
64
|
+
line = line.replace(
|
|
65
|
+
url,
|
|
66
|
+
url.replace(".ts", ".js").replace(".tsx", ".js"),
|
|
67
|
+
);
|
|
68
|
+
newLines.push(line);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
newLines.push(line);
|
|
66
74
|
}
|
|
67
|
-
|
|
75
|
+
}
|
|
76
|
+
return newLines.join("\n");
|
|
68
77
|
}
|
|
69
|
-
builtCode = handleReplacements(builtCode)
|
|
70
|
-
fs.writeFileSync(
|
|
78
|
+
builtCode = handleReplacements(builtCode);
|
|
79
|
+
fs.writeFileSync(
|
|
80
|
+
path.join(process.cwd(), "dist", process.env.filePath),
|
|
81
|
+
builtCode,
|
|
82
|
+
);
|
|
71
83
|
|
|
72
84
|
let isClass = function (element) {
|
|
73
|
-
|
|
85
|
+
return element.toString().startsWith("class");
|
|
74
86
|
};
|
|
75
87
|
const generatePage = async (
|
|
76
|
-
|
|
88
|
+
data = { path: process.env.INPUT, route: process.env.OUT },
|
|
77
89
|
) => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
const { path, route } = data;
|
|
91
|
+
if (path.includes("root.js")) return;
|
|
92
|
+
let html = await import(path).then((m) => m.default);
|
|
93
|
+
let { head } = await import(path).then((m) => m);
|
|
94
|
+
let isFunction = false;
|
|
95
|
+
globalThis.isServer = true;
|
|
96
|
+
if (isClass(html)) {
|
|
97
|
+
html = new html();
|
|
98
|
+
html.Mounted = true;
|
|
99
|
+
html = html.render();
|
|
100
|
+
} else {
|
|
101
|
+
isFunction = true;
|
|
102
|
+
let instance = new Component();
|
|
103
|
+
html = html.bind(instance);
|
|
104
|
+
instance.render = html;
|
|
105
|
+
html = instance.render();
|
|
106
|
+
}
|
|
95
107
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
let h = document(html);
|
|
109
|
+
if (!fs.existsSync(process.cwd() + "/dist" + path2.dirname(route))) {
|
|
110
|
+
fs.mkdirSync(process.cwd() + "/dist" + path2.dirname(route), {
|
|
111
|
+
recursive: true,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
let headHtml = "";
|
|
115
|
+
if (head) {
|
|
116
|
+
headHtml = document(head());
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
await Bun.write(
|
|
120
|
+
process.cwd() + "/dist/" + route + "/index.html",
|
|
121
|
+
`<!DOCTYPE html>
|
|
110
122
|
<head>
|
|
111
123
|
${headHtml}
|
|
112
124
|
${process.env.bindes}
|
|
@@ -114,29 +126,29 @@ const generatePage = async (
|
|
|
114
126
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
115
127
|
</head>
|
|
116
128
|
${h}
|
|
117
|
-
<script type="module">
|
|
129
|
+
<script type="module">
|
|
118
130
|
import c from '${process.env.filePath}'
|
|
119
131
|
import {render, e} from '/src/vader/index.js'
|
|
120
132
|
window.e = e
|
|
121
133
|
render(c, document.body.firstChild)
|
|
122
134
|
</script>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
`,
|
|
136
|
+
);
|
|
137
|
+
console.log(
|
|
138
|
+
ansiColors.blue(
|
|
139
|
+
`${process.env.filePath.replace(".ts", ".js")} - ${parseInt(
|
|
140
|
+
process.env.size,
|
|
141
|
+
).toFixed(2)}kb`,
|
|
142
|
+
),
|
|
143
|
+
);
|
|
144
|
+
process.exit(0);
|
|
133
145
|
};
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
146
|
+
try {
|
|
147
|
+
if (process.env.isTs == undefined && process.env.isImport) {
|
|
148
|
+
generatePage({ path: process.env.INPUT, route: process.env.OUT });
|
|
149
|
+
} else if (process.env.isTs == undefined) {
|
|
150
|
+
generatePage({ path: process.env.INPUT, route: process.env.OUT });
|
|
151
|
+
}
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.log(ansiColors.red(error));
|
|
154
|
+
}
|
package/index.ts
CHANGED
|
@@ -63,8 +63,8 @@ export const useFetch = (url: string, options: any) => {
|
|
|
63
63
|
export const useAsyncState = (promise: Promise<any>) => {
|
|
64
64
|
return [null, () => {}];
|
|
65
65
|
}
|
|
66
|
-
export const useEffect = (callback:any, dependencies: any[]) => {
|
|
67
|
-
dependencies = dependencies.map((dep) =>
|
|
66
|
+
export const useEffect = (callback:any, dependencies: any[] = []) => {
|
|
67
|
+
dependencies = dependencies.map((dep) => JSON.stringify(dep));
|
|
68
68
|
if (dependencies.length === 0) {
|
|
69
69
|
callback();
|
|
70
70
|
}
|
|
@@ -138,9 +138,12 @@ export const e = (element, props, ...children) => {
|
|
|
138
138
|
instance.Mounted = true;
|
|
139
139
|
let firstEl = instance.render({key: instance.key, children: children, ...props}, children);
|
|
140
140
|
instance.children = children;
|
|
141
|
-
if (!firstEl)
|
|
141
|
+
if (!firstEl) {
|
|
142
|
+
return {type: "div", props: {key: instance.key, ...props}, children: children};
|
|
143
|
+
}
|
|
144
|
+
|
|
142
145
|
firstEl.props = { key: instance.key, ...firstEl.props, ...props };
|
|
143
|
-
return firstEl
|
|
146
|
+
return { type: "ghost", props:{}, children: [firstEl]}
|
|
144
147
|
default:
|
|
145
148
|
return { type: element, props: props || {}, children: children || [] };
|
|
146
149
|
}
|
|
@@ -177,20 +180,15 @@ export function Match({ when, children }) {
|
|
|
177
180
|
* @param key
|
|
178
181
|
* @param initialState
|
|
179
182
|
* @param persist - persist state on reload
|
|
180
|
-
* @returns {
|
|
183
|
+
* @returns {T, (newState: any, Element: string) => void, key}
|
|
181
184
|
*/
|
|
182
185
|
export const useState = <T>(initialState: T, persist: false) => {
|
|
183
186
|
const setState = (newState: T) => {
|
|
184
187
|
initialState = newState;
|
|
185
188
|
}
|
|
186
|
-
/**
|
|
187
|
-
* @returns {T}
|
|
188
|
-
*/
|
|
189
|
-
const getVal = () => {
|
|
190
|
-
return initialState as T;
|
|
191
|
-
}
|
|
192
189
|
|
|
193
|
-
|
|
190
|
+
|
|
191
|
+
return [initialState, setState];
|
|
194
192
|
}
|
|
195
193
|
|
|
196
194
|
if (!isServer) {
|
|
@@ -215,6 +213,19 @@ if (!isServer) {
|
|
|
215
213
|
*
|
|
216
214
|
* render(<App name="John" />, document.getElementById("root"));
|
|
217
215
|
*/
|
|
216
|
+
|
|
217
|
+
// create a hidden object on window
|
|
218
|
+
//
|
|
219
|
+
if(!isServer){
|
|
220
|
+
Object.defineProperty(window, "state", {
|
|
221
|
+
value: [],
|
|
222
|
+
writable: true,
|
|
223
|
+
enumerable: true,
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
}else{
|
|
227
|
+
globalThis.state = []
|
|
228
|
+
}
|
|
218
229
|
export class Component {
|
|
219
230
|
props;
|
|
220
231
|
state;
|
|
@@ -225,17 +236,27 @@ export class Component {
|
|
|
225
236
|
effectCalls: any[]
|
|
226
237
|
eventRegistry: any
|
|
227
238
|
prevState;
|
|
239
|
+
refs: HTMLElement[] | any[]
|
|
240
|
+
state: any[] = []
|
|
228
241
|
constructor() {
|
|
229
242
|
this.key = crypto.randomUUID();
|
|
230
243
|
this.props = {};
|
|
231
|
-
this.state = {};
|
|
232
244
|
this.effect = [];
|
|
233
245
|
this.Mounted = false;
|
|
246
|
+
this.state = [];
|
|
234
247
|
this.element = null;
|
|
235
248
|
this.effectCalls = []
|
|
236
249
|
this.errorThreshold = 1000
|
|
237
250
|
this.maxIntervalCalls = 10
|
|
238
|
-
this.eventRegistry = new
|
|
251
|
+
this.eventRegistry = new WeakMap();
|
|
252
|
+
this.refs = []
|
|
253
|
+
}
|
|
254
|
+
useRef = (key, value) => {
|
|
255
|
+
if(!this.refs.find((r)=> r.key == key)){
|
|
256
|
+
this.refs.push({key, value});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return this.refs.find((r)=> r.key == key).value;
|
|
239
260
|
}
|
|
240
261
|
useEffect(callback, dependencies = []) {
|
|
241
262
|
const callbackId = callback.toString();
|
|
@@ -263,7 +284,10 @@ export class Component {
|
|
|
263
284
|
|
|
264
285
|
setTimeout(() => {
|
|
265
286
|
try {
|
|
266
|
-
|
|
287
|
+
|
|
288
|
+
effects.push(callbackId);
|
|
289
|
+
|
|
290
|
+
callback()
|
|
267
291
|
} catch (error) {
|
|
268
292
|
console.error(error);
|
|
269
293
|
}
|
|
@@ -273,7 +297,6 @@ export class Component {
|
|
|
273
297
|
if (dependencies.length === 0 && this.Mounted && this.effect.length === 0 && !effects.includes(callbackId)){
|
|
274
298
|
executeCallback();
|
|
275
299
|
this.effect.push(callbackId);
|
|
276
|
-
effects.push(callbackId);
|
|
277
300
|
} else {
|
|
278
301
|
// Check if dependencies have changed
|
|
279
302
|
let dependenciesChanged = false;
|
|
@@ -295,53 +318,96 @@ export class Component {
|
|
|
295
318
|
}
|
|
296
319
|
}
|
|
297
320
|
useState(key, defaultValue, persist = false) {
|
|
321
|
+
|
|
298
322
|
if (typeof window === "undefined")
|
|
299
323
|
return [defaultValue, () => {
|
|
300
324
|
}];
|
|
301
|
-
let value = sessionStorage.getItem("state_" + key) ? JSON.parse(sessionStorage.getItem("state_" + key)).value : defaultValue;
|
|
302
325
|
|
|
326
|
+
let value = this.state.find((v) => v.key == key) ? this.state.find((v) => v.key == key).value : defaultValue;
|
|
327
|
+
|
|
328
|
+
if(!this.state.find(i => i.key === key)){
|
|
329
|
+
this.state.push({key: key, value: defaultValue})
|
|
330
|
+
}
|
|
303
331
|
if (typeof value === "string") {
|
|
304
332
|
try {
|
|
305
333
|
value = JSON.parse(value);
|
|
306
334
|
} catch (error) {
|
|
307
335
|
}
|
|
308
336
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
!persist && sessionStorage.removeItem("state_" + key);
|
|
313
|
-
});
|
|
337
|
+
|
|
338
|
+
const clear = () =>{
|
|
339
|
+
this.state = this.state.filter((v) => v.key !== key);
|
|
314
340
|
}
|
|
315
341
|
const setValue = (newValue) => {
|
|
342
|
+
// If newValue is a function, call it with the current value
|
|
316
343
|
if (typeof newValue === "function") {
|
|
317
|
-
|
|
344
|
+
const item = this.state.find(i => i.key === key);
|
|
345
|
+
newValue = item ? newValue(item.value) : newValue;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
let itemIndex = this.state.findIndex(i => i.key === key);
|
|
350
|
+
|
|
351
|
+
if (itemIndex !== -1) {
|
|
352
|
+
this.state[itemIndex].value = newValue;
|
|
353
|
+
} else {
|
|
354
|
+
this.state.push({ key: key, value: newValue });
|
|
318
355
|
}
|
|
319
|
-
|
|
356
|
+
|
|
320
357
|
this.forceUpdate(this.key);
|
|
321
358
|
};
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return [getVal, setValue];
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
return [value, setValue, clear];
|
|
326
362
|
}
|
|
327
363
|
useFetch(url, options) {
|
|
328
364
|
const loadingKey = "loading_" + url;
|
|
329
365
|
const errorKey = "error" + url;
|
|
330
366
|
const dataKey = "_data" + url;
|
|
331
|
-
let [loading, setLoading] = this.useState(loadingKey, true);
|
|
332
|
-
let [error, setError] = this.useState(errorKey, null);
|
|
333
|
-
let [data, setData] = this.useState(dataKey, null);
|
|
334
|
-
if (loading && !error && !data) {
|
|
367
|
+
let [loading, setLoading, _clear1] = this.useState(loadingKey, true);
|
|
368
|
+
let [error, setError, _clear2] = this.useState(errorKey, null);
|
|
369
|
+
let [data, setData, clear] = this.useState(dataKey, null);
|
|
370
|
+
if (loading() && !error() && !data()) {
|
|
335
371
|
fetch(url, options).then((res) => res.json()).then((data2) => {
|
|
336
372
|
setLoading(false);
|
|
337
373
|
setData(data2);
|
|
338
374
|
this.forceUpdate(this.key);
|
|
375
|
+
setTimeout(()=> {
|
|
376
|
+
_clear1()
|
|
377
|
+
_clear2()
|
|
378
|
+
clear()
|
|
379
|
+
}, 1500)
|
|
339
380
|
}).catch((err) => {
|
|
340
381
|
setError(err);
|
|
341
382
|
this.forceUpdate(this.key);
|
|
342
383
|
});
|
|
343
384
|
}
|
|
344
|
-
return
|
|
385
|
+
return { loading, error, data };
|
|
386
|
+
}
|
|
387
|
+
addEventListener(element, event, handler) {
|
|
388
|
+
// Ensure element is tracked
|
|
389
|
+
if (!this.eventRegistry.has(element)) {
|
|
390
|
+
this.eventRegistry.set(element, []);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Check for duplicates
|
|
394
|
+
const registeredEvents = this.eventRegistry.get(element);
|
|
395
|
+
const isDuplicate = registeredEvents.some(
|
|
396
|
+
(e) => e.type === event && e.handler === handler
|
|
397
|
+
);
|
|
398
|
+
if (!isDuplicate) {
|
|
399
|
+
element.addEventListener(event, handler);
|
|
400
|
+
registeredEvents.push({ type: event, handler });
|
|
401
|
+
this.eventRegistry.set(element, registeredEvents);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
removeEventListeners(element) {
|
|
405
|
+
// Unregister and remove all events for the element
|
|
406
|
+
const registeredEvents = this.eventRegistry.get(element) || [];
|
|
407
|
+
registeredEvents.forEach(({ type, handler }) => {
|
|
408
|
+
element.removeEventListener(type, handler);
|
|
409
|
+
});
|
|
410
|
+
this.eventRegistry.delete(element);
|
|
345
411
|
}
|
|
346
412
|
forceUpdate(key) {
|
|
347
413
|
let el = Array.from(document.querySelectorAll("*")).filter((el2) => {
|
|
@@ -354,50 +420,92 @@ export class Component {
|
|
|
354
420
|
this.Reconciler.update(el, newl);
|
|
355
421
|
}
|
|
356
422
|
Reconciler = {
|
|
357
|
-
update:
|
|
423
|
+
update:(oldElement, newElement) => {
|
|
358
424
|
if (!oldElement || !newElement) return;
|
|
359
|
-
|
|
360
|
-
//
|
|
361
|
-
const events = this.eventRegistry.get(oldElement) || [];
|
|
362
|
-
|
|
425
|
+
|
|
426
|
+
// If nodes are the same type and can be updated
|
|
363
427
|
if (this.Reconciler.shouldUpdate(oldElement, newElement)) {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
if (
|
|
367
|
-
oldElement.
|
|
428
|
+
// Update attributes of the parent
|
|
429
|
+
Array.from(oldElement.attributes).forEach(({ name }) => {
|
|
430
|
+
if (!newElement.hasAttribute(name)) {
|
|
431
|
+
oldElement.removeAttribute(name);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
Array.from(newElement.attributes).forEach(({ name, value }) => {
|
|
436
|
+
if (oldElement.getAttribute(name) !== value) {
|
|
437
|
+
oldElement.setAttribute(name, value);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// Update the parent content (if text content differs)
|
|
442
|
+
if (oldElement.childNodes.length === 1 && oldElement.firstChild.nodeType === Node.TEXT_NODE) {
|
|
443
|
+
if (oldElement.textContent !== newElement.textContent) {
|
|
444
|
+
oldElement.textContent = newElement.textContent;
|
|
445
|
+
}
|
|
446
|
+
return; // No children to reconcile if it's a text node
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Reconcile child nodes
|
|
450
|
+
const oldChildren = Array.from(oldElement.childNodes);
|
|
451
|
+
const newChildren = Array.from(newElement.childNodes);
|
|
452
|
+
|
|
453
|
+
const maxLength = Math.max(oldChildren.length, newChildren.length);
|
|
454
|
+
for (let i = 0; i < maxLength; i++) {
|
|
455
|
+
if (i >= oldChildren.length) {
|
|
456
|
+
// Add new children
|
|
457
|
+
const newChildClone = newChildren[i].cloneNode(true);
|
|
458
|
+
oldElement.appendChild(newChildClone);
|
|
459
|
+
|
|
460
|
+
// Transfer events for the new child
|
|
461
|
+
const newChildEvents = this.eventRegistry.get(newChildren[i]) || [];
|
|
462
|
+
newChildEvents.forEach(({ type, handler }) => {
|
|
463
|
+
this.addEventListener(newChildClone, type, handler);
|
|
464
|
+
});
|
|
465
|
+
} else if (i >= newChildren.length) {
|
|
466
|
+
// Remove extra old children
|
|
467
|
+
oldElement.removeChild(oldChildren[i]);
|
|
368
468
|
} else {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
// Swap attributes
|
|
372
|
-
for (let i = 0; i < newElement.attributes.length; i++) {
|
|
373
|
-
let attr = newElement.attributes[i];
|
|
374
|
-
oldElement.setAttribute(attr.name, attr.value);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Re-attach events
|
|
378
|
-
for (const { event, handler } of events) {
|
|
379
|
-
oldElement.addEventListener(event, handler);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// Update children recursively
|
|
383
|
-
for (let i = 0; i < newElement.childNodes.length; i++) {
|
|
384
|
-
this.Reconciler.update(oldElement.childNodes[i], newElement.childNodes[i], true);
|
|
385
|
-
}
|
|
469
|
+
// Update existing children recursively
|
|
470
|
+
this.Reconciler.update(oldChildren[i], newChildren[i]);
|
|
386
471
|
}
|
|
387
|
-
} else if (part.type === "attribute") {
|
|
388
|
-
oldElement.setAttribute(part.name, part.value);
|
|
389
472
|
}
|
|
473
|
+
|
|
474
|
+
// Reapply events to the parent
|
|
475
|
+
const parentEvents = this.eventRegistry.get(newElement) || [];
|
|
476
|
+
parentEvents.forEach(({ type, handler }) => {
|
|
477
|
+
this.addEventListener(oldElement, type, handler);
|
|
478
|
+
});
|
|
390
479
|
} else {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
480
|
+
const oldChildren = Array.from(oldElement.childNodes);
|
|
481
|
+
const newChildren = Array.from(newElement.childNodes);
|
|
482
|
+
|
|
483
|
+
const maxLength = Math.max(oldChildren.length, newChildren.length);
|
|
484
|
+
for (let i = 0; i < maxLength; i++) {
|
|
485
|
+
if (i >= oldChildren.length) {
|
|
486
|
+
// Add new children
|
|
487
|
+
const newChildClone = newChildren[i].cloneNode(true);
|
|
488
|
+
oldElement.appendChild(newChildClone);
|
|
489
|
+
|
|
490
|
+
// Transfer events for the new child
|
|
491
|
+
const newChildEvents = this.eventRegistry.get(newChildren[i]) || [];
|
|
492
|
+
newChildEvents.forEach(({ type, handler }) => {
|
|
493
|
+
this.addEventListener(newChildClone, type, handler);
|
|
494
|
+
});
|
|
495
|
+
} else if (i >= newChildren.length) {
|
|
496
|
+
// Remove extra old children
|
|
497
|
+
oldElement.removeChild(oldChildren[i]);
|
|
498
|
+
} else {
|
|
499
|
+
// Update existing children recursively
|
|
500
|
+
this.Reconciler.update(oldChildren[i], newChildren[i]);
|
|
501
|
+
}
|
|
394
502
|
}
|
|
395
503
|
}
|
|
396
504
|
},
|
|
397
|
-
|
|
505
|
+
|
|
398
506
|
shouldUpdate: (oldElement, newElement, isChild = false) => {
|
|
399
507
|
if (oldElement.nodeType !== newElement.nodeType) {
|
|
400
|
-
return oldElement.innerHTML !== newElement.innerHTML ? { type:
|
|
508
|
+
return oldElement.innerHTML !== newElement.innerHTML ? { type: "innerHTML" } : true;
|
|
401
509
|
}
|
|
402
510
|
if (oldElement.nodeType === 3 && newElement.nodeType === 3) {
|
|
403
511
|
if (oldElement.nodeValue !== newElement.nodeValue) {
|
|
@@ -411,7 +519,7 @@ export class Component {
|
|
|
411
519
|
return true;
|
|
412
520
|
}
|
|
413
521
|
if (newElement.attributes) {
|
|
414
|
-
for (let i = 0;
|
|
522
|
+
for (let i = 0;i < newElement.attributes.length; i++) {
|
|
415
523
|
let attr = newElement.attributes[i];
|
|
416
524
|
if (oldElement.getAttribute(attr.name) !== attr.value) {
|
|
417
525
|
return { type: "attribute", name: attr.name, value: attr.value };
|
|
@@ -428,7 +536,7 @@ export class Component {
|
|
|
428
536
|
let svg = ["svg", "path", "circle", "rect", "line", "polyline", "polygon", "ellipse", "g"];
|
|
429
537
|
let el = svg.includes(element.type) ? document.createElementNS("http://www.w3.org/2000/svg", element.type) : document.createElement(element.type);
|
|
430
538
|
let isText = typeof element === "string" || typeof element === "number" || typeof element === "boolean";
|
|
431
|
-
if (isText)
|
|
539
|
+
if (isText && element){
|
|
432
540
|
el.innerHTML = element;
|
|
433
541
|
} else {
|
|
434
542
|
let attributes = element.props;
|
|
@@ -439,7 +547,7 @@ export class Component {
|
|
|
439
547
|
continue;
|
|
440
548
|
}
|
|
441
549
|
if (key === "className") {
|
|
442
|
-
el.
|
|
550
|
+
el.setAttribute("class", attributes[key]);
|
|
443
551
|
continue;
|
|
444
552
|
}
|
|
445
553
|
if (key === "style") {
|
|
@@ -454,7 +562,8 @@ export class Component {
|
|
|
454
562
|
}
|
|
455
563
|
if (key.startsWith("on")) {
|
|
456
564
|
el.addEventListener(key.substring(2).toLowerCase(), attributes[key]);
|
|
457
|
-
this.eventRegistry.set(el, [...
|
|
565
|
+
this.eventRegistry.set(el, [...this.eventRegistry.get(el) || [], { event: key.substring(2).toLowerCase(), handler: attributes[key] }]);
|
|
566
|
+
this.addEventListener(el,key.substring(2).toLowerCase(), attributes[key])
|
|
458
567
|
continue;
|
|
459
568
|
}
|
|
460
569
|
el.setAttribute(key, attributes[key]);
|
|
@@ -468,8 +577,7 @@ export class Component {
|
|
|
468
577
|
el.appendChild(this.parseToElement(c));
|
|
469
578
|
});
|
|
470
579
|
}
|
|
471
|
-
if (typeof child === "function") {
|
|
472
|
-
console.log("child is function");
|
|
580
|
+
if (typeof child === "function") {
|
|
473
581
|
let comp = memoizeClassComponent(Component);
|
|
474
582
|
comp.Mounted = true;
|
|
475
583
|
comp.render = child;
|
|
@@ -478,7 +586,7 @@ export class Component {
|
|
|
478
586
|
el.appendChild(el2);
|
|
479
587
|
} else if (typeof child === "object") {
|
|
480
588
|
el.appendChild(this.parseToElement(child));
|
|
481
|
-
} else {
|
|
589
|
+
} else if(child){
|
|
482
590
|
let span = document.createTextNode(child)
|
|
483
591
|
el.appendChild(span);
|
|
484
592
|
}
|
package/main.js
CHANGED
|
@@ -110,7 +110,9 @@ const vader = {
|
|
|
110
110
|
const handleReplacements = (code) => {
|
|
111
111
|
let lines = code.split('\n')
|
|
112
112
|
let newLines = []
|
|
113
|
+
let isDefault
|
|
113
114
|
for (let line of lines) {
|
|
115
|
+
|
|
114
116
|
let hasImport = line.includes('import')
|
|
115
117
|
|
|
116
118
|
if (hasImport && line.includes('.css')) {
|
|
@@ -300,7 +302,6 @@ async function generateApp() {
|
|
|
300
302
|
function handleFiles() {
|
|
301
303
|
return new Promise(async (resolve, reject) => {
|
|
302
304
|
try {
|
|
303
|
-
console.log(Glob)
|
|
304
305
|
let glob = new Glob('public/**/*')
|
|
305
306
|
for await (var i of glob.scan()) {
|
|
306
307
|
let file = i
|
|
@@ -311,42 +312,42 @@ function handleFiles() {
|
|
|
311
312
|
fs.copyFileSync(file, path.join(process.cwd() + '/dist', file))
|
|
312
313
|
}
|
|
313
314
|
let glob2 = new Glob('src/**/*')
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
315
|
+
for await (var i of glob2.scan()) {
|
|
316
|
+
var file = i
|
|
317
|
+
fs.mkdirSync(path.join(process.cwd() + '/dist', path.dirname(file)), { recursive: true })
|
|
318
|
+
// turn jsx to js
|
|
319
|
+
if (file.includes('.jsx') || file.includes('.tsx')) {
|
|
320
|
+
let code = await Bun.file(file).text()
|
|
321
|
+
|
|
322
|
+
code = handleReplacements(code)
|
|
323
|
+
|
|
324
|
+
file = file.replace('.jsx', '.js').replace('.tsx', '.js')
|
|
325
|
+
fs.writeFileSync(path.join(process.cwd() + '/dist', file.replace('.jsx', '.js').replace('.tsx', '.js')), code)
|
|
326
|
+
await Bun.spawn({
|
|
327
|
+
cmd: ['bun', 'run', './dev/bundler.js'],
|
|
328
|
+
cwd: process.cwd(),
|
|
329
|
+
stdout: 'inherit',
|
|
330
|
+
env: {
|
|
331
|
+
ENTRYPOINT: path.join(process.cwd() + '/dist/' + file.replace('.jsx', '.js').replace('.tsx', '.js')),
|
|
332
|
+
ROOT: process.cwd() + '/app/',
|
|
333
|
+
OUT: path.dirname(file),
|
|
334
|
+
shouldReplace: true,
|
|
335
|
+
file: process.cwd() + '/dist/' + file.replace('.jsx', '.js').replace('.tsx', '.js'),
|
|
336
|
+
DEV: mode === 'development',
|
|
337
|
+
size: code.length / 1024,
|
|
338
|
+
filePath: file.replace('.jsx', '.js'),
|
|
339
|
+
isTs: false,
|
|
340
|
+
INPUT: path.join(process.cwd(), file.replace('.js', '.jsx').replace('.tsx', '.js')),
|
|
341
|
+
},
|
|
342
|
+
onExit({ exitCode: code }) {
|
|
343
|
+
if (code === 0) {
|
|
344
|
+
resolve()
|
|
345
|
+
} else {
|
|
346
|
+
reject()
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
})
|
|
350
|
+
} else if (file.includes('.ts') || file.includes('.js')) {
|
|
350
351
|
let code = await Bun.file(file).text()
|
|
351
352
|
code = handleReplacements(code)
|
|
352
353
|
file = file.replace('.ts', '.js')
|
|
@@ -361,10 +362,10 @@ function handleFiles() {
|
|
|
361
362
|
OUT: path.dirname(file),
|
|
362
363
|
file: process.cwd() + '/dist/' + file.replace('.ts', '.js'),
|
|
363
364
|
DEV: mode === 'development',
|
|
364
|
-
|
|
365
|
+
isTs: true,
|
|
365
366
|
size: code.length / 1024,
|
|
366
367
|
filePath: file.replace('.ts', '.js'),
|
|
367
|
-
INPUT: path.join(process.cwd(), file.replace('.
|
|
368
|
+
INPUT: path.join(process.cwd(), file.replace('.ts', '.js')),
|
|
368
369
|
},
|
|
369
370
|
onExit({ exitCode: code }) {
|
|
370
371
|
if (code === 0) {
|
|
@@ -399,6 +400,7 @@ if (mode === 'development') {
|
|
|
399
400
|
const handleFileChangeDebounced = async (change, file) => {
|
|
400
401
|
if (file.endsWith('.tsx') || file.endsWith('.jsx') || file.endsWith('.css') || file.endsWith('.ts')
|
|
401
402
|
&& !file.includes('node_module')
|
|
403
|
+
|| file.endsWith('.js') && !file.includes('dist')
|
|
402
404
|
) {
|
|
403
405
|
// delete files cache
|
|
404
406
|
if (file.endsWith('vader.config.ts')){
|