vaderjs 1.3.3-7924566dd811 → 1.3.3-7b27417dd2e1

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/vader.js CHANGED
@@ -1,11 +1,40 @@
1
1
  #!/usr/bin/env node
2
- import fs from "fs";
2
+ import fs, { fstatSync } from "fs";
3
3
  import { glob, globSync, globStream, globStreamSync, Glob, } from 'glob'
4
4
  import puppeteer from 'puppeteer';
5
5
  import http from 'http'
6
+ import { SourceMapGenerator } from 'source-map'
7
+
6
8
  import { WebSocketServer } from 'ws'
9
+ import prettier from 'prettier'
7
10
  import { watch } from "fs";
8
11
  import path from 'path'
12
+
13
+ globalThis.compiledFiles = []
14
+
15
+ const sourceMapGen = (data, code) => {
16
+ let { origin, fileName } = data
17
+ const sourceMap = new SourceMapGenerator({ file: '/src/' + fileName.replace('.jsx', '.js') });
18
+
19
+ const lines = fs.readFileSync(origin, "utf8").split("\n");
20
+ let line = 1;
21
+ let column = 0;
22
+ for (const l of lines) {
23
+ sourceMap.addMapping({
24
+ source: origin,
25
+ sourceRoot: '/src',
26
+ original: { line: line, column: 0 },
27
+ generated: { line: line, column: 0 },
28
+ });
29
+ line++;
30
+ }
31
+
32
+ sourceMap.setSourceContent(origin, fs.readFileSync(origin, "utf8"));
33
+
34
+ code = code + `\n//# sourceMappingURL=./src/maps/${fileName.replace('.jsx', '.js')}.map \n //#sourceURL=/src/maps/${fileName.replace('.jsx', '.js')}.map`
35
+ return { code, sourceMap };
36
+ }
37
+
9
38
  let config = await import('file://' + process.cwd() + '/vader.config.js').then((e) => e.default || e)
10
39
  let writer = async (file, data) => {
11
40
  globalThis.isWriting = file
@@ -22,8 +51,8 @@ let writer = async (file, data) => {
22
51
  globalThis.isWriting = null
23
52
  return { _written: true };
24
53
  };
25
-
26
- let bundleSize = 0;
54
+
55
+ let bundleSize = 0;
27
56
 
28
57
  if (!fs.existsSync(process.cwd() + '/dist')) {
29
58
  fs.mkdirSync(process.cwd() + '/dist')
@@ -33,102 +62,47 @@ if (!fs.existsSync(process.cwd() + '/dist')) {
33
62
 
34
63
 
35
64
  if (typeof process.env.isCloudflare !== "undefined" || !fs.existsSync(process.cwd() + '/dist/index.html')) {
36
- let htmlFile = fs.readFileSync(process.cwd() + "/node_modules/vaderjs/runtime/index.html", 'utf8')
37
- fs.writeFileSync(process.cwd() + "/dist/index.html", htmlFile)
65
+ fs.writeFileSync(process.cwd() + "/dist/index.html", '')
38
66
  }
39
67
 
40
68
 
41
69
 
42
70
  function Compiler(func, file) {
43
- let string = func;
71
+ let string = func;
44
72
  let returns = []
45
73
  let comments = string.match(/\{\s*\/\*.*\*\/\s*}/gs)?.map((comment) => comment.trim());
46
74
 
47
-
48
-
49
-
50
75
 
51
- // get all Obj({}) and parse to JSON.stringify
52
76
 
53
- let objects = string.match(/Obj\({.*}\)/gs);
54
77
 
55
- objects && objects.forEach((obj) => {
56
- let key = obj.split("Obj")[1].split("(")[1].split(")")[0].trim();
57
- let newobj = obj.replaceAll(`Obj(${key})`, `${key}`);
58
- // let newobj = obj.replaceAll(`Obj(${key})`, `JSON.parse('${key}')`)
59
- string = string.replaceAll(obj, `this.handleObject('${newobj}')`);
60
- });
61
78
 
62
79
 
63
80
  let childs = [];
64
81
 
65
- const spreadAttributeRegex = /\s*([a-zA-Z0-9_-]+)(\s*\$\s*=\s*{{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)}})/gs;
66
- let spreadMatch;
67
- while ((spreadMatch = spreadAttributeRegex.exec(string)) !== null) {
68
- let [, element, spread] = spreadMatch;
69
- let isJSXComponent = element.match(/[A-Z]/) ? true : false;
70
- if (isJSXComponent) {
71
- continue
72
-
73
- }
74
- let old = spread;
75
82
 
76
- // turn spread into attributes
77
- spread = spread.replace(/\s*$\s*=\s*/, "");
78
- spread = spread.replace(/{{/, "");
79
- spread = spread.replace(/}}/, "");
80
- spread = spread.replace(/\$\s*=\s*/, "");
83
+ // or : value boolean variable etc
84
+ const spreadAttributeRegex = /\s*([a-zA-Z0-9_-]+)\s*(\$\s*=\s*\{\s*\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}\s*\})/gs;
81
85
 
82
- // turn : into =
83
-
84
- // do not split inner Objects ex: {color: 'red', background: {color: 'blue'}} -> {color: 'red', background: {color: 'blue'}}
85
- let splitByCommas = spread.split(/,(?![^{]*})/g);
86
- splitByCommas = splitByCommas.map((e) => e.trim())
87
- splitByCommas = splitByCommas.map((e) => {
88
- switch (true) {
89
- case e.includes('function') || e.includes('=>'):
90
- e = e.replace(/:(.*)/gs, '={$1}')
91
- break;
92
- case e.includes('style'):
93
- e = e.replace(/:(.*)/gs, '="${this.parseStyle($1)}"')
94
- break;
95
- case e.includes('[') && e.includes(']'):
96
- e = e.replace(/:(.*)/gs, '={$1.join(" ")}')
97
- break;
98
- default:
99
- }
100
-
101
- return e.trim()
102
- })
103
-
104
- let newSpread = `\t` + splitByCommas.join(' ') + `\t`
105
-
106
- string = string.replace(old, newSpread);
107
-
108
- }
109
86
 
110
87
 
111
88
 
112
89
  function extractAttributes(code) {
113
- // Match elements with opening tags
90
+ // grab $={...} and ={...}
114
91
  const elementRegex = /<([a-zA-Z0-9_-]+)([^>]*)>/gs;
115
92
 
116
93
  // Match attributes in an opening tag, including those with ={}
117
94
  // Match attributes in an opening tag, including those with ={...}
118
95
  const attributeRegex =
119
- /\s*([a-zA-Z0-9_-]+)(\s*=\s*("([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}|(?:\([^)]*\)|\{[^}]*\}|()=>\s*(?:\{[^}]*\})?)|\[[^\]]*\]))?/gs;
120
-
121
- // <div $={{color: 'red'}}></div>
96
+ /\s*([a-zA-Z0-9_-]+)(\s*=\s*("(?:[^"\\]*(?:\\.[^"\\]*)*)"|'(?:[^'\\]*(?:\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}|(?:\([^)]*\)|\{[^}]*\}|()=>\s*(?:\{[^}]*\})?)|\[[^\]]*\]))?/gs;
122
97
 
123
98
 
124
99
 
125
- // only return elements with attribute {()=>{}} or if it also has parameters ex: onclick={(event)=>{console.log(event)}} also get muti line functions or onClick=()=>{}
126
- const functionAttributeRegex = /\s*([a-zA-Z0-9_-]+)(\s*=\s*{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)})/gs;
100
+ const functionAttributeRegex = /\s*([a-zA-Z0-9_-]+)\s*(=\s*{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)})/gs;
127
101
 
