vaderjs 1.3.3-alpha-18 → 1.3.3-alpha-20

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 CHANGED
@@ -94,9 +94,10 @@ return {default:Home}
94
94
 
95
95
 
96
96
  ### State Management
97
+ Vaderjs uses partial hydration which is much better than react vdom, simply pass the ref key to state and only that element will update - no vdom required!!
97
98
 
98
99
  ```jsx
99
- let {Component, useState} = await import('vaderjs/client')
100
+ let {Component, useState, useRef} = await import('vaderjs/client')
100
101
 
101
102
  class MyApp extends Component{
102
103
  contructor(){
@@ -106,12 +107,16 @@ class MyApp extends Component{
106
107
 
107
108
  render(){
108
109
  let [count, setCount] = useState(0)
109
- function increment(){
110
- setCount(count()+ 1)
111
- }
110
+ let ref = useRef('')
111
+
112
112
  return <>
113
- <p>Count is ${count}</p>
114
- <button onclick={()=>increment()}>Increment</button>
113
+ <p ref={ref.bind}>Count is ${count}</p>
114
+ ${/**
115
+ pass anything used from the toplevel render to the lowerlevel function params to be able to invoke!
116
+ **/}
117
+ <button onclick={(setCount, count, ref)=>{
118
+ setCount(count + 1, ref.bind)
119
+ }}>Increment</button>
115
120
  </>
116
121
 
117
122
  }
@@ -124,6 +129,7 @@ return {default:MyApp}
124
129
  ### Function Binding
125
130
 
126
131
  Vaderjs allows you to bind functions directly to html elements just like react
132
+ there are two ways - top level invokes like below
127
133
 
128
134
  ```javascript
129
135
  // vader uses params[0] as the event target object and other parameters resolve after
@@ -141,8 +147,18 @@ return <>
141
147
  </>
142
148
  ```
143
149
 
144
-
145
-
150
+ and lower level invokes - these operate the same just allow you to pass items from top level to lower level: ex - I have a variable named car and i want the button to log it i can pass it as a parameter to allow it to be added to the buttons function scope
151
+
152
+ ```jsx
153
+ let car = {
154
+ model: 'tesla',
155
+ price: 'toomiuch'
156
+ }
157
+ return <>
158
+ <button onclick={(car)=>{
159
+ console.log(car.model)
160
+ }}>Log</button>
161
+ ```
146
162
 
147
163
 
148
164
 
package/client/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  window.params = {};
3
3
  window.Vader = {
4
- version: "1.3.2",
4
+ version: "1.3.3",
5
5
  };
6
6
 
7
7
  let errors = {
@@ -43,16 +43,13 @@ let hasran = [];
43
43
  let states = {};
44
44
  let mounts = [];
45
45
  export const strictMount = (key, callback) => {
46
- let interval = setInterval(() => {
47
- if(mounts.find(mount => mount.key === key)
48
- && !hasran.includes(callback.toString())
49
- ){
46
+ let timer = setInterval(() => {
47
+ if (document.querySelector('[key="' + key + '"]')) {
48
+ console.log('mounted')
49
+ clearInterval(timer);
50
50
  callback();
51
- clearInterval(interval)
52
-
53
- hasran.push(callback.toString());
54
- }
55
- },0);
51
+ }
52
+ }, 120);
56
53
  };
57
54
 
58
55
  window.delegate = (event) => {
@@ -167,9 +164,93 @@ export class Component {
167
164
  window.listeners = [];
168
165
  this.functionMap = new Map();
169
166
  this.freeMemoryFromFunctions();
167
+ this.checkIFMounted();
170
168
  this.memoizes = []
169
+
170
+ this.vdom = []
171
+
171
172
  this.children = []
173
+ let dom = new DOMParser().parseFromString(this.render(), 'text/html').body.firstChild;
174
+ dom.querySelectorAll('*').forEach((el) => {
175
+ let obj = {
176
+ el: el,
177
+ tag: el.tagName,
178
+ html: el.innerHTML,
179
+ content: el.textContent,
180
+ value: el.value,
181
+ attributes: el.attributes,
182
+ children: el.childNodes,
183
+ }
184
+ this.vdom.push(obj)
185
+ });
186
+
187
+ /**
188
+ * Parent of the current component.
189
+ * @type {Component}
190
+ */
191
+ this.parentNode = {}
192
+
193
+ /**
194
+ * Request object.
195
+ */
196
+ this.request = {
197
+ /**
198
+ * @type {string}
199
+ * @description The headers for the current route
200
+ */
201
+ headers:{},
202
+ /**
203
+ * @type {string}
204
+ * @description The method for the current route
205
+ */
206
+ method: "GET",
207
+ /**
208
+ * @type {string}
209
+ * @description params for the given route /:id/:name etc
210
+ */
211
+ params: {},
212
+ /**
213
+ * @type {string}
214
+ * @description path: current route path
215
+ */
216
+ path: "",
217
+ /**
218
+ * @type {string}
219
+ * @description query: query object for the current route ?name=hello -> {name: 'hello'}
220
+ */
221
+ query: {},
222
+ },
223
+ /**
224
+ * @type {string}
225
+ * @description The response object for the current route
226
+ */
227
+ this.response = {
228
+ /**
229
+ * @method json
230
+ * @description This method allows you to send json data to the client
231
+ * @param {*} data
232
+ */
233
+ json: (data) => {},
234
+ /**
235
+ * @method send
236
+ * @description This method allows you to send text data to the client
237
+ * @param {*} data
238
+ */
239
+ send: (data) => {},
240
+ /**
241
+ * @method redirect
242
+ * @description This method allows you to redirect the client to a new route
243
+ * @param {*} path
244
+ */
245
+ redirect: (path) => {},
246
+ /**
247
+ * @method render
248
+ * @description render a new component to the client
249
+ * @param {*} Component
250
+ */
251
+ render: async (Component) => {},
172
252
  }
253
+ }
173
254
 
174
255
  createComponent(/**@type {Component}**/component, props, children) {
175
256
 
@@ -179,26 +260,16 @@ export class Component {
179
260
  if(!props.key){
180
261
  throw new Error('new components must have a key')
181
262
  }
182
- let comp = new component();
183
- Object.keys(props).forEach((key) => {
184
- // some props are this.bind inside of "" so we need to handle that
185
- let newFunc = props[key].match(/this.bind\((.*)\)/gs);
186
- if (newFunc) {
187
- newFunc = newFunc[0].replace(/this.bind\((.*)\)/gs, "$1");
188
- newFunc = newFunc.split('`')[1]
189
- props[key] = this.bind(newFunc, { jsx: true, params: props[key], ref: props.ref });
190
- return
191
- }
192
-
193
-
194
-
195
- props[key] = props[key].toString().replace('"', '').replace("'", '').replace('${', '').replace('}', '')
196
- });
263
+ let comp = new component(props);
264
+ if(this.components[props.key]){
265
+ return this.components[props.key]
266
+ }
197
267
  comp['props'] = props;
