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/client/index.js +221 -222
- package/package.json +4 -2
- package/runtime/router.js +1 -1
- package/runtime/vader.js +1 -1
- package/vader.js +462 -434
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
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
//
|
|
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*("([^"\\]*(
|
|
120
|
-
|
|
121
|
-
// <div $={{color: 'red'}}></div>
|
|
96
|
+
/\s*([a-zA-Z0-9_-]+)(\s*=\s*("(?:[^"\\]*(?:\\.[^"\\]*)*)"|'(?:[^'\\]*(?:\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}|(?:\([^)]*\)|\{[^}]*\}|()=>\s*(?:\{[^}]*\})?)|\[[^\]]*\]))?/gs;
|
|
122
97
|
|
|
123
98
|
|
|
124
99
|
|
|
125
|
-
|
|
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
|
-
|
|
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("=>")
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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
|
-
|
|
517
|
-
|
|
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 =
|
|
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}, {${
|
|
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
|
-
|
|
597
|
-
let
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
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
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
let
|
|
628
|
-
let
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
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('
|
|
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
|
-
|
|
842
|
-
|
|
843
|
-
if (route
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
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
|
-
|
|
858
|
-
|
|
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
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
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
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
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
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
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
|
-
|
|
1021
|
-
|
|
1022
|
-
await browser.close();
|
|
1023
|
-
server.close()
|
|
932
|
+
|
|
933
|
+
|
|
1024
934
|
|
|
1025
935
|
} catch (error) {
|
|
1026
|
-
|
|
1027
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
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
|
-
|
|
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("
|
|
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 =
|
|
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
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
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('
|
|
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
|
|
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
|
-
|
|
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('
|
|
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('
|
|
1390
|
-
let port = process.argv[process.argv.indexOf('
|
|
1391
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1434
|
+
|
|
1435
|
+
vaderjs dev -p <number> Start the development server
|
|
1408
1436
|
|
|
1409
|
-
|
|
1437
|
+
vaderjs build Build the project to ./dist
|
|
1410
1438
|
|
|
1411
|
-
|
|
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
|
|