128
102
  let attributesList = [];
129
103
 
130
104
  let spreadAttributes = [];
131
- let spreadMatch;
105
+
132
106
  /**
133
107
  * @search - handle spread for html elements
134
108
  * @keywords - spread, spread attributes, spread props, spread html attributes
@@ -141,19 +115,22 @@ function Compiler(func, file) {
141
115
  *
142
116
  */
143
117
  let functionAttributes = [];
118
+ let spreadFunctions = [];
144
119
  let functionMatch;
145
120
  while ((functionMatch = functionAttributeRegex.exec(code)) !== null) {
146
121
 
147
122
  let [, attributeName, attributeValue] = functionMatch;
148
123
  let attribute = {};
149
124
 
150
- if (attributeValue && attributeValue.includes("=>") || attributeValue && attributeValue.includes("function")
125
+ if (attributeValue && attributeValue.includes("=>")
126
+ && !attributeValue.includes("this.bind")
127
+ || attributeValue && attributeValue.includes("function")
151
128
  && !spreadFunctions.includes(attributeValue)
152
129
  ) {
153
-
130
+
154
131
  let ref = Math.random().toString(36).substring(2).split('').filter((e) => !Number(e)).join('')
155
132
  let old = `${attributeName}${attributeValue}`
156
-
133
+
157
134
  let elementMatch = string.match(/<([a-zA-Z0-9_-]+)([^>]*)>/gs);
158
135
  let isJSXComponent = false;
159
136
  elementMatch.forEach((element) => {
@@ -166,11 +143,15 @@ function Compiler(func, file) {
166
143
  isJSXComponent = elementTag.match(/^[A-Z]/) ? true : false;
167
144
  }
168
145
  });
146
+ if (isJSXComponent) {
147
+ continue
148
+ }
169
149
  // add ; after newlines
170
150
 
171
151
 
172
152
  let newvalue = attributeValue.includes('=>') ? attributeValue.split("=>").slice(1).join("=>").trim() : attributeValue.split("function").slice(1).join("function").trim()
173
153
 
154
+ // add ; after newlines
174
155
 
175
156
 
176
157
  newvalue = newvalue.trim();
@@ -207,7 +188,7 @@ function Compiler(func, file) {
207
188
  newvalue = newvalue.replace(/}\s*$/, '');
208
189
 
209
190
 
210
-
191
+
211
192
 
212
193
  newvalue = newvalue.replaceAll(',,', ',')
213
194
  let paramnames = params ? params.split(',').map((e) => e.trim()) : null
@@ -217,6 +198,8 @@ function Compiler(func, file) {
217
198
 
218
199
  // add ; after newlines
219
200
  newvalue = newvalue.replaceAll(/\n/g, ";\n")
201
+ // remove () from newvalue
202
+ newvalue = newvalue.replace(/\(\s*=>/gs, '=>').replace(/\function\s*\([^\)]*\)\s*\{/gs, '{')
220
203
 
221
204
  let bind = isJSXComponent ? `${attributeName}='function(${params}){${newvalue}}'` : `${attributeName}="\$\{this.bind(function(){${newvalue}}.bind(this), ${isJSXComponent}, "${ref}", "${paramnames ? paramnames.map((e, index) => {
222
205
  if (e.length < 1) return ''
@@ -235,9 +218,10 @@ function Compiler(func, file) {
235
218
  * @keywords - attributes, props, html attributes
236
219
  */
237
220
  let match;
238
- while ((match = elementRegex.exec(code)) !== null) {
221
+ while ((match = elementRegex.exec(string)) !== null) {
239
222
  let [, element, attributes] = match;
240
223
 
224
+
241
225
  let attributesMatch;
242
226
  let elementAttributes = {};
243
227
 
@@ -250,6 +234,60 @@ function Compiler(func, file) {
250
234
  attributesList.push({ element, attributes: elementAttributes });
251
235
  }
252
236
 
237
+ let spreadMatch;
238
+ while ((spreadMatch = spreadAttributeRegex.exec(code)) !== null) {
239
+ let [, element, spread] = spreadMatch;
240
+ let isJSXComponent = element.match(/^[A-Z]/) ? true : false;
241
+ if (isJSXComponent) {
242
+ continue;
243
+ }
244
+ let old = spread;
245
+ spread = spread.trim().replace(/\s+/g, " ");
246
+ // re,pve $={ and }
247
+ spread = spread.replace(/\s*\$\s*=\s*{\s*{/gs, '')
248
+
249
+ // replace trailing }
250
+ spread = spread.replace(/}}\s*$/, '').replace(/}\s*}$/, '')
251
+ let splitByCommas = spread.split(/,(?![^{}]*})/gs)
252
+ // remove empty strings
253
+ splitByCommas = splitByCommas.filter((e) => e.split(':')[0].trim().length > 0)
254
+ splitByCommas = splitByCommas.map((e, index) => {
255
+ let key = e.split(':')[0].trim()
256
+ switch (true) {
257
+ case e.includes('function') && !e.includes('this.bind') || e && e.includes('=>') && !e.includes('this.bind'):
258
+ let value = e.split(':')[1].trim()
259
+ let ref = Math.random().toString(36).substring(2).split('').filter((e) => !Number(e)).join('');
260
+ value = `this.bind(${value}, false, "${ref}", "")`
261
+ e = `${key}="\${${value}}"`
262
+ break;
263
+ case e.includes('style:'):
264
+ let v2 = e.split('style:')[1].trim().replace(/,$/, '')
265
+ v2 = v2.replace(/,$/, '')
266
+ e = `${key}="\${this.parseStyle(${v2})}"`
267
+ break;
268
+
269
+ default:
270
+ let v = e.split(':')
271
+ key = v[0].trim()
272
+ // remove key from v
273
+ v.shift()
274
+ v = v.join(' ')
275
+ e = `${key}="\${${v}}"`
276
+
277
+ break;
278
+ }
279
+
280
+
281
+ return e;
282
+ });
283
+
284
+
285
+ let newSpread = splitByCommas.join(' ').trim().replace(/,$/, '');
286
+
287
+ // remove trailing }
288
+ string = string.replace(old, newSpread);
289
+ }
290
+
253
291
  return attributesList;
254
292
  }
255
293
 
@@ -258,7 +296,7 @@ function Compiler(func, file) {
258
296
  let returns = code.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs);
259
297
 
260
298
  return returns || [];
261
- }
299
+ }
262
300
  if (string.match(/return\s*\<>|return\s*\(.*\)/gs) && !string.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs)
263
301
  || string.match(/return\s*\<[a-zA-Z0-9_-]+.*>/gs)
264
302
  ) {
@@ -291,17 +329,22 @@ function Compiler(func, file) {
291
329
  }
292
330
  let usesBraces = returnStatement.match(/return\s*\(/gs) ? true : false;
293
331
 
294
-
332
+ let attributes = extractAttributes(string);
295
333
  contents = contents.trim().replace(/\]$/, "")
296
334
  contents = contents.replace(/\)$/, "");
297
335
  usesBraces ? !contents.includes('<>') ? contents = `<>${contents}</>` : null : null
298
336
  updatedContents = contents;
299
- let attributes = extractAttributes(contents);
337
+
300
338
 
301
339
  let newAttributes = [];
302
340
  let oldAttributes = [];
303
341
  attributes.forEach((attribute) => {
304
342
  const { element, attributes } = attribute;
343
+ // make sure it isnt a jsx component
344
+ let isJSXComponent = element.match(/[A-Z]/) ? true : false;
345
+ if (isJSXComponent) {
346
+ return;
347
+ }
305
348
  if (Object.keys(attributes).length === 0) return;
306
349
 
307
350
 
@@ -311,7 +354,9 @@ function Compiler(func, file) {
311
354
  let value = attributes[key];
312
355
  let oldvalue = value;
313
356
  if (value && !value.new) {
357
+
314
358
  if (value && value.includes("={")) {
359
+
315
360
  value = value.replace("=", "");
316
361
  value == "undefined" ? (value = '"') : (value = value);
317
362
 
@@ -436,14 +481,17 @@ function Compiler(func, file) {
436
481
  let myChildrens = [];
437
482
 
438
483
  let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
439
- let componentAttributes = component.split("<")[1].split(">")[0].split(" ").join(" ").replace(name, "").trim();
440
- const dynamicAttributesRegex = /(\w+)(?:="([^"]*)")?(?:='([^']*)')?(?:=\{([^}]*)\})?(?:=\{(.*?)\})?(?:={([^}]*)})?(?:{([^}]*)})?|(?:{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|(\.{3}\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|\$=\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\}/gs;
484
+ let componentAttributes = component.split("<")[1].split(">")[0].split(" ").join(" ").replace(name, "").trim();
485
+ // catchall = "" ={} =[]
486
+
441
487
 
488
+ let props = component.split("<")[1].split(">")[0]
442
489
 
443
490
 
491
+ const dynamicAttributesRegex = /([a-zA-Z0-9_-]+)\s*=\s*("(?:[^"\\]*(?:\\.[^"\\]*)*)"|'(?:[^'\\]*(?:\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{.*.*\})*)*\})*)*\}|(?:\([^)]*\)|()\s*=>\s*(?:\{.*\})?|\{[^}]*\})|\[[^\]]*\])/gs;
444
492
 
493
+ const attributeObject = {};
445
494
 
446
- let props = component.match(dynamicAttributesRegex)
447
495
 
448
496
  let filteredProps = [];
449
497
  let isWithinComponent = false;
@@ -452,70 +500,31 @@ function Compiler(func, file) {
452
500
 
453
501
  let $_ternaryprops = []
454
502
 
455
- for (let prop of props) {
456
-
457
- if (prop === componentName) {
458
-
459
- isWithinComponent = true;
460
- filteredProps.push(prop);
461
- } else if (isWithinComponent && prop.includes('=')) {
462
-
463
- if (prop.startsWith('$=')) {
464
- let old = prop
465
- prop = prop.replace('$=', '$_ternary=')
466
-
467
- // remove trailing }
468
- prop = prop.replace(/}\s*$/, '')
469
- component = component.replace(old, prop)
470
- componentAttributes = componentAttributes.replace(old, prop)
471
-
472
- $_ternaryprops.push(prop)
473
-
474
- }
475
- else if (prop.includes('${')) {
476
-
477
- prop = prop.replace('="', ':').replace('}"', '}')
478
- if (prop.includes('${')) {
479
- prop = prop.replace('="', ':')
480
- prop = prop.replace('${', '')
481
- prop = prop.replace('}', '')
482
-
483
- }
484
- if (prop.includes('="${{')) {
485
- prop = prop.replace('${{', '{')
486
- prop = prop.replace('}}', '}')
487
- prop = prop.replace('="', ':')
488
- prop = prop.replace('}"', '}')
489
- }
490
-
491
- }
492
- else if (prop.startsWith('={')) {
493
- prop = prop.replace('={', ':`${')
494
- prop.replace('} ', '}`')
495
- }
496
-
497
- if (prop.includes('function')) {
498
- // parse 'function' to function
499
- prop = prop.replace("'", '')
500
-
501
- if (prop.endsWith("}'")) {
502
- prop = prop.replace("}'", '}')
503
-
504
- }
505
-
506
- prop = prop.replace('=function', ':function')
507
- }
508
-
509
- filteredProps.push(prop);
510
-
511
-
512
-
503
+ let match;
504
+ let propstring = ''
505
+ // props right now is just a string with all of them on one line and a space between each
506
+ while ((match = dynamicAttributesRegex.exec(props)) !== null) {
507
+ let str = match[0].trim().replace(/\s+/g, " ");
508
+ if (!str.includes('=')) {
509
+ continue
513
510
  }
514
-
515
-
516
- else {
517
- isWithinComponent = false;
511
+ str = str.split('=')
512
+ let key = str[0].trim()
513
+ let value = str[1].trim()
514
+ if (value.startsWith('"') && !value.endsWith('"') || value.startsWith("'") && !value.endsWith("'")
515
+ || value.startsWith('`') && !value.endsWith('`')) {
516
+ // wrap in respective quotes
517
+ value = value + value[0]
518
518
  }
519
+ let isObject = value.startsWith('{{') && value.endsWith('}}')
520
+ if (isObject) {
521
+ value = value.split('{{')[1].split('}}')[0].trim()
522
+ value = `{${value}}`
523
+ } else {
524
+ // remove starting { and ending } using regex
525
+ value = value.replace(/^{/, '').replace(/}$/, '')
526
+ }
527
+ propstring += `${key}:${value},`
519
528
  }
520
529
  component = component.replaceAll(/\s+/g, " ");
521
530
 
@@ -524,10 +533,9 @@ function Compiler(func, file) {
524
533
  component = component.replace(prop, '')
525
534
  })
526
535
 
527
- let children = component.split(`<${name}`)[1].split(`</${name}>`)[0].trim().replace(/\s+/g, " ").trim().replace(/,$/, '').replace('>', '').replace(/\/$/, '').trim()
536
+ let children = new RegExp(`<${name}[^>]*>([^]*)<\/${name}>`, 'gs').exec(component)?.[1] || null;
528
537
 
529
538
 
530
- props = filteredProps.join(',').replace(/\s+/g, " ").trim().replace(/,$/, '')
531
539
 
532
540
  let savedname = name;
533
541
 
@@ -560,24 +568,15 @@ function Compiler(func, file) {
560
568
 
561
569
 
562
570
 
563
-
564
- props = props.replaceAll(`,${savedname}`, '').replaceAll(savedname, '')
565
- if (props.startsWith(',')) {
566
- props = props.replace(',', '')
567
- }
568
- props = props.replaceAll("='", ":'")
569
- .replaceAll('=`', ':`')
570
- .replaceAll('="', ':"')
571
- .replaceAll('={', ':')
571
+ propstring = propstring.replace(/,$/, '')
572
572
 
573
573
 
574
574
  /**
575
575
  * @memoize - memoize a component to be remembered on each render and replace the old jsx
576
576
  */
577
577
 
578
-
579
578
  let replace = "";
580
- replace = `\${this.memoize(this.createComponent(${savedname}, {${props}}, [\`${myChildrens.join('')}\`]))}`;
579
+ replace = `\${this.memoize(this.createComponent(${savedname}, {${propstring}}, [\`${myChildrens.join('')}\`]))}`;
581
580
 
582
581
 
583
582
  body = body.replace(before, replace);
@@ -593,48 +592,49 @@ function Compiler(func, file) {
593
592
  let replaceMents = [];
594
593
 
595
594
 
596
- for (let match of imports) {
597
- let path = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
598
- switch (true) {
599
- case path && !path.includes('./') && !path.includes('/vader.js') && !path.includes('/vaderjs/client') && !path.startsWith('src') && !path.startsWith('public') && !path.includes('http') && !path.includes('https'):
600
- let componentFolder = fs.existsSync(process.cwd() + '/node_modules/' + path) ? process.cwd() + '/node_modules/' + path : process.cwd() + '/node_modules/' + path.split('/')[0]
601
- componentFolder = componentFolder.split(process.cwd())[1]
602
- if (!fs.existsSync(process.cwd() + componentFolder)) {
603
- throw new Error('Could not find ' + path + ' at ' + match + ' in file ' + file)
604
- }
605
-
606
- if (!fs.existsSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'))) {
607
- fs.mkdirSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'), { recursive: true })
608
- }
609
-
610
- let baseFolder = componentFolder.split('node_modules')[1].split('/')[1]
611
- let glp = globSync('**/**/**/**.{jsx,js}', {
612
- cwd: process.cwd() + '/node_modules/' + baseFolder + '/',
613
- absolute: true,
614
- recursive: true
615
- })
616
- for (let file of glp) {
617
- let text = fs.readFileSync(file, "utf8");
618
- if (!file.endsWith('.js') && file.endsWith('.jsx')) {
619
- text = Compiler(text, file);
620
-
595
+ if(imports){
596
+ for (let match of imports) {
597
+ let path = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
598
+ switch (true) {
599
+ case path && !path.includes('./') && !path.includes('/vader.js') && !path.includes('/vaderjs/client') && !path.startsWith('src') && !path.startsWith('public') && !path.includes('http') && !path.includes('https'):
600
+ let componentFolder = fs.existsSync(process.cwd() + '/node_modules/' + path) ? process.cwd() + '/node_modules/' + path : process.cwd() + '/node_modules/' + path.split('/')[0]
601
+ componentFolder = componentFolder.split(process.cwd())[1]
602
+ if (!fs.existsSync(process.cwd() + componentFolder)) {
603
+ throw new Error('Could not find ' + path + ' at ' + match + ' in file ' + file)
621
604
  }
622
- let dest = file.split('node_modules')[1]
623
- dest = dest.split(baseFolder)[1]
624
- // write to dist
625
- writer(process.cwd() + '/dist/src/' + baseFolder + dest, text)
626
- let importname = match.split('import')[1].split('from')[0].trim()
627
- let oldImportstring = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
628
- let newImport = `/src/${baseFolder + dest}`
629
- newImport = newImport.replaceAll('.jsx', '.js').replaceAll('\\', '/')
630
- replaceMents.push({ match: oldImportstring, replace: newImport })
631
- console.log(`📦 imported Node Package ${baseFolder} `)
632
- }
633
-
634
-
635
- break;
636
- default:
637
- break;
605
+
606
+ if (!fs.existsSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'))) {
607
+ fs.mkdirSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'), { recursive: true })
608
+ }
609
+
610
+ let baseFolder = componentFolder.split('node_modules')[1].split('/')[1]
611
+ let glp = globSync('**/**/**/**.{jsx,js}', {
612
+ cwd: process.cwd() + '/node_modules/' + baseFolder + '/',
613
+ absolute: true,
614
+ recursive: true
615
+ })
616
+ for (let file of glp) {
617
+ let text = fs.readFileSync(file, "utf8");
618
+ if (!file.endsWith('.js') && file.endsWith('.jsx')) {
619
+ text = Compiler(text, file);
620
+
621
+ }
622
+ let dest = file.split('node_modules')[1]
623
+ dest = dest.split(baseFolder)[1]
624
+ writer(process.cwd() + '/dist/src/' + baseFolder + dest, text)
625
+ let importname = match.split('import')[1].split('from')[0].trim()
626
+ let oldImportstring = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
627
+ let newImport = `/src/${baseFolder + dest}`
628
+ newImport = newImport.replaceAll('.jsx', '.js').replaceAll('\\', '/')
629
+ replaceMents.push({ match: oldImportstring, replace: newImport })
630
+ console.log(`📦 imported Node Package ${baseFolder} `)
631
+ }
632
+
633
+
634
+ break;
635
+ default:
636
+ break;
637
+ }
638
638
  }
639
639
  }
640
640
 
@@ -827,224 +827,147 @@ const glb = await glob("**/**/**/**.{jsx,js}", {
827
827
  absolute: true,
828
828
  recursive: true
829
829
  });
830
+ let hasRendered = []
831
+
830
832
  async function Build() {
831
833
  globalThis.isBuilding = true
832
- console.log('Compiling......')
834
+ console.log(globalThis.isProduction ? 'Creating Optimized Production Build\n' : '')
835
+ let str = `Page \t\t\t\t Size\n`
836
+ globalThis.isProduction ? console.log('\x1b[32m%s\x1b[0m', str) : null
833
837
  let reader = async (file) => {
834
838
  let text = await fs.readFileSync(file, "utf8");
835
839
  return text;
836
840
  };
837
841
 
838
-
842
+
843
+
839
844
  function ssg(routes = []) {
840
845
  globalThis.isBuilding = true
841
- console.log(`Generating html files for ${routes.length} routes`)
842
- routes.forEach(async (route) => {
843
- if (route.url.includes(':')) {
844
- console.log('Route ' + route.url + ' is a dynamic route and will not be generated')
845
- return
846
- }
847
- let equalparamroute = routes.map((e) => {
848
- if (e.url.includes(':')) {
849
- let url = e.url.split('/:')[0]
850
- if (url && route.url === url) {
851
- return e
852
- } else {
853
- return null
846
+ let server = http.createServer((req, res) => {
847
+ let route = routes.find((e) => e.url === req.url)
848
+ if (route) {
849
+ let document = globalThis.routeDocuments.find((e) => e.url === req.url)
850
+ res.writeHead(200, { 'Content-Type': 'text/html' });
851
+ res.end(document.document);
852
+ } else {
853
+ const filePath = process.cwd() + '/dist/' + req.url
854
854
 
855
+ fs.readFile(filePath, (err, data) => {
856
+ if (err) {
857
+ res.writeHead(404, { 'Content-Type': filePath.includes('js') ? 'text/javascript' : 'text/html' });
858
+ res.end('File not found');
859
+ } else {
860
+ res.writeHead(200, { 'Content-Type': filePath.includes('js') ? 'text/javascript' : 'text/html' });
861
+ res.end(data);
855
862
  }
856
- }
857
- return null
858
- }).filter(Boolean)
859
- let document = `
860
- <!DOCTYPE html>
861
- <html lang="en">
862
- <head>
863
- <script>
864
- window.routes = JSON.parse('${JSON.stringify(routes)}')
865
- </script>
866
- <script id="isServer">
867
- window.isServer = true
868
- </script>
869
- <meta charset="UTF-8">
870
- <meta name="viewport" content="width=device-width,initial-scale=1.0">
871
- <script type="module" id="meta">
872
- window.history.pushState({}, '', '${route.url}')
873
- window.module = await import('/${route.fileName.replace('.jsx', '.js')}')
874
- let metadata = await module.$metadata
875
- if(metadata && metadata.title){
876
- document.head.innerHTML += '<title>' + metadata.title + '</title>'
877
- }
878
- if(metadata && metadata.description){
879
- document.head.innerHTML += '<meta name="description" content="' + metadata.description + '">'
880
- }
881
- if(metadata && metadata.keywords){
882
- document.head.innerHTML += '<meta name="keywords" content="' + metadata.keywords + '">'
883
- }
884
- if(metadata && metadata.author){
885
- document.head.innerHTML += '<meta name="author" content="' + metadata.author + '">'
886
- }
887
- if(metadata && metadata.image){
888
- let image = metadata.image.file
889
- let type = metadata.image.type
890
-
891
- document.head.innerHTML += '<meta property="og:image" content="' + image + '">'
892
- document.head.innerHTML += '<meta property="og:image:type" content="' + type + '">'
893
- }
894
- if(metadata && metadata.url){
895
- document.head.innerHTML += '<meta property="og:url" content="' + metadata.url + '">'
896
- }
897
-
898
- if(metadata && metadata.robot){
899
- document.head.innerHTML += '<meta name="robots" content="' + metadata.robot + '">'
900
- }
901
- if(metadata && metadata.manifest){
902
- document.head.innerHTML += '<link rel="manifest" href="' + metadata.manifest + '">'
903
- }
904
- if(metadata && metadata.tags){
905
- metadata.tags.forEach(tag => {
906
- document.head.innerHTML += tag
907
- })
908
- }
909
-
910
- if(metadata && metadata.styles){
911
- metadata.styles.forEach(style => {
912
- style = style.replaceAll('./', '/')
913
- style = style.replaceAll('../', '/')
914
- style = style.replace("'", '')
915
- document.head.innerHTML += '<link rel="stylesheet" href="' + style + '">'
916
- })
917
- }
918
- if(metadata && metadata.icon){
919
- document.head.innerHTML += '<link rel="icon" href="' + metadata.icon + '">'
920
- }
921
- </script>
922
- <script type="module" id="router">
923
- import VaderRouter from '/router.js'
924
- const router = new VaderRouter('${route.url}', 3000)
925
- router.get('${route.url}', async (req, res) => {
926
- let module = await import('/${route.fileName.replace('.jsx', '.js')}')
927
- if(Object.keys(module).includes('$prerender') && !module.$prerender){
928
- document.head.setAttribute('prerender', 'false')
929
- }
930
- res.render(module, req, res, module.$metadata)
931
- })
932
- ${equalparamroute.length > 0 ? equalparamroute.map((e) => {
933
-
934
-
935
-
936
- return `router.get('${e.url}', async (req, res) => {
937
- let module = await import('/${e.fileName.replace('.jsx', '.js')}')
938
- res.render(module, req, res, module.$metadata)
939
- })\n`
940
- }) : ''}
941
- router.listen(3000)
942
-
943
- </script>
944
- </head>
945
- <body>
946
- <div id="root"></div>
947
- </body>
948
-
949
-
950
- </html>
951
- `;
952
-
953
- // generate random but common ports
954
- let port = Math.floor(Math.random() * (65535 - 49152 + 1) + 49152)
955
-
956
- const server = http.createServer((req, res) => {
863
+ });
864
+ }
865
+ });
957
866
 
958
- if (req.url === '/') {
959
- res.writeHead(200, { 'Content-Type': 'text/html' });
960
- res.end(document);
961
- } else {
962
- // Serve static files (adjust the file paths based on your project structure)
963
- const filePath = process.cwd() + '/dist/' + req.url
964
-
965
- fs.readFile(filePath, (err, data) => {
966
- if (err) {
967
- res.writeHead(404, { 'Content-Type': filePath.includes('js') ? 'text/javascript' : 'text/html' });
968
- res.end('File not found');
969
- } else {
970
- res.writeHead(200, { 'Content-Type': filePath.includes('js') ? 'text/javascript' : 'text/html' });
971
- res.end(data);
972
- }
973
- });
974
- }
975
- });
867
+ let port = 12000
868
+ server.on('error', (err) => {
869
+ if (err.code === 'EADDRINUSE') {
870
+ setTimeout(() => {
871
+ server.close();
872
+ server.listen(++port);
873
+ }, 1000);
874
+ }
875
+ })
976
876
 
977
- server.listen(port)
978
- server.on('error', (err) => {
979
- if (err.code === 'EADDRINUSE') {
980
- console.log(`Port ${port} is in use, trying another port...`);
981
- setTimeout(() => {
982
- server.close();
983
- server.listen(++port);
984
- }, 1000);
985
- }
986
- })
877
+ const browser = puppeteer.launch({
878
+ headless: "new", args: ['--no-sandbox', '--disable-setuid-sandbox'],
879
+ warning: false,
880
+ })
881
+ server.listen(port);
987
882
 
883
+ routes.forEach(async (route) => {
884
+ if (route.url.includes(':')) {
885
+ return
886
+ }
988
887
  globalThis.listen = true;
989
888
 
990
- const browser = await puppeteer.launch({
991
- headless: "new", args: ['--no-sandbox', '--disable-setuid-sandbox'],
992
- warning: false,
993
- })
994
-
995
- const browserPID = browser.process().pid
996
889
  try {
997
890
 
998
891
  route.url = route.url.replaceAll(/\/:[a-zA-Z0-9_-]+/gs, '')
999
- let page = await browser.newPage();
1000
- await page.goto(`http://localhost:${port}/`, { waitUntil: 'networkidle2' });
1001
- await page.on('console', msg => console.log('PAGE LOG:', msg.text()));
1002
- await page.on('error', err => console.log('PAGE LOG:', err));
1003
- await page.on('pageerror', err => console.log('PAGE LOG:', err));
1004
- await page.evaluate(() => {
1005
- window.onerror = function (msg, url, lineNo, columnNo, error) {
1006
- console.log(msg, url, lineNo, columnNo, error)
892
+ let page = (await browser).newPage()
893
+ page.then(async (page) => {
894
+ page.on('error', (err) => {
895
+ console.error('JS ERROR:', JSON.parse(err));
896
+ });
897
+ try {
898
+ page.on('pageerror', async err => {
899
+ let errorObj = JSON.parse(await page.evaluate(() => document.documentElement.getAttribute('error')) || '{}')
900
+ console.log('\x1b[31m%s\x1b[0m', 'Compiler Error:', errorObj)
901
+
902
+ console.log('\x1b[31m%s\x1b[0m', 'Error:', err)
903
+ });
904
+ } catch (error) {
905
+ page.close()
1007
906
  }
907
+ page.on('crash', () => {
908
+ console.error(`Render process crashed for ${route.url}`)
909
+ });
910
+
911
+ await page.goto(`http://localhost:${port}${route.url}`, { waitUntil: 'networkidle2' });
912
+
913
+ page.evaluate(() => {
914
+ document.querySelector('#meta').remove()
915
+ document.querySelector('#isServer').innerHTML = 'window.isServer = false'
916
+ if (document.head.getAttribute('prerender') === 'false') {
917
+ document.querySelector('#root').innerHTML = ''
918
+ console.log(`Disabled prerendering for ${window.location.pathname}`)
919
+ }
920
+ })
921
+ let html = await page.content();
922
+
923
+ html = await prettier.format(html, { parser: "html" })
924
+
925
+ writer(process.cwd() + '/dist/' + (route.url === '/' ? 'index.html' : `${route.url}/` + 'index.html'), html)
926
+
927
+ console.log(`\x1b[32m%s\x1b[0m`, `Prerendered ${route.url}...`)
928
+
929
+ hasRendered.push(route.url)
1008
930
  })
1009
- await page.waitForSelector('#root', { timeout: 10000 })
1010
- await page.evaluate(() => {
1011
- document.getElementById('meta').remove()
1012
- document.querySelector('#isServer').innerHTML = 'window.isServer = false'
1013
- if (document.head.getAttribute('prerender') === 'false') {
1014
- document.querySelector('#root').innerHTML = ''
1015
- console.log(`Disabled prerendering for ${window.location.pathname}`)
1016
- }
1017
- })
1018
- const html = await page.content();
1019
931
 
1020
- await page.close();
1021
- await writer(process.cwd() + '/dist/' + (route.url === '/' ? 'index.html' : `${route.url}/` + 'index.html'), html)
1022
- await browser.close();
1023
- server.close()
932
+
933
+
1024
934
 
1025
935
  } catch (error) {
1026
- server.close()
1027
- await browser.close();
936
+ console.log('\x1b[31m%s\x1b[0m', 'Error:', error)
937
+
1028
938
  }
1029
939
  finally {
1030
- await browser.close();
1031
- server.close()
1032
- }
1033
- try {
1034
- process.kill(browserPID)
1035
- } catch (error) {
1036
940
  }
941
+ })
942
+
943
+
1037
944
 
1038
945
 
1039
- })
1040
946
 
1041
- let timeout = setTimeout(() => {
947
+ function kill() {
948
+ console.log(`\x1b[32m%s\x1b[0m`, `\nPrerendered ${routes.length} pages...\n`)
949
+ server.close()
950
+ browser.then((browser) => {
951
+ browser.close()
952
+ })
953
+ hasRendered = []
1042
954
  globalThis.isBuilding = false
1043
- clearTimeout(timeout)
1044
- }, 1000)
1045
- console.log(`Generated ${routes.length} html files for ${routes.length} routes`)
1046
- }
955
+ globalThis.isProduction ? console.log(`Total Bundle Size: ${Math.round(bundleSize / 1000)}kb`) : null
956
+ bundleSize = 0
957
+ }
1047
958
 
959
+ if (hasRendered.length === routes.length) {
960
+ kill()
961
+ } else {
962
+ console.log(`\x1b[32m%s\x1b[0m`, `Prerendering ${routes.length} pages...\n`)
963
+ let interval = setInterval(() => {
964
+ if (hasRendered.length === routes.length) {
965
+ kill()
966
+ clearInterval(interval)
967
+ }
968
+ }, 1000);
969
+ }
970
+ }
1048
971
  globalThis.routes = []
1049
972
 
1050
973
  for await (let file of glb) {
@@ -1074,16 +997,15 @@ async function Build() {
1074
997
 
1075
998
 
1076
999
  let data = await fs.readFileSync(origin, "utf8");
1077
- data = Compiler(data, origin);
1078
-
1079
-
1080
- await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), data).then(async () => {
1081
-
1082
-
1083
1000
 
1084
- await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), data)
1085
-
1086
- })
1001
+ // gen sourcemap if not production
1002
+ let size = fs.statSync(origin).size;
1003
+ if (!globalThis.isProduction) {
1004
+ let { sourceMap } = sourceMapGen({ origin: origin, fileName: fileName }, await Compiler(data, origin))
1005
+ data = data + `\n//# sourceMappingURL=/src/maps/${fileName.replace('.jsx', '.js.map')}\n //#sourceURL=${origin}`
1006
+ await writer(process.cwd() + "/dist/src/maps/" + fileName.replace('.jsx', '.js.map'), JSON.stringify(sourceMap, null, 2))
1007
+ }
1008
+ await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), await Compiler(data, origin))
1087
1009
 
1088
1010
  // configure routing for each page
1089
1011
 
@@ -1145,13 +1067,108 @@ async function Build() {
1145
1067
  }
1146
1068
 
1147
1069
 
1148
- globalThis.routes.push({ fileName: fileName, url: obj.url, html: '/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html') })
1070
+ if (!obj.url.includes(':')) {
1071
+ globalThis.routes.push({ fileName: fileName, url: obj.url, html: '/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html') })
1072
+ }
1073
+
1149
1074
 
1075
+ let stats = {
1076
+ route: obj.url.padEnd(30),
1077
+ size: Math.round(size / 1000) + 'kb',
1078
+ letParentFolder: obj.url.split('/').slice(0, -1).join('/'),
1079
+ isChildRoute: obj.url.split('/').slice(0, -1).join('/').includes(':') ? true : false,
1080
+ parentRoute: obj.url.split('/').slice(0, -1).join('/').split(':')[0],
1150
1081
 
1082
+ }
1083
+ stats.isChildRoute ? stats.route = `? ${obj.url}` : null
1084
+ let string = `${isBasePath ? '+' : '+'} ${stats.route.padEnd(30)} ${stats.size}`
1151
1085
 
1086
+ globalThis.isProduction ? console.log(string) : null
1152
1087
  }
1153
1088
 
1154
- ssg(globalThis.routes)
1089
+ globalThis.routeDocuments = []
1090
+ globalThis.routes.map((route) => {
1091
+ let equalparamroute = globalThis.routes.map((e) => {
1092
+ if (e.url.includes(':')) {
1093
+ let url = e.url.split('/:')[0]
1094
+ if (url && route.url === url) {
1095
+ return e
1096
+ } else {
1097
+ return null
1098
+
1099
+ }
1100
+ }
1101
+ return null
1102
+ }).filter(Boolean)
1103
+ let document = `
1104
+ <!DOCTYPE html>
1105
+ <html lang="en">
1106
+ <head>
1107
+ <script>
1108
+ window.routes = JSON.parse('${JSON.stringify(globalThis.routes)}')
1109
+ </script>
1110
+ <script type="module" id="meta">
1111
+ window.history.pushState({}, '', '${route.url}')
1112
+
1113
+ </script>
1114
+ <script id="isServer">
1115
+ window.isServer = true
1116
+ </script>
1117
+ <meta charset="UTF-8">
1118
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
1119
+
1120
+ <script type="module" id="router">
1121
+ import VaderRouter from '/router.js'
1122
+ const router = new VaderRouter('${route.url}')
1123
+ router.get('${route.url}', async (req, res) => {
1124
+ try{
1125
+ let module = await import('/${route.fileName.replace('.jsx', '.js')}')
1126
+ if(Object.keys(module).includes('$prerender') && !module.$prerender){
1127
+ document.head.setAttribute('prerender', 'false')
1128
+ }
1129
+ res.render(module, req, res, module.$metadata)
1130
+ }
1131
+ catch(error){
1132
+ let errorMessage = {
1133
+ message: error.message,
1134
+ name: error.name,
1135
+ stack: error.stack,
1136
+ path: window.location.pathname
1137
+ };
1138
+
1139
+
1140
+ document.documentElement.setAttribute('error', JSON.stringify(errorMessage));
1141
+ throw new Error(error)
1142
+ }
1143
+ })
1144
+ ${equalparamroute.length > 0 ? equalparamroute.map((e) => {
1145
+
1146
+
1147
+
1148
+ return `router.get('${e.url}', async (req, res) => {
1149
+ let module = await import('/${e.fileName.replace('.jsx', '.js')}')
1150
+ res.render(module, req, res, module.$metadata)
1151
+ })\n`
1152
+ }) : ''}
1153
+ router.listen(3000)
1154
+
1155
+ </script>
1156
+ </head>
1157
+ <body>
1158
+ <div id="root"></div>
1159
+ </body>
1160
+
1161
+
1162
+ </html>
1163
+ `;
1164
+ globalThis.routeDocuments.push({ url: route.url, document: document })
1165
+ })
1166
+
1167
+ if(globalThis.devMode && !globalThis.oneAndDone){
1168
+ ssg(globalThis.routes)
1169
+ globalThis.oneAndDone = true
1170
+ console.log('Prerendering...')
1171
+ }
1155
1172
 
1156
1173
 
1157
1174
  const scannedSourceFiles = await glob("**/**.{jsx,js,json}", {
@@ -1179,23 +1196,25 @@ async function Build() {
1179
1196
  scannedSourceFiles.forEach(async (file) => {
1180
1197
  file = file.replace(/\\/g, '/');
1181
1198
  let name = file.split('/src/')[1]
1182
- //parse jsx
1183
1199
 
1184
1200
  let data = await reader(process.cwd() + "/src/" + name)
1185
1201
  if (name.includes('.jsx')) {
1186
- data = Compiler(data, process.cwd() + "/src/" + name);
1187
-
1188
- await writer(process.cwd() + "/dist/src/" + name.split('.jsx').join('.js'), data).then(async () => {
1189
- await writer(process.cwd() + "/dist/src/" + name.replace('.jsx', '.js'), data)
1190
-
1191
- })
1202
+ let origin = process.cwd() + "/src/" + name
1203
+ if (!globalThis.isProduction) {
1204
+ let { sourceMap } = sourceMapGen({ origin: origin, fileName: name }, await Compiler(data, origin))
1205
+ data = data + `\n//# sourceMappingURL=/src/maps/${name.replace('.jsx', '.js.map')}\n //#sourceURL=${origin}`
1206
+ await writer(process.cwd() + "/dist/src/maps/" + name.replace('.jsx', '.js.map'), JSON.stringify(sourceMap, null, 2))
1207
+ }
1208
+ await writer(process.cwd() + "/dist/src/" + name.split('.jsx').join('.js'), await Compiler(data, origin))
1192
1209
  return
1193
1210
  }
1194
- bundleSize += fs.statSync(process.cwd() + "/src/" + name).size;
1211
+ if (!name.includes('.map')) {
1212
+ bundleSize += fs.statSync(process.cwd() + "/src/" + name).size;
1213
+ }
1195
1214
  await writer(process.cwd() + "/dist/src/" + name, data);
1196
1215
  })
1197
1216
 
1198
- const scannedPublicFiles = await glob("**/**.{css,js,html,mjs,cjs}", {
1217
+ const scannedPublicFiles = await glob("**/**/**.{css,js,html,mjs,cjs,png,jpg,jpeg,gif,svg,mp4,webm,ogg}", {
1199
1218
  ignore: ["node_modules/**/*", "dist/**/*"],
1200
1219
  cwd: process.cwd() + '/public/',
1201
1220
  absolute: true,
@@ -1203,7 +1222,7 @@ async function Build() {
1203
1222
  scannedPublicFiles.forEach(async (file) => {
1204
1223
  file = file.replace(/\\/g, '/');
1205
1224
  file = file.split('/public/')[1]
1206
- let data = await reader(process.cwd() + "/public/" + file)
1225
+ let data = fs.readFileSync(process.cwd() + "/public/" + file);
1207
1226
  bundleSize += fs.statSync(process.cwd() + "/public/" + file).size;
1208
1227
  await writer(process.cwd() + "/dist/public/" + file, data);
1209
1228
  })
@@ -1236,17 +1255,16 @@ async function Build() {
1236
1255
  }
1237
1256
 
1238
1257
  globalThis.isBuilding = false
1239
- console.log(`📦 Build completed: Build Size -> ${Math.round(bundleSize / 1000)}kb`)
1240
1258
 
1241
1259
  bundleSize = 0;
1242
1260
 
1243
1261
  return true
1244
1262
  }
1245
- const s = () => {
1263
+ const s = (port) => {
1246
1264
 
1247
1265
  const server = http.createServer((req, res) => {
1248
1266
 
1249
- const validExtensions = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg'];
1267
+ const validExtensions = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg', '.map']
1250
1268
 
1251
1269
  if (!validExtensions.some(ext => req.url.endsWith(ext))) {
1252
1270
  req.url = req.url !== '/' ? req.url.split('/')[1] : req.url;
@@ -1269,6 +1287,7 @@ const s = () => {
1269
1287
  let ws = new WebSocket('ws://localhost:${process.env.PORT || 3000}')
1270
1288
  ws.onmessage = (e) => {
1271
1289
  if(e.data === 'reload'){
1290
+ console.log('Reloading...')
1272
1291
  window.location.reload()
1273
1292
  }
1274
1293
  }
@@ -1290,7 +1309,7 @@ const s = () => {
1290
1309
 
1291
1310
 
1292
1311
  function getContentType(filePath) {
1293
- let ext = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg'].includes(path.extname(filePath)) ? path.extname(filePath) : '.html'
1312
+ let ext = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg', '.map'].includes(path.extname(filePath)) ? path.extname(filePath) : '.html'
1294
1313
  switch (ext) {
1295
1314
  case '.js':
1296
1315
  return 'text/javascript';
@@ -1302,6 +1321,8 @@ const s = () => {
1302
1321
  return 'text/javascript';
1303
1322
  case '.html':
1304
1323
  return 'text/html';
1324
+ case '.map':
1325
+ return 'application/json';
1305
1326
  case '.json':
1306
1327
  return 'application/json';
1307
1328
  case '.png':
@@ -1324,35 +1345,30 @@ const s = () => {
1324
1345
  return 'application/octet-stream';
1325
1346
  }
1326
1347
  }
1327
-
1328
- const PORT = process.env.PORT || 3000;
1329
- server.listen(PORT, () => {
1330
- console.log(`Server is running on port ${PORT}`);
1348
+
1349
+ server.listen(port, () => {
1350
+ console.log(`Server is running on port ${port}`);
1351
+ globalThis.ws = ws
1331
1352
  });
1332
- let i =
1333
- setInterval(() => {
1334
- if (globalThis.isBuilding && globalThis.devMode) {
1335
1353
 
1336
- ws.clients.forEach((client) => {
1337
- client.send('reload')
1338
- })
1339
- } else {
1340
- clearInterval(i)
1341
- }
1342
- }, 120)
1343
1354
 
1344
1355
  }
1345
1356
 
1346
1357
 
1347
1358
  switch (true) {
1348
- case process.argv.includes('--watch') && !process.argv.includes('--build') && !process.argv.includes('--serve'):
1359
+ case process.argv.includes('dev') && !process.argv.includes('build') && !process.argv.includes('start'):
1349
1360
 
1350
1361
  globalThis.devMode = true
1362
+ globalThis.isProduction = false
1363
+
1364
+ let p = process.env.PORT || config.port || process.argv.includes('-p') ? process.argv[process.argv.indexOf('-p') + 1] : 3000
1365
+ globalThis.oneAndDone = false
1351
1366
  console.log(`
1352
- Vader.js v1.3.3
1367
+ Vader.js v${fs.readFileSync(process.cwd() + '/node_modules/vaderjs/package.json', 'utf8').split('"version": "')[1].split('"')[0]}
1353
1368
  - Watching for changes in ./pages
1354
1369
  - Watching for changes in ./src
1355
1370
  - Watching for changes in ./public
1371
+ - Serving on port ${p}
1356
1372
  `)
1357
1373
  !globalThis.isBuilding ? Build() : null
1358
1374
 
@@ -1364,51 +1380,63 @@ Vader.js v1.3.3
1364
1380
  if (event == 'change'
1365
1381
  && !globalThis.isBuilding
1366
1382
  ) {
1383
+ if (globalThis.ws && !globalThis.isWriting) {
1384
+ globalThis.ws.clients.forEach((client) => {
1385
+ console.log('Reloading...')
1386
+ client.send('reload')
1387
+ })
1388
+ }
1367
1389
 
1390
+ console.log('\nRebuilding...')
1391
+ globalThis.isBuilding = true
1368
1392
  Build()
1369
1393
  }
1370
1394
  }).on('error', (err) => console.log(err))
1371
- })
1372
- let p = process.argv[process.argv.indexOf('--watch') + 1] || process.env.PORT || 3000
1373
-
1374
- process.env.PORT = p
1375
- s()
1395
+ })
1396
+ s(p)
1376
1397
 
1377
1398
  globalThis.listen = true;
1378
1399
 
1379
1400
  break;
1380
- case process.argv.includes('--build') && !process.argv.includes('--watch') && !process.argv.includes('--serve'):
1401
+ case process.argv.includes('build') && !process.argv.includes('dev') && !process.argv.includes('start'):
1381
1402
  globalThis.devMode = false
1403
+ globalThis.isProduction = true
1404
+ globalThis.routeStates = []
1382
1405
  console.log(`
1383
1406
  Vader.js v1.3.3
1384
1407
  Building to ./dist
1385
1408
  `)
1409
+ if (fs.existsSync(process.cwd() + '/dist/src/maps')) {
1410
+ fs.rmSync(process.cwd() + '/dist/src/maps', { recursive: true })
1411
+ }
1386
1412
  Build()
1387
1413
 
1388
1414
  break;
1389
- case process.argv.includes('--serve') && !process.argv.includes('--watch') && !process.argv.includes('--build'):
1390
- let port = process.argv[process.argv.indexOf('--serve') + 1] || 3000
1391
- process.env.PORT = port
1415
+ case process.argv.includes('start') && !process.argv.includes('dev') && !process.argv.includes('build'):
1416
+ let port = process.env.PORT || config.port || process.argv.includes('-p') ? process.argv[process.argv.indexOf('-p') + 1] : 3000
1417
+ console.log(port)
1392
1418
  globalThis.devMode = false
1393
1419
  console.log(`
1394
1420
  Vader.js v1.3.3
1395
1421
  Serving ./dist on port ${port}
1396
1422
  url: http://localhost:${port}
1397
1423
  `)
1398
- s()
1424
+ s(port)
1399
1425
  break;
1400
1426
  default:
1401
- console.log(`
1427
+ // add color
1428
+ console.log(`
1402
1429
  Vader.js is a reactive framework for building interactive applications for the web built ontop of bun.js!
1403
1430
 
1404
1431
  Usage: vader <command>
1405
1432
 
1406
1433
  Commands:
1407
- --watch (port) Watch the pages folder for changes with hot reloading
1434
+
1435
+ vaderjs dev -p <number> Start the development server
1408
1436
 
1409
- --build Build the project to ./dist
1437
+ vaderjs build Build the project to ./dist
1410
1438
 
1411
- --serve (400) Serve the project on a port (default 3000 or process.env.PORT)
1439
+ vaderjs start -p <number> Production Mode (default 3000 or process.env.PORT)
1412
1440
 
1413
1441
  Learn more about vader: https://vader-js.pages.dev/
1414
1442