198
268
  comp.children = children;
199
269
  comp.props.children = children.join('')
200
270
  comp.parentNode = this;
201
271
  comp.key = props.key || null;
272
+
202
273
  this.components[props.key] = comp
203
274
  this.children.push(comp)
204
275
  return this.components[props.key]
@@ -215,6 +286,7 @@ export class Component {
215
286
  }
216
287
 
217
288
  let comp = this.components[component.key];
289
+
218
290
  let h = comp.render()
219
291
 
220
292
  if(h && h.split('>,').length > 1){
@@ -240,28 +312,75 @@ export class Component {
240
312
  * Hydrates the component by updating the HTML content if it has changed.
241
313
  * @private
242
314
  */
243
- hydrate() {
244
- if (this.key) {
245
-
246
- const el = document.querySelector(`[key="${this.key}"]`);
247
315
 
248
-
249
- if (el) {
250
-
251
-
252
- // Render the new HTML content
253
- const newHtml = this.render();
254
- // Compare the new HTML with the cached content
255
- if (newHtml !== this.currentHtml) {
256
- // Update the HTML only if it has changed
257
- el.innerHTML = newHtml;
258
-
259
- // Update the cached HTML content
260
- this.currentHtml = newHtml;
316
+ domDifference(oldDom, newDom) {
317
+ let diff = [];
318
+
319
+ for (let i = 0; i < oldDom.length; i++) {
320
+ let oldEl = oldDom[i];
321
+ let newEl = newDom[i];
322
+
323
+ if (oldEl && newEl && !oldEl.isEqualNode(newEl)) {
324
+ diff.push({
325
+ type: 'replace',
326
+ old: oldEl,
327
+ new: newEl.cloneNode(true),
328
+ });
329
+ }
330
+ }
331
+
332
+ return diff;
333
+ }
334
+
335
+ updateChangedElements(diff) {
336
+ diff.forEach((change) => {
337
+ switch (change.type) {
338
+ case 'replace':
339
+ change.old.parentNode.replaceChild(change.new, change.old);
340
+ break;
341
+ case 'remove':
342
+ change.old.remove();
343
+ break;
344
+ case 'add':
345
+ change.old.appendChild(change.new.cloneNode(true));
346
+ break;
347
+ default:
348
+ break;
349
+ }
350
+ });
351
+ }
352
+
353
+ hydrate(hook) {
354
+ if (this.key) {
355
+ if (hook) {
356
+ let newDom = new DOMParser().parseFromString(this.render(), 'text/html').body.firstChild;
357
+
358
+ let oldElements = document.body.querySelectorAll(`[ref="${hook}"]`);
359
+ let newElements = newDom.querySelectorAll(`[ref="${hook}"]`);
360
+ let diff = this.domDifference(oldElements, newElements);
361
+ this.updateChangedElements(diff);
362
+ } else {
363
+ const targetElement = document.querySelector(`[key="${this.key}"]`);
364
+ if (targetElement) {
365
+ targetElement.innerHTML = this.render();
366
+ } else {
367
+ console.error('Target element not found.');
261
368
  }
262
369
  }
263
370
  }
264
371
  }
372
+
373
+
374
+
375
+ patch(oldElements, newElements) {
376
+ const diff = this.domDifference(oldElements, newElements);
377
+
378
+ this.updateChangedElements(diff);
379
+ }
380
+
381
+
382
+
383
+
265
384
 
266
385
  /**
267
386
  * Handles an object by parsing it as JSON and evaluating it.
@@ -279,7 +398,7 @@ export class Component {
279
398
  }
280
399
 
281
400
  /**
282
- * Frees memory from functions that have not been used for a certain period of time.
401
+ * Frees memory from functions that have not been used for a certain period of time.c
283
402
  * @private
284
403
  */
285
404
  freeMemoryFromFunctions() {
@@ -299,23 +418,47 @@ export class Component {
299
418
  * @param {string} ref - The reference.
300
419
  * @returns {string} - A valid inline JS function call.
301
420
  */
302
- bind(funcData, d) {
421
+ bind(funcData,jsx,ref, paramNames, ...params) {
422
+
303
423
 
304
424
  const name = `func_${crypto ? crypto.getRandomValues(new Uint32Array(1))[0] : Math.random()}`;
305
425
 
306
- var dynamicFunction = (params) => {
307
- let func = new Function(`return (async () => {
308
- ${funcData}
309
- })()`);
310
- func = func.bind(this);
311
- func(params);
426
+ var dynamicFunction = async (...params) => {
427
+
428
+ // Replace double commas with a single comma
429
+
430
+
431
+ // Turn params into a destructured object
432
+ let paramObject = {};
433
+ params = params[0]
434
+
435
+ paramNames = paramNames.replace(/,,/g, ',');
436
+ let newparamnames = paramNames.replaceAll(',,', ',')
437
+ // Remove trailing commas
438
+ paramNames.endsWith(',') ? paramNames = paramNames.slice(0, -1) : null;
439
+ console.log(paramNames)
440
+
441
+ params.forEach((param, index) => {
442
+ paramObject[newparamnames.split(',')[index]] = param;
443
+ });
444
+
445
+ paramNames = paramNames.replace(',,', ',');
446
+ let func = new Function(`${paramNames}`, `
447
+ return (async (${paramNames}) => {
448
+ ${funcData}
449
+ })(${Object.keys(paramObject).join(',')})
450
+ `);
451
+
452
+ // Bind and execute the function with the provided parameters
453
+ await func.bind(this)(...Object.values(paramObject));
312
454
  };
455
+
313
456
 
314
457
  dynamicFunction = dynamicFunction.bind(this);
315
458
  if (!this.functionMap.has(name)) {
316
459
  document.addEventListener(`call_${name}`, (e) => {
317
460
 
318
- dynamicFunction();
461
+ dynamicFunction(params);
319
462
  this.functionMap.set(e.detail.name, {
320
463
  lastUsed: Date.now(),
321
464
  });
@@ -335,15 +478,17 @@ export class Component {
335
478
  };
336
479
 
337
480
  // Return a valid inline js function call
338
- return d.jsx ? dynamicFunction : `
481
+ return jsx ? dynamicFunction : `
339
482
  ((event) => {
340
- event.target.setAttribute('data-ref', '${d.ref}');
483
+ event.target.setAttribute('data-ref', '${ref}');
341
484
  let reference = event.target.getAttribute('data-ref');
342
485
  event.target.eventData = event;
486
+
343
487
  let domquery = queryRef(reference);
344
- domquery.eventData = event;
345
- domquery.eventData.detail.target = domquery;
346
- call('${name}', {event:domquery.eventData}, '${d.params}')
488
+
489
+ domquery.eventData = event;
490
+ domquery.eventData.target = domquery;
491
+ call('${name}', {event:domquery.eventData}, '${paramNames}')
347
492
  })(event)
348
493
  `;
349
494
  }
@@ -412,11 +557,14 @@ export class Component {
412
557
  if (!this.state[key]) {
413
558
  this.state[key] = initialState;
414
559
  }
415
- const getValue = () => this.state[key];
416
- const set = (newValue) => {
560
+ let updatedValue = () => this.state[key];
561
+ const getValue = updatedValue()
562
+ const set = (newValue, hook) => {
417
563
  this.state[key] = newValue;
418
- this.hydrate();
564
+ this.hydrate(hook);
419
565
  };
566
+ this[`set${key}`] = set;
567
+ this[`get${key}`] = getValue;
420
568
  return [getValue, set];
421
569
  }
422
570
 
@@ -429,9 +577,11 @@ export class Component {
429
577
  this.state[key] = newValue;
430
578
  this.hydrate();
431
579
  };
580
+
581
+
432
582
  return {
433
- bind: key,
434
- current: () => document.querySelector(`[ref="${key}"]`) || this.state[key],
583
+ bind: key + this.key,
584
+ current: document.querySelector(`[ref="${key + this.key}"]`) || initialState
435
585
  }
436
586
  }
437
587
 
@@ -455,7 +605,7 @@ export class Component {
455
605
  * @private
456
606
  */
457
607
  checkIFMounted() {
458
- if (this.mounted) return;
608
+ if (this.mounted || !this.key) return;
459
609
  let timer = setInterval(() => {
460
610
  if (document.querySelector('[key="' + this.key + '"]')) {
461
611
  clearInterval(timer);
@@ -533,6 +683,7 @@ window.require = require;
533
683
  * @description Allows you to use state to dynamically update your component
534
684
  */
535
685
  export const useState = (initialState) => {
686
+ let key = ''
536
687
  let value = initialState;
537
688
  if (key && !states[key]) {
538
689
  this.states[key] = initialState;
@@ -540,6 +691,16 @@ export const useState = (initialState) => {
540
691
  return [value, (newValue) => {}];
541
692
  };
542
693
 
694
+ /**
695
+ * @method useReducer
696
+ * @param {*} initialState
697
+ * @param {*} reducer
698
+ * @returns {Array} [value, set]
699
+ */
700
+ export const useReducer = (/**@type {*}**/initialState, /**@type {function}**/reducer) => {
701
+ return [initialState, (newValue) => {}];
702
+ };
703
+
543
704
  const constants = {};
544
705
  let constantCounter = 0;
545
706
 
@@ -551,12 +712,20 @@ export const constant = (value) => {
551
712
  return constants[key];
552
713
  };
553
714
 
715
+ export const useRef = (initialState) => {
716
+ return {
717
+ current: initialState,
718
+ bind: '',
719
+ };
720
+ };
554
721
  export default {
555
722
  Component,
556
723
  require,
557
724
  invoke,
558
725
  mem,
559
726
  constant,
727
+ useRef,
728
+ useReducer,
560
729
  useState,
561
730
  strictMount,
562
731
  stylis,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "vaderjs",
3
3
  "description": "A Reactive library aimed to helping you build reactive applications inspired by react.js",
4
4
  "module": "vader.js",
5
- "version": "1.3.3-alpha-18",
5
+ "version": "1.3.3-alpha-20",
6
6
  "bin": {
7
7
  "vader": "./vader.js"
8
8
  },
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Vaderjs v1.3.3</title>
7
7
  <meta name="description" content="Vader.js is a modern web framework for building web applications.">
8
- <link rel="shortcut icon" href="https://raw.githubusercontent.com/Postr-Inc/Vader.js/vader1.3.3-beta/logo.png" type="image/x-icon">
8
+ <link rel="shortcut icon" href="https://raw.githubusercontent.com/Postr-Inc/Vader.js/main/logo.png" type="image/x-icon">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/runtime/router.js CHANGED
@@ -198,6 +198,9 @@ class VaderRouter{
198
198
  });
199
199
  }
200
200
  },
201
+ redirect: (path) => {
202
+ window.location.hash = path;
203
+ },
201
204
  render: async (/**@type {Component} */ Component, req, res) => {
202
205
 
203
206
  if(!Component.default || !Component.constructor){
package/runtime/vader.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  window.params = {};
3
3
  window.Vader = {
4
- version: "1.3.2",
4
+ version: "1.3.3",
5
5
  };
6
6
 
7
7
  let errors = {
@@ -43,16 +43,13 @@ let hasran = [];
43
43
  let states = {};
44
44
  let mounts = [];
45
45
  export const strictMount = (key, callback) => {
46
- let interval = setInterval(() => {
47
- if(mounts.find(mount => mount.key === key)
48
- && !hasran.includes(callback.toString())
49
- ){
46
+ let timer = setInterval(() => {
47
+ if (document.querySelector('[key="' + key + '"]')) {
48
+ console.log('mounted')
49
+ clearInterval(timer);
50
50
  callback();
51
- clearInterval(interval)
52
-
53
- hasran.push(callback.toString());
54
- }
55
- },0);
51
+ }
52
+ }, 120);
56
53
  };
57
54
 
58
55
  window.delegate = (event) => {
@@ -167,9 +164,93 @@ export class Component {
167
164
  window.listeners = [];
168
165
  this.functionMap = new Map();
169
166
  this.freeMemoryFromFunctions();
167
+ this.checkIFMounted();
170
168
  this.memoizes = []
169
+
170
+ this.vdom = []
171
+
171
172
  this.children = []
173
+ let dom = new DOMParser().parseFromString(this.render(), 'text/html').body.firstChild;
174
+ dom.querySelectorAll('*').forEach((el) => {
175
+ let obj = {
176
+ el: el,
177
+ tag: el.tagName,
178
+ html: el.innerHTML,
179
+ content: el.textContent,
180
+ value: el.value,
181
+ attributes: el.attributes,
182
+ children: el.childNodes,
183
+ }
184
+ this.vdom.push(obj)
185
+ });
186
+
187
+ /**
188
+ * Parent of the current component.
189
+ * @type {Component}
190
+ */
191
+ this.parentNode = {}
192
+
193
+ /**
194
+ * Request object.
195
+ */
196
+ this.request = {
197
+ /**
198
+ * @type {string}
199
+ * @description The headers for the current route
200
+ */
201
+ headers:{},
202
+ /**
203
+ * @type {string}
204
+ * @description The method for the current route
205
+ */
206
+ method: "GET",
207
+ /**
208
+ * @type {string}
209
+ * @description params for the given route /:id/:name etc
210
+ */
211
+ params: {},
212
+ /**
213
+ * @type {string}
214
+ * @description path: current route path
215
+ */
216
+ path: "",
217
+ /**
218
+ * @type {string}
219
+ * @description query: query object for the current route ?name=hello -> {name: 'hello'}
220
+ */
221
+ query: {},
222
+ },
223
+ /**
224
+ * @type {string}
225
+ * @description The response object for the current route
226
+ */
227
+ this.response = {
228
+ /**
229
+ * @method json
230
+ * @description This method allows you to send json data to the client
231
+ * @param {*} data
232
+ */
233
+ json: (data) => {},
234
+ /**
235
+ * @method send
236
+ * @description This method allows you to send text data to the client
237
+ * @param {*} data
238
+ */
239
+ send: (data) => {},
240
+ /**
241
+ * @method redirect
242
+ * @description This method allows you to redirect the client to a new route
243
+ * @param {*} path
244
+ */
245
+ redirect: (path) => {},
246
+ /**
247
+ * @method render
248
+ * @description render a new component to the client
249
+ * @param {*} Component
250
+ */
251
+ render: async (Component) => {},
172
252
  }
253
+ }
173
254
 
174
255
  createComponent(/**@type {Component}**/component, props, children) {
175
256
 
@@ -179,26 +260,16 @@ export class Component {
179
260
  if(!props.key){
180
261
  throw new Error('new components must have a key')
181
262
  }
182
- let comp = new component();
183
- Object.keys(props).forEach((key) => {
184
- // some props are this.bind inside of "" so we need to handle that
185
- let newFunc = props[key].match(/this.bind\((.*)\)/gs);
186
- if (newFunc) {
187
- newFunc = newFunc[0].replace(/this.bind\((.*)\)/gs, "$1");
188
- newFunc = newFunc.split('`')[1]
189
- props[key] = this.bind(newFunc, { jsx: true, params: props[key], ref: props.ref });
190
- return
191
- }
192
-
193
-
194
-
195
- props[key] = props[key].toString().replace('"', '').replace("'", '').replace('${', '').replace('}', '')
196
- });
263
+ let comp = new component(props);
264
+ if(this.components[props.key]){
265
+ return this.components[props.key]
266
+ }
197
267
  comp['props'] = props;
198
268
  comp.children = children;
199
269
  comp.props.children = children.join('')
200
270
  comp.parentNode = this;
201
271
  comp.key = props.key || null;
272
+
202
273
  this.components[props.key] = comp
203
274
  this.children.push(comp)
204
275
  return this.components[props.key]
@@ -215,6 +286,7 @@ export class Component {
215
286
  }
216
287
 
217
288
  let comp = this.components[component.key];
289
+
218
290
  let h = comp.render()
219
291
 
220
292
  if(h && h.split('>,').length > 1){
@@ -240,28 +312,75 @@ export class Component {
240
312
  * Hydrates the component by updating the HTML content if it has changed.
241
313
  * @private
242
314
  */
243
- hydrate() {
244
- if (this.key) {
245
-
246
- const el = document.querySelector(`[key="${this.key}"]`);
247
315
 
248
-
249
- if (el) {
250
-
251
-
252
- // Render the new HTML content
253
- const newHtml = this.render();
254
- // Compare the new HTML with the cached content
255
- if (newHtml !== this.currentHtml) {
256
- // Update the HTML only if it has changed
257
- el.innerHTML = newHtml;
258
-
259
- // Update the cached HTML content
260
- this.currentHtml = newHtml;
316
+ domDifference(oldDom, newDom) {
317
+ let diff = [];
318
+
319
+ for (let i = 0; i < oldDom.length; i++) {
320
+ let oldEl = oldDom[i];
321
+ let newEl = newDom[i];
322
+
323
+ if (oldEl && newEl && !oldEl.isEqualNode(newEl)) {
324
+ diff.push({
325
+ type: 'replace',
326
+ old: oldEl,
327
+ new: newEl.cloneNode(true),
328
+ });
329
+ }
330
+ }
331
+
332
+ return diff;
333
+ }
334
+
335
+ updateChangedElements(diff) {
336
+ diff.forEach((change) => {
337
+ switch (change.type) {
338
+ case 'replace':
339
+ change.old.parentNode.replaceChild(change.new, change.old);
340
+ break;
341
+ case 'remove':
342
+ change.old.remove();
343
+ break;
344
+ case 'add':
345
+ change.old.appendChild(change.new.cloneNode(true));
346
+ break;
347
+ default:
348
+ break;
349
+ }
350
+ });
351
+ }
352
+
353
+ hydrate(hook) {
354
+ if (this.key) {
355
+ if (hook) {
356
+ let newDom = new DOMParser().parseFromString(this.render(), 'text/html').body.firstChild;
357
+
358
+ let oldElements = document.body.querySelectorAll(`[ref="${hook}"]`);
359
+ let newElements = newDom.querySelectorAll(`[ref="${hook}"]`);
360
+ let diff = this.domDifference(oldElements, newElements);
361
+ this.updateChangedElements(diff);
362
+ } else {
363
+ const targetElement = document.querySelector(`[key="${this.key}"]`);
364
+ if (targetElement) {
365
+ targetElement.innerHTML = this.render();
366
+ } else {
367
+ console.error('Target element not found.');
261
368
  }
262
369
  }
263
370
  }
264
371
  }
372
+
373
+
374
+
375
+ patch(oldElements, newElements) {
376
+ const diff = this.domDifference(oldElements, newElements);
377
+
378
+ this.updateChangedElements(diff);
379
+ }
380
+
381
+
382
+
383
+
265
384
 
266
385
  /**
267
386
  * Handles an object by parsing it as JSON and evaluating it.
@@ -279,7 +398,7 @@ export class Component {
279
398
  }
280
399
 
281
400
  /**
282
- * Frees memory from functions that have not been used for a certain period of time.
401
+ * Frees memory from functions that have not been used for a certain period of time.c
283
402
  * @private
284
403
  */
285
404
  freeMemoryFromFunctions() {
@@ -299,23 +418,47 @@ export class Component {
299
418
  * @param {string} ref - The reference.
300
419
  * @returns {string} - A valid inline JS function call.
301
420
  */
302
- bind(funcData, d) {
421
+ bind(funcData,jsx,ref, paramNames, ...params) {
422
+
303
423
 
304
424
  const name = `func_${crypto ? crypto.getRandomValues(new Uint32Array(1))[0] : Math.random()}`;
305
425
 
306
- var dynamicFunction = (params) => {
307
- let func = new Function(`return (async () => {
308
- ${funcData}
309
- })()`);
310
- func = func.bind(this);
311
- func(params);
426
+ var dynamicFunction = async (...params) => {
427
+
428
+ // Replace double commas with a single comma
429
+
430
+
431
+ // Turn params into a destructured object
432
+ let paramObject = {};
433
+ params = params[0]
434
+
435
+ paramNames = paramNames.replace(/,,/g, ',');
436
+ let newparamnames = paramNames.replaceAll(',,', ',')
437
+ // Remove trailing commas
438
+ paramNames.endsWith(',') ? paramNames = paramNames.slice(0, -1) : null;
439
+ console.log(paramNames)
440
+
441
+ params.forEach((param, index) => {
442
+ paramObject[newparamnames.split(',')[index]] = param;
443
+ });
444
+
445
+ paramNames = paramNames.replace(',,', ',');
446
+ let func = new Function(`${paramNames}`, `
447
+ return (async (${paramNames}) => {
448
+ ${funcData}
449
+ })(${Object.keys(paramObject).join(',')})
450
+ `);
451
+
452
+ // Bind and execute the function with the provided parameters
453
+ await func.bind(this)(...Object.values(paramObject));
312
454
  };
455
+
313
456
 
314
457
  dynamicFunction = dynamicFunction.bind(this);
315
458
  if (!this.functionMap.has(name)) {
316
459
  document.addEventListener(`call_${name}`, (e) => {
317
460
 
318
- dynamicFunction();
461
+ dynamicFunction(params);
319
462
  this.functionMap.set(e.detail.name, {
320
463
  lastUsed: Date.now(),
321
464
  });
@@ -335,15 +478,17 @@ export class Component {
335
478
  };
336
479
 
337
480
  // Return a valid inline js function call
338
- return d.jsx ? dynamicFunction : `
481
+ return jsx ? dynamicFunction : `
339
482
  ((event) => {
340
- event.target.setAttribute('data-ref', '${d.ref}');
483
+ event.target.setAttribute('data-ref', '${ref}');
341
484
  let reference = event.target.getAttribute('data-ref');
342
485
  event.target.eventData = event;
486
+
343
487
  let domquery = queryRef(reference);
344
- domquery.eventData = event;
345
- domquery.eventData.detail.target = domquery;
346
- call('${name}', {event:domquery.eventData}, '${d.params}')
488
+
489
+ domquery.eventData = event;
490
+ domquery.eventData.target = domquery;
491
+ call('${name}', {event:domquery.eventData}, '${paramNames}')
347
492
  })(event)
348
493
  `;
349
494
  }
@@ -412,11 +557,14 @@ export class Component {
412
557
  if (!this.state[key]) {
413
558
  this.state[key] = initialState;
414
559
  }
415
- const getValue = () => this.state[key];
416
- const set = (newValue) => {
560
+ let updatedValue = () => this.state[key];
561
+ const getValue = updatedValue()
562
+ const set = (newValue, hook) => {
417
563
  this.state[key] = newValue;
418
- this.hydrate();
564
+ this.hydrate(hook);
419
565
  };
566
+ this[`set${key}`] = set;
567
+ this[`get${key}`] = getValue;
420
568
  return [getValue, set];
421
569
  }
422
570
 
@@ -429,9 +577,11 @@ export class Component {
429
577
  this.state[key] = newValue;
430
578
  this.hydrate();
431
579
  };
580
+
581
+
432
582
  return {
433
- bind: key,
434
- current: () => document.querySelector(`[ref="${key}"]`) || this.state[key],
583
+ bind: key + this.key,
584
+ current: document.querySelector(`[ref="${key + this.key}"]`) || initialState
435
585
  }
436
586
  }
437
587
 
@@ -455,7 +605,7 @@ export class Component {
455
605
  * @private
456
606
  */
457
607
  checkIFMounted() {
458
- if (this.mounted) return;
608
+ if (this.mounted || !this.key) return;
459
609
  let timer = setInterval(() => {
460
610
  if (document.querySelector('[key="' + this.key + '"]')) {
461
611
  clearInterval(timer);
@@ -533,6 +683,7 @@ window.require = require;
533
683
  * @description Allows you to use state to dynamically update your component
534
684
  */
535
685
  export const useState = (initialState) => {
686
+ let key = ''
536
687
  let value = initialState;
537
688
  if (key && !states[key]) {
538
689
  this.states[key] = initialState;
@@ -540,6 +691,16 @@ export const useState = (initialState) => {
540
691
  return [value, (newValue) => {}];
541
692
  };
542
693
 
694
+ /**
695
+ * @method useReducer
696
+ * @param {*} initialState
697
+ * @param {*} reducer
698
+ * @returns {Array} [value, set]
699
+ */
700
+ export const useReducer = (/**@type {*}**/initialState, /**@type {function}**/reducer) => {
701
+ return [initialState, (newValue) => {}];
702
+ };
703
+
543
704
  const constants = {};
544
705
  let constantCounter = 0;
545
706
 
@@ -551,12 +712,20 @@ export const constant = (value) => {
551
712
  return constants[key];
552
713
  };
553
714
 
715
+ export const useRef = (initialState) => {
716
+ return {
717
+ current: initialState,
718
+ bind: '',
719
+ };
720
+ };
554
721
  export default {
555
722
  Component,
556
723
  require,
557
724
  invoke,
558
725
  mem,
559
726
  constant,
727
+ useRef,
728
+ useReducer,
560
729
  useState,
561
730
  strictMount,
562
731
  stylis,
package/vader.js CHANGED
@@ -25,23 +25,21 @@ function Compiler(func) {
25
25
  let savedfuncnames = [];
26
26
  let functions = string
27
27
  .match(
28
- /(?:const|let|var)?\s*([a-zA-Z0-9_-]+)\s*(?:=|function)\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)|(?:const|let|var)?\s*([a-zA-Z0-9_-]+)\s*=\s*\(([^)]*)\)/gs
28
+ /(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
29
29
  )
30
30
  ?.map((match) => match.trim());
31
31
 
32
-
33
32
  let functionNames = [];
34
33
 
35
34
  if (functions) {
36
35
  functions.forEach((func) => {
37
36
  if (
38
37
  !func.match(
39
- /(?:const|let|var)?\s*([a-zA-Z0-9_-]+)\s*(?:=|function)\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)|(?:const|let|var)?\s*([a-zA-Z0-9_-]+)\s*=\s*\(([^)]*)\)/gs
38
+ /(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
40
39
  )
41
40
  ) {
42
41
  return;
43
- }
44
- let code = string;
42
+ }
45
43
 
46
44
  let name = func.split(" ")[1].split("(")[0].trim();
47
45
 
@@ -73,6 +71,7 @@ function Compiler(func) {
73
71
  let childs = [];
74
72
 
75
73
 
74
+
76
75
  function extractAttributes(code) {
77
76
  // Match elements with opening tags
78
77
  const elementRegex = /<([a-zA-Z0-9_-]+)([^>]*)>/gs;
@@ -134,12 +133,11 @@ function Compiler(func) {
134
133
  if (functionNames.length > 0) {
135
134
  functionNames.forEach((name) => {
136
135
  string.split("\n").forEach((line) => {
137
- if (line.includes(name) && line.includes("function") || line.includes(name) && line.includes("=>")) {
136
+ if (line.includes(name) && line.includes("function")) {
138
137
  line = line.trim();
139
138
  line = line.replace(/\s+/g, " ");
140
139
 
141
- let ps = line.split("(")[1].split(")")[0].trim();
142
-
140
+ let ps = line.split("(").slice(1).join("(").split(")")[0].trim();
143
141
 
144
142
  // remove comments
145
143
  ps = ps.match(/\/\*.*\*\//gs)
@@ -160,8 +158,7 @@ function Compiler(func) {
160
158
  let params = hasParams
161
159
  ? line.split("(")[1].split(")")[0].trim()
162
160
  : null;
163
-
164
-
161
+
165
162
  if (
166
163
  functionparams.length > 0 &&
167
164
  functionparams.find((p) => p.name == name)
@@ -187,11 +184,10 @@ function Compiler(func) {
187
184
  } ${params || null}${isJSXComponent ? "" : ","} true ${isJSXComponent ? "" : ","
188
185
  } '${ref}')`;
189
186
 
190
- console.log(replacement)
191
187
  newvalue = newvalue.replace(
192
- line,
188
+ hasParams ? `${name}(${params})` : name,
193
189
  `this.callFunction(\${${replacement}}, ${isJSXComponent ? true : false
194
- }, event,${params || null})`
190
+ }, event, \${JSON.stringify(${params || null})})`
195
191
  );
196
192
  }
197
193
  }
@@ -218,14 +214,21 @@ function Compiler(func) {
218
214
 
219
215
 
220
216
  let otherdata = {};
217
+
221
218
  params ? (otherdata["params"] = params) : null;
222
219
  otherdata["jsx"] = isJSXComponent;
223
220
  otherdata["ref"] = ref;
224
221
 
225
222
  newvalue = newvalue.split('\n').map(line => line.trim() ? line.trim() + ';' : line).join('\n');
226
223
 
227
- let newatribute = `${attributeName}="\${this.bind(\`${newvalue}\`, {jsx: ${isJSXComponent}, ref: '${ref}'})}"`;
224
+ // turn params into param1, param2, param3
225
+
226
+
227
+ let paramString = params ? params.split(' ').map(param => param + ',').join('') : "";
228
228
 
229
+ let newatribute = `${attributeName}="\${this.bind(\`${newvalue}\`, ${isJSXComponent ? true : false}, '${ref}', "${paramString}", ${params || null})}"`
230
+
231
+
229
232
  attribute[attributeName] = {
230
233
  old: old,
231
234
  new: newatribute,
@@ -259,9 +262,10 @@ function Compiler(func) {
259
262
  otherdata["ref"] = ref;
260
263
  // since js is all in one line split it
261
264
  newvalue = newvalue.split('\n').map(line => line.trim() ? line.trim() + ';' : line).join('\n');
262
-
263
- let newattribute = `${attributeName}="\${this.bind(\`${newvalue}\` ${isJSXComponent ? "" : ","}${JSON.stringify(otherdata)} )}"`;
264
- console.log(newattribute)
265
+ // param1, param2, param3
266
+ let length = params ? params.split(' ').length : 0;
267
+ let paramString = params ? params.split(' ').map(param => param + ',').join('') : "";
268
+ let newattribute = `${attributeName}="\${this.bind(\`${newvalue}\`, ${isJSXComponent ? true : false}, '${ref}', "${paramString}", ${params || null})}"`
265
269
  newattribute = newattribute.replace(/\s+/g, " ")
266
270
  string = string.replace(old, newattribute);
267
271
  }
@@ -298,6 +302,7 @@ function Compiler(func) {
298
302
  let contents = "";
299
303
  let updatedContents = "";
300
304
  outerReturn.forEach((returnStatement) => {
305
+
301
306
  let lines = returnStatement.split("\n");
302
307
 
303
308
  for (let i = 0; i < lines.length; i++) {
@@ -306,7 +311,7 @@ function Compiler(func) {
306
311
  continue;
307
312
  }
308
313
  contents += line + "\n";
309
- }
314
+ }
310
315
 
311
316
  // Remove trailing ']'
312
317
  contents = contents.trim().replace(/\]$/, "");
@@ -324,24 +329,25 @@ function Compiler(func) {
324
329
 
325
330
  let value = attributes[key];
326
331
  let oldvalue = value;
327
- if (value && !value.new) {
328
- if (value && value.includes("{")) {
332
+ if (value && !value.new) {
333
+ if (value && value.includes("={")) {
329
334
  value = value.replace("=", "");
330
335
  value == "undefined" ? (value = '"') : (value = value);
331
336
  key == 'style' ? value = `{this.parseStyle({${value.split('{{')[1].split('}}')[0]}})}` : null
332
337
 
333
- value = `="\$${value}"`;
338
+
339
+ value = `="\$${value}",`;
334
340
  string = string.replace(oldvalue, value);
335
341
 
336
- } else if (value && value.includes("`")) {
342
+ } else if (value && value.includes("={`")) {
337
343
  value = value.replace("=", "");
338
-
339
- value = `"\$${value}"`;
344
+
345
+ value = `"\$${value}",`;
340
346
  string = string.replace(oldvalue, value);
341
347
 
342
348
  }
343
349
  } else if (value && value.new) {
344
- let newvalue = value.new;
350
+ let newvalue = value.new + ",";
345
351
  let old = value.old;
346
352
  string = string.replace(old, newvalue);
347
353
  }
@@ -407,16 +413,15 @@ function Compiler(func) {
407
413
  let setKey = line.split("=")[0].split(",")[1].trim().replace("]", "");
408
414
 
409
415
  key = key.replace("[", "").replace(",", "");
410
- let value = line
411
- .split("=")[1]
412
- .split("useState")[1]
413
- .split("(")[1]
414
- .split(")")[0]
415
- .trim();
416
- let newState = `${type} [${key}, ${setKey}] = this.useState('${key}', ${value})
417
- this.${key} = ${key}
418
- this.${setKey} = ${setKey}
416
+ let value = line.split("=")[1].split("useState(")[1]
417
+ let regex = /useState\((.*)\)/gs
418
+ value = value.match(regex) ? value.match(regex)[0].split("useState(")[1].split(")")[0].trim() : value
419
+
420
+
421
+ let newState = `${type} [${key}, ${setKey}] = this.useState('${key}', ${value}
422
+
419
423
  `;
424
+
420
425
 
421
426
  // get setkey calls and replace with this.setKey
422
427
  string.split("\n").forEach((line) => {
@@ -431,18 +436,28 @@ function Compiler(func) {
431
436
  }
432
437
  });
433
438
  string = string.replace(line, newState);
434
- } else if (line.includes("useRef")) {
439
+ } else if (line.includes("useRef") && !line.includes("import")) {
435
440
  line = line.trim();
436
441
  // let ref = useRef(null)
437
442
  let type = line.split(" ")[0];
438
443
  let key = line.split("=")[0].split(" ")[1].trim();
439
- let value = line
440
- .split("=")[1]
441
- .split("useRef")[1]
442
- .split("(")[1]
443
- .split(")")[0]
444
- .trim();
445
- let newState = `${type} ${key} = this.useRef('${key}', ${value})`;
444
+ let value = line.split("=")[1].split("useRef(")[1]
445
+
446
+ let regex = /useState\((.*)\)/gs
447
+ value = value.match(regex) ? value.match(regex)[0].split("useRef(")[1].split(")")[0].trim() : value
448
+ let newState = `${type} ${key} = this.useRef('${key}', ${value}`;
449
+
450
+ string = string.replace(line, newState);
451
+ }else if (line.includes("useReducer") && !line.includes("import")){
452
+ line = line.trim();
453
+ // let ref = useRef(null)
454
+ let type = line.split(" ")[0];
455
+ let key = line.split("=")[0].split(" ")[1].trim();
456
+ let value = line.split("=")[1].split("useReducer(")[1]
457
+
458
+ let regex = /useReducer\((.*)\)/gs
459
+ value = value.match(regex) ? value.match(regex)[0].split("useReducer(")[1].split(")")[0].trim() : value
460
+ let newState = `${type} ${key} = this.useReducer('${key}', ${value}`;
446
461
 
447
462
  string = string.replace(line, newState);
448
463
  }
@@ -477,7 +492,11 @@ function Compiler(func) {
477
492
  return array;
478
493
  };
479
494
 
480
- string = string.replaceAll('vaderjs/client', './vader.js')
495
+ // replaceall comments ${/* */} with ''
496
+ string = string.replaceAll(/\$\{\/\*.*\*\/\}/gs, "");
497
+
498
+ string = string.replaceAll('../src', './src')
499
+
481
500
 
482
501
  // capture <Component />, <Component></Component>, and <Component>content</Component>
483
502
 
@@ -498,29 +517,9 @@ function Compiler(func) {
498
517
  let myChildrens = [];
499
518
 
500
519
  let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
501
- let props = component.split(`<${name}`)[1].split(">")[0].trim();
502
- function parseProps(attributes) {
503
- console.log(attributes)
504
- let props = {};
505
- if (attributes) {
506
- let propsMatch;
507
- let regex = /([a-zA-Z0-9_-]+)(\s*=\s*("([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}|(?:\([^)]*\)|\{[^}]*\}|()=>\s*(?:\{[^}]*\})?)|\[[^\]]*\]))?/gs
508
- while ((propsMatch = regex.exec(attributes)) !== null) {
509
- let [, attributeName, attributeValue] = propsMatch;
510
- console.log(attributeName, attributeValue)
511
- attributeValue = attributeValue.replaceAll('="', '').replace("='", '')
512
- if(attributeValue.startsWith("'")){
513
- attributeValue = attributeValue.replace("'", '')
514
- }
515
- props[attributeName] = attributeValue || null;
516
- }
517
-
518
- }
519
-
520
- return props;
521
- }
522
-
520
+ let props = component.split(`<${name}`)[1].split(">")[0].trim()
523
521
 
522
+
524
523
  let savedname = name;
525
524
  let children = props
526
525
  ? component
@@ -555,14 +554,36 @@ function Compiler(func) {
555
554
  myChildrens.push(child.children);
556
555
  }
557
556
  });
557
+
558
+
559
+
560
+
561
+ props = props
562
+ .replaceAll("=", ":")
563
+ .replaceAll('"', "'")
564
+ //fix key:'value' to key:'value', only if value ="value"
565
+
566
+ .replaceAll(",,", ',')
567
+ .replaceAll("className", "class")
568
+ .replaceAll("classname", "class")
569
+ .replaceAll("'${", "")
570
+ .replaceAll("}'", "")
571
+ .split("$:")
572
+ .join("")
573
+ .replace('/', '')
574
+ // remove trailing ,
575
+ .replace(/,\s*$/, "")
576
+ props = props.replace(/:('[^']*'|"[^"]*")/g, ':$1,');
577
+ props = props.replaceAll(',,', ',')
578
+
579
+
580
+
558
581
 
559
- props = JSON.stringify(parseProps(props));
560
-
561
582
  let replace = "";
562
583
  replace = isChild
563
- ? `this.memoize(this.createComponent(${savedname.replaceAll('/', '')}, ${props} , [${myChildrens.length > 0 ? myChildrens.join(",") : ""
584
+ ? `this.memoize(this.createComponent(${savedname.replaceAll('/', '')}, ${props}, [${myChildrens.length > 0 ? myChildrens.join(",") : ""
564
585
  }])),`
565
- : `\${this.memoize(this.createComponent(${savedname.replaceAll('/', '')}, ${props} , [${myChildrens.length > 0 ? myChildrens.join(",") : ""
586
+ : `\${this.memoize(this.createComponent(${savedname.replaceAll('/', '')}, {${props}}, [${myChildrens.length > 0 ? myChildrens.join(",") : ""
566
587
  }]))}`;
567
588
 
568
589
  body = body.replace(before, replace);
@@ -573,6 +594,7 @@ function Compiler(func) {
573
594
 
574
595
 
575
596
 
597
+ string = string.replaceAll('vaderjs/client', './vader.js')
576
598
  string = string.replaceAll("<>", "`").replaceAll("</>", "`");
577
599
  string = parseComponents(string);
578
600
 
@@ -633,10 +655,8 @@ async function Build() {
633
655
 
634
656
  // Read and compile file content
635
657
  let data = await fs.readFileSync(origin, "utf8");
636
- data = Compiler(data);
637
-
638
- // Write compiled content to the 'dist/pages' directory
639
- console.log(`Compiling ${fileName} to ${obj.url}`)
658
+ data = Compiler(data);
659
+
640
660
  await writer(process.cwd() + "/dist/pages/" + fileName, data);
641
661
 
642
662
  // Generate routing logic
@@ -666,12 +686,13 @@ async function Build() {
666
686
  absolute: true,
667
687
  });
668
688
  scannedVaderFiles.forEach(async (file) => {
669
- file = file.replace(/\\/g, '/');
670
- if(file.includes('index.html') && fs.existsSync(process.cwd() + "/dist/index.html")){
671
- return
672
- }
673
-
689
+ file = file.replace(/\\/g, '/');
690
+
691
+
674
692
  let name = file.split( '/node_modules/vaderjs/runtime/')[1]
693
+ if(file.includes('index.html') && fs.existsSync(process.cwd() + "/dist/" + name)){
694
+ return
695
+ }
675
696
  let data = await reader(file)
676
697
  bundleSize += fs.statSync(file).size;
677
698
  await writer(process.cwd() + "/dist/" + name, data);
@@ -709,21 +730,25 @@ async function Build() {
709
730
  })
710
731
 
711
732
  if (!fs.existsSync(process.cwd() + "/dist/index.html")) {
733
+
712
734
  scannedFiles.forEach(async (file) => {
713
735
  file = file.split(process.cwd() + '/runtime/')[1]
714
736
 
715
737
  if (file === "app.js") {
716
738
  return
717
739
  }
740
+ console.log(`Compiling ${file} to /dist/${file}`)
741
+ if(file.includes('index.html') && fs.existsSync(process.cwd() + "/runtime/" + file)){
742
+ console.log(`Compiling ${file} to /dist/${file}`)
743
+ return
744
+ }
718
745
  bundleSize += fs.statSync(process.cwd() + "/runtime/" + file).size;
719
746
  let data = await reader(process.cwd() + "/runtime/" + file)
720
747
  await writer(process.cwd() + "/dist/" + file, data);
721
748
  });
722
749
 
723
750
  }
724
-
725
751
 
726
- console.log(`Compilation completed`)
727
752
  globalThis.isBuilding = false
728
753
  }
729
754
  import { watch } from "fs";
@@ -747,13 +772,17 @@ Vader.js v1.3.3
747
772
  }
748
773
  },
749
774
  );
750
- const watcher2 = watch( process.cwd() + '/src', { recursive: true }, (event, filename) => {
751
- if (event == 'change'
752
- && !globalThis.isBuilding
753
- ) {
754
- Build()
755
- }
756
- });
775
+ const watcher2 = watch(
776
+ process.cwd() + '/src',
777
+ { recursive: true },
778
+ (event, filename) => {
779
+ if (event == 'change'
780
+ && !globalThis.isBuilding
781
+ ) {
782
+ Build()
783
+ }
784
+ },
785
+ );
757
786
  watcher2.on('error', (err) => console.log(err))
758
787
  watcher.on('error', (err) => console.log(err))
759
788