vaderjs 1.3.3-7924566dd811 → 1.3.3-7b27417d42e1
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 +471 -444
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
|
-
|
|
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*/, "");
|
|
81
|
-
|
|
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
82
|
|
|
106
|
-
|
|
83
|
+
// or : value boolean variable etc
|
|
84
|
+
const spreadAttributeRegex = /\s*([a-zA-Z0-9_-]+)\s*(\$\s*=\s*\{\s*\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}\s*\})/gs;
|
|
107
85
|
|
|
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
|
|
|
@@ -437,85 +482,44 @@ function Compiler(func, file) {
|
|
|
437
482
|
|
|
438
483
|
let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
|
|
439
484
|
let componentAttributes = component.split("<")[1].split(">")[0].split(" ").join(" ").replace(name, "").trim();
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
let props = component.match(dynamicAttributesRegex)
|
|
447
|
-
|
|
448
|
-
let filteredProps = [];
|
|
449
|
-
let isWithinComponent = false;
|
|
450
|
-
let componentName = name
|
|
451
|
-
let currentProps = []
|
|
452
|
-
|
|
453
|
-
let $_ternaryprops = []
|
|
454
|
-
|
|
455
|
-
for (let prop of props) {
|
|
485
|
+
let props = component.includes('/>')? component.split(`<`)[1].split('/>')[0] : component.split(`<`)[1].split(`>`)[1].split(`</${name}`)[0].trim()
|
|
486
|
+
props = props.replaceAll(/\s+/g, " ").trim()
|
|
487
|
+
props = props.replace(name, '').trim()
|
|
488
|
+
component = component.replace(componentAttributes, '')
|
|
489
|
+
const dynamicAttributesRegex = /([a-zA-Z0-9_-]+)\s*=\s*("(?:[^"\\]*(?:\\.[^"\\]*)*)"|'(?:[^'\\]*(?:\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{(.*.*?)\})*)*\})*)*\}|(?:\([^)]*\)|()\s*=>\s*(?:\{.*.*\})?|\{.*\})|\[[^\]]*\])/gs;
|
|
456
490
|
|
|
457
|
-
|
|
491
|
+
const attributeObject = {};
|
|
458
492
|
|
|
459
|
-
|
|
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
|
-
|
|
513
|
-
}
|
|
493
|
+
let $_ternaryprops = []
|
|
514
494
|
|
|
495
|
+
let match;
|
|
496
|
+
let propstring = ''
|
|
497
|
+
// props right now is just a string with all of them on one line and a space between each
|
|
498
|
+
while ((match = dynamicAttributesRegex.exec(props)) !== null) {
|
|
499
|
+
let str = match[0].trim().replace(/\s+/g, " ");
|
|
500
|
+
if (!str.includes('=')) {
|
|
501
|
+
continue
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
str = str.replaceAll(/\s+/g, " ")
|
|
506
|
+
str = str.split('=')
|
|
507
|
+
let key = str[0].trim()
|
|
508
|
+
let value = str.slice(1).join('=').trim().match(/\{.*\}/gs) ? str.slice(1).join('=').trim().match(/\{.*\}/gs)[0] : str.slice(1).join('=').trim();
|
|
515
509
|
|
|
516
|
-
|
|
517
|
-
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
let isObject = value.startsWith('{{') && value.endsWith('}}')
|
|
513
|
+
if (isObject) {
|
|
514
|
+
value = value.split('{{')[1].split('}}')[0].trim()
|
|
515
|
+
value = `{${value}}`
|
|
516
|
+
propstring += `${key}:${value},`
|
|
517
|
+
} else {
|
|
518
|
+
// remove starting { and ending } using regex
|
|
519
|
+
value = value.replace(/^{/, '').replace(/}$/, '')
|
|
520
|
+
propstring += `${key}:${value},`
|
|
518
521
|
}
|
|
522
|
+
|
|
519
523
|
}
|
|
520
524
|
component = component.replaceAll(/\s+/g, " ");
|
|
521
525
|
|
|
@@ -524,10 +528,9 @@ function Compiler(func, file) {
|
|
|
524
528
|
component = component.replace(prop, '')
|
|
525
529
|
})
|
|
526
530
|
|
|
527
|
-
let children =
|
|
531
|
+
let children = new RegExp(`<${name}[^>]*>([^]*)<\/${name}>`, 'gs').exec(component)?.[1] || null;
|
|
528
532
|
|
|
529
533
|
|
|
530
|
-
props = filteredProps.join(',').replace(/\s+/g, " ").trim().replace(/,$/, '')
|
|
531
534
|
|
|
532
535
|
let savedname = name;
|
|
533
536
|
|
|
@@ -560,24 +563,15 @@ function Compiler(func, file) {
|
|
|
560
563
|
|
|
561
564
|
|
|
562
565
|
|
|
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('={', ':')
|
|
566
|
+
propstring = propstring.replace(/,$/, '')
|
|
572
567
|
|
|
573
568
|
|
|
574
569
|
/**
|
|
575
570
|
* @memoize - memoize a component to be remembered on each render and replace the old jsx
|
|
576
571
|
*/
|
|
577
572
|
|
|
578
|
-
|
|
579
573
|
let replace = "";
|
|
580
|
-
replace = `\${this.memoize(this.createComponent(${savedname}, {${
|
|
574
|
+
replace = `\${this.memoize(this.createComponent(${savedname}, {${propstring}}, [\`${myChildrens.join('')}\`]))}`;
|
|
581
575
|
|
|
582
576
|
|
|
583
577
|
body = body.replace(before, replace);
|
|
@@ -593,48 +587,49 @@ function Compiler(func, file) {
|
|
|
593
587
|
let replaceMents = [];
|
|
594
588
|
|
|
595
589
|
|
|
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
|
-
|
|
590
|
+
if(imports){
|
|
591
|
+
for (let match of imports) {
|
|
592
|
+
let path = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
|
|
593
|
+
switch (true) {
|
|
594
|
+
case path && !path.includes('./') && !path.includes('/vader.js') && !path.includes('/vaderjs/client') && !path.startsWith('src') && !path.startsWith('public') && !path.includes('http') && !path.includes('https'):
|
|
595
|
+
let componentFolder = fs.existsSync(process.cwd() + '/node_modules/' + path) ? process.cwd() + '/node_modules/' + path : process.cwd() + '/node_modules/' + path.split('/')[0]
|
|
596
|
+
componentFolder = componentFolder.split(process.cwd())[1]
|
|
597
|
+
if (!fs.existsSync(process.cwd() + componentFolder)) {
|
|
598
|
+
throw new Error('Could not find ' + path + ' at ' + match + ' in file ' + file)
|
|
621
599
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
let
|
|
628
|
-
let
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
600
|
+
|
|
601
|
+
if (!fs.existsSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'))) {
|
|
602
|
+
fs.mkdirSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'), { recursive: true })
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
let baseFolder = componentFolder.split('node_modules')[1].split('/')[1]
|
|
606
|
+
let glp = globSync('**/**/**/**.{jsx,js}', {
|
|
607
|
+
cwd: process.cwd() + '/node_modules/' + baseFolder + '/',
|
|
608
|
+
absolute: true,
|
|
609
|
+
recursive: true
|
|
610
|
+
})
|
|
611
|
+
for (let file of glp) {
|
|
612
|
+
let text = fs.readFileSync(file, "utf8");
|
|
613
|
+
if (!file.endsWith('.js') && file.endsWith('.jsx')) {
|
|
614
|
+
text = Compiler(text, file);
|
|
615
|
+
|
|
616
|
+
}
|
|
617
|
+
let dest = file.split('node_modules')[1]
|
|
618
|
+
dest = dest.split(baseFolder)[1]
|
|
619
|
+
writer(process.cwd() + '/dist/src/' + baseFolder + dest, text)
|
|
620
|
+
let importname = match.split('import')[1].split('from')[0].trim()
|
|
621
|
+
let oldImportstring = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
|
|
622
|
+
let newImport = `/src/${baseFolder + dest}`
|
|
623
|
+
newImport = newImport.replaceAll('.jsx', '.js').replaceAll('\\', '/')
|
|
624
|
+
replaceMents.push({ match: oldImportstring, replace: newImport })
|
|
625
|
+
console.log(`📦 imported Node Package ${baseFolder} `)
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
break;
|
|
630
|
+
default:
|
|
631
|
+
break;
|
|
632
|
+
}
|
|
638
633
|
}
|
|
639
634
|
}
|
|
640
635
|
|
|
@@ -827,224 +822,146 @@ const glb = await glob("**/**/**/**.{jsx,js}", {
|
|
|
827
822
|
absolute: true,
|
|
828
823
|
recursive: true
|
|
829
824
|
});
|
|
825
|
+
let hasRendered = []
|
|
826
|
+
|
|
830
827
|
async function Build() {
|
|
831
828
|
globalThis.isBuilding = true
|
|
832
|
-
console.log('
|
|
829
|
+
console.log(globalThis.isProduction ? 'Creating Optimized Production Build\n' : '')
|
|
830
|
+
let str = `Page \t\t\t\t Size\n`
|
|
831
|
+
globalThis.isProduction ? console.log('\x1b[32m%s\x1b[0m', str) : null
|
|
833
832
|
let reader = async (file) => {
|
|
834
833
|
let text = await fs.readFileSync(file, "utf8");
|
|
835
834
|
return text;
|
|
836
835
|
};
|
|
837
836
|
|
|
838
|
-
|
|
837
|
+
|
|
838
|
+
|
|
839
839
|
function ssg(routes = []) {
|
|
840
840
|
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
|
|
841
|
+
let server = http.createServer((req, res) => {
|
|
842
|
+
let route = routes.find((e) => e.url === req.url)
|
|
843
|
+
if (route) {
|
|
844
|
+
let document = globalThis.routeDocuments.find((e) => e.url === req.url)
|
|
845
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
846
|
+
res.end(document.document);
|
|
847
|
+
} else {
|
|
848
|
+
const filePath = process.cwd() + '/dist/' + req.url
|
|
854
849
|
|
|
850
|
+
fs.readFile(filePath, (err, data) => {
|
|
851
|
+
if (err) {
|
|
852
|
+
res.writeHead(404, { 'Content-Type': filePath.includes('js') ? 'text/javascript' : 'text/html' });
|
|
853
|
+
res.end('File not found');
|
|
854
|
+
} else {
|
|
855
|
+
res.writeHead(200, { 'Content-Type': filePath.includes('js') ? 'text/javascript' : 'text/html' });
|
|
856
|
+
res.end(data);
|
|
855
857
|
}
|
|
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) => {
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
});
|
|
957
861
|
|
|
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
|
-
});
|
|
862
|
+
let port = 12000
|
|
863
|
+
server.on('error', (err) => {
|
|
864
|
+
if (err.code === 'EADDRINUSE') {
|
|
865
|
+
setTimeout(() => {
|
|
866
|
+
server.close();
|
|
867
|
+
server.listen(++port);
|
|
868
|
+
}, 1000);
|
|
869
|
+
}
|
|
870
|
+
})
|
|
976
871
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
server.close();
|
|
983
|
-
server.listen(++port);
|
|
984
|
-
}, 1000);
|
|
985
|
-
}
|
|
986
|
-
})
|
|
872
|
+
const browser = puppeteer.launch({
|
|
873
|
+
headless: "new", args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
874
|
+
warning: false,
|
|
875
|
+
})
|
|
876
|
+
server.listen(port);
|
|
987
877
|
|
|
878
|
+
routes.forEach(async (route) => {
|
|
879
|
+
if (route.url.includes(':')) {
|
|
880
|
+
return
|
|
881
|
+
}
|
|
988
882
|
globalThis.listen = true;
|
|
989
883
|
|
|
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
884
|
try {
|
|
997
885
|
|
|
998
886
|
route.url = route.url.replaceAll(/\/:[a-zA-Z0-9_-]+/gs, '')
|
|
999
|
-
let page = await browser.newPage()
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
887
|
+
let page = (await browser).newPage()
|
|
888
|
+
page.then(async (page) => {
|
|
889
|
+
page.on('error', (err) => {
|
|
890
|
+
console.error('JS ERROR:', JSON.parse(err));
|
|
891
|
+
});
|
|
892
|
+
try {
|
|
893
|
+
page.on('pageerror', async err => {
|
|
894
|
+
let errorObj = JSON.parse(await page.evaluate(() => document.documentElement.getAttribute('error')) || '{}')
|
|
895
|
+
console.log('\x1b[31m%s\x1b[0m', 'Compiler Error:', errorObj)
|
|
896
|
+
|
|
897
|
+
console.log('\x1b[31m%s\x1b[0m', 'Error:', err)
|
|
898
|
+
});
|
|
899
|
+
} catch (error) {
|
|
900
|
+
page.close()
|
|
1007
901
|
}
|
|
902
|
+
page.on('crash', () => {
|
|
903
|
+
console.error(`Render process crashed for ${route.url}`)
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
await page.goto(`http://localhost:${port}${route.url}`, { waitUntil: 'networkidle2' });
|
|
907
|
+
|
|
908
|
+
page.evaluate(() => {
|
|
909
|
+
document.querySelector('#meta').remove()
|
|
910
|
+
document.querySelector('#isServer').innerHTML = 'window.isServer = false'
|
|
911
|
+
if (document.head.getAttribute('prerender') === 'false') {
|
|
912
|
+
document.querySelector('#root').innerHTML = ''
|
|
913
|
+
console.log(`Disabled prerendering for ${window.location.pathname}`)
|
|
914
|
+
}
|
|
915
|
+
})
|
|
916
|
+
let html = await page.content();
|
|
917
|
+
|
|
918
|
+
html = await prettier.format(html, { parser: "html" })
|
|
919
|
+
|
|
920
|
+
writer(process.cwd() + '/dist/' + (route.url === '/' ? 'index.html' : `${route.url}/` + 'index.html'), html)
|
|
921
|
+
|
|
922
|
+
console.log(`\x1b[32m%s\x1b[0m`, `Prerendered ${route.url}...`)
|
|
923
|
+
|
|
924
|
+
hasRendered.push(route.url)
|
|
1008
925
|
})
|
|
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
926
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
await browser.close();
|
|
1023
|
-
server.close()
|
|
927
|
+
|
|
928
|
+
|
|
1024
929
|
|
|
1025
930
|
} catch (error) {
|
|
1026
|
-
|
|
1027
|
-
|
|
931
|
+
console.log('\x1b[31m%s\x1b[0m', 'Error:', error)
|
|
932
|
+
|
|
1028
933
|
}
|
|
1029
934
|
finally {
|
|
1030
|
-
await browser.close();
|
|
1031
|
-
server.close()
|
|
1032
|
-
}
|
|
1033
|
-
try {
|
|
1034
|
-
process.kill(browserPID)
|
|
1035
|
-
} catch (error) {
|
|
1036
935
|
}
|
|
936
|
+
})
|
|
1037
937
|
|
|
1038
938
|
|
|
1039
|
-
})
|
|
1040
939
|
|
|
1041
|
-
let timeout = setTimeout(() => {
|
|
1042
|
-
globalThis.isBuilding = false
|
|
1043
|
-
clearTimeout(timeout)
|
|
1044
|
-
}, 1000)
|
|
1045
|
-
console.log(`Generated ${routes.length} html files for ${routes.length} routes`)
|
|
1046
|
-
}
|
|
1047
940
|
|
|
941
|
+
|
|
942
|
+
function kill() {
|
|
943
|
+
console.log(`\x1b[32m%s\x1b[0m`, `\nPrerendered ${routes.length} pages...\n`)
|
|
944
|
+
server.close()
|
|
945
|
+
browser.then((browser) => {
|
|
946
|
+
browser.close()
|
|
947
|
+
})
|
|
948
|
+
hasRendered = []
|
|
949
|
+
globalThis.isBuilding = false
|
|
950
|
+
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
if (hasRendered.length === routes.length) {
|
|
954
|
+
kill()
|
|
955
|
+
} else {
|
|
956
|
+
console.log(`\x1b[32m%s\x1b[0m`, `Prerendering ${routes.length} pages...\n`)
|
|
957
|
+
let interval = setInterval(() => {
|
|
958
|
+
if (hasRendered.length === routes.length) {
|
|
959
|
+
kill()
|
|
960
|
+
clearInterval(interval)
|
|
961
|
+
}
|
|
962
|
+
}, 1000);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
1048
965
|
globalThis.routes = []
|
|
1049
966
|
|
|
1050
967
|
for await (let file of glb) {
|
|
@@ -1074,16 +991,15 @@ async function Build() {
|
|
|
1074
991
|
|
|
1075
992
|
|
|
1076
993
|
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
994
|
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
995
|
+
// gen sourcemap if not production
|
|
996
|
+
let size = fs.statSync(origin).size;
|
|
997
|
+
if (!globalThis.isProduction) {
|
|
998
|
+
let { sourceMap } = sourceMapGen({ origin: origin, fileName: fileName }, await Compiler(data, origin))
|
|
999
|
+
data = data + `\n//# sourceMappingURL=/src/maps/${fileName.replace('.jsx', '.js.map')}\n //#sourceURL=${origin}`
|
|
1000
|
+
await writer(process.cwd() + "/dist/src/maps/" + fileName.replace('.jsx', '.js.map'), JSON.stringify(sourceMap, null, 2))
|
|
1001
|
+
}
|
|
1002
|
+
await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), await Compiler(data, origin))
|
|
1087
1003
|
|
|
1088
1004
|
// configure routing for each page
|
|
1089
1005
|
|
|
@@ -1145,13 +1061,111 @@ async function Build() {
|
|
|
1145
1061
|
}
|
|
1146
1062
|
|
|
1147
1063
|
|
|
1148
|
-
|
|
1064
|
+
if (!obj.url.includes(':')) {
|
|
1065
|
+
globalThis.routes.push({ fileName: fileName, url: obj.url, html: '/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html') })
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1149
1068
|
|
|
1069
|
+
let stats = {
|
|
1070
|
+
route: obj.url.padEnd(30),
|
|
1071
|
+
size: Math.round(size / 1000) + 'kb',
|
|
1072
|
+
letParentFolder: obj.url.split('/').slice(0, -1).join('/'),
|
|
1073
|
+
isChildRoute: obj.url.split('/').slice(0, -1).join('/').includes(':') ? true : false,
|
|
1074
|
+
parentRoute: obj.url.split('/').slice(0, -1).join('/').split(':')[0],
|
|
1150
1075
|
|
|
1076
|
+
}
|
|
1077
|
+
stats.isChildRoute ? stats.route = `? ${obj.url}` : null
|
|
1078
|
+
let string = `${isBasePath ? '+' : '+'} ${stats.route.padEnd(30)} ${stats.size}`
|
|
1151
1079
|
|
|
1080
|
+
globalThis.isProduction ? console.log(string) : null
|
|
1152
1081
|
}
|
|
1153
1082
|
|
|
1154
|
-
|
|
1083
|
+
globalThis.routeDocuments = []
|
|
1084
|
+
globalThis.routes.map((route) => {
|
|
1085
|
+
let equalparamroute = globalThis.routes.map((e) => {
|
|
1086
|
+
if (e.url.includes(':')) {
|
|
1087
|
+
let url = e.url.split('/:')[0]
|
|
1088
|
+
if (url && route.url === url) {
|
|
1089
|
+
return e
|
|
1090
|
+
} else {
|
|
1091
|
+
return null
|
|
1092
|
+
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
return null
|
|
1096
|
+
}).filter(Boolean)
|
|
1097
|
+
let document = `
|
|
1098
|
+
<!DOCTYPE html>
|
|
1099
|
+
<html lang="en">
|
|
1100
|
+
<head>
|
|
1101
|
+
<script>
|
|
1102
|
+
window.routes = JSON.parse('${JSON.stringify(globalThis.routes)}')
|
|
1103
|
+
</script>
|
|
1104
|
+
<script type="module" id="meta">
|
|
1105
|
+
window.history.pushState({}, '', '${route.url}')
|
|
1106
|
+
|
|
1107
|
+
</script>
|
|
1108
|
+
<script id="isServer">
|
|
1109
|
+
window.isServer = true
|
|
1110
|
+
</script>
|
|
1111
|
+
<meta charset="UTF-8">
|
|
1112
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
1113
|
+
|
|
1114
|
+
<script type="module" id="router">
|
|
1115
|
+
import VaderRouter from '/router.js'
|
|
1116
|
+
const router = new VaderRouter('${route.url}')
|
|
1117
|
+
router.get('${route.url}', async (req, res) => {
|
|
1118
|
+
try{
|
|
1119
|
+
let module = await import('/${route.fileName.replace('.jsx', '.js')}')
|
|
1120
|
+
if(Object.keys(module).includes('$prerender') && !module.$prerender){
|
|
1121
|
+
document.head.setAttribute('prerender', 'false')
|
|
1122
|
+
}
|
|
1123
|
+
res.render(module, req, res, module.$metadata)
|
|
1124
|
+
}
|
|
1125
|
+
catch(error){
|
|
1126
|
+
let errorMessage = {
|
|
1127
|
+
message: error.message,
|
|
1128
|
+
name: error.name,
|
|
1129
|
+
stack: error.stack,
|
|
1130
|
+
path: window.location.pathname
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
document.documentElement.setAttribute('error', JSON.stringify(errorMessage));
|
|
1135
|
+
throw new Error(error)
|
|
1136
|
+
}
|
|
1137
|
+
})
|
|
1138
|
+
${equalparamroute.length > 0 ? equalparamroute.map((e) => {
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
|
|
1142
|
+
return `router.get('${e.url}', async (req, res) => {
|
|
1143
|
+
let module = await import('/${e.fileName.replace('.jsx', '.js')}')
|
|
1144
|
+
res.render(module, req, res, module.$metadata)
|
|
1145
|
+
})\n`
|
|
1146
|
+
}) : ''}
|
|
1147
|
+
router.listen(3000)
|
|
1148
|
+
|
|
1149
|
+
</script>
|
|
1150
|
+
</head>
|
|
1151
|
+
<body>
|
|
1152
|
+
<div id="root"></div>
|
|
1153
|
+
</body>
|
|
1154
|
+
|
|
1155
|
+
|
|
1156
|
+
</html>
|
|
1157
|
+
`;
|
|
1158
|
+
globalThis.routeDocuments.push({ url: route.url, document: document })
|
|
1159
|
+
})
|
|
1160
|
+
|
|
1161
|
+
if(globalThis.devMode && !globalThis.oneAndDone){
|
|
1162
|
+
ssg(globalThis.routes)
|
|
1163
|
+
globalThis.oneAndDone = true
|
|
1164
|
+
console.log(`In Development Mode, Prerendering ${globalThis.routes.length} pages... Once`)
|
|
1165
|
+
}
|
|
1166
|
+
else if(globalThis.isProduction){
|
|
1167
|
+
ssg(globalThis.routes)
|
|
1168
|
+
}
|
|
1155
1169
|
|
|
1156
1170
|
|
|
1157
1171
|
const scannedSourceFiles = await glob("**/**.{jsx,js,json}", {
|
|
@@ -1179,23 +1193,25 @@ async function Build() {
|
|
|
1179
1193
|
scannedSourceFiles.forEach(async (file) => {
|
|
1180
1194
|
file = file.replace(/\\/g, '/');
|
|
1181
1195
|
let name = file.split('/src/')[1]
|
|
1182
|
-
//parse jsx
|
|
1183
1196
|
|
|
1184
1197
|
let data = await reader(process.cwd() + "/src/" + name)
|
|
1185
1198
|
if (name.includes('.jsx')) {
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
}
|
|
1199
|
+
let origin = process.cwd() + "/src/" + name
|
|
1200
|
+
if (!globalThis.isProduction) {
|
|
1201
|
+
let { sourceMap } = sourceMapGen({ origin: origin, fileName: name }, await Compiler(data, origin))
|
|
1202
|
+
data = data + `\n//# sourceMappingURL=/src/maps/${name.replace('.jsx', '.js.map')}\n //#sourceURL=${origin}`
|
|
1203
|
+
await writer(process.cwd() + "/dist/src/maps/" + name.replace('.jsx', '.js.map'), JSON.stringify(sourceMap, null, 2))
|
|
1204
|
+
}
|
|
1205
|
+
await writer(process.cwd() + "/dist/src/" + name.split('.jsx').join('.js'), await Compiler(data, origin))
|
|
1192
1206
|
return
|
|
1193
1207
|
}
|
|
1194
|
-
|
|
1208
|
+
if (!name.includes('.map')) {
|
|
1209
|
+
bundleSize += fs.statSync(process.cwd() + "/src/" + name).size;
|
|
1210
|
+
}
|
|
1195
1211
|
await writer(process.cwd() + "/dist/src/" + name, data);
|
|
1196
1212
|
})
|
|
1197
1213
|
|
|
1198
|
-
const scannedPublicFiles = await glob("
|
|
1214
|
+
const scannedPublicFiles = await glob("**/**/**.{css,js,html,mjs,cjs,png,jpg,jpeg,gif,svg,mp4,webm,ogg}", {
|
|
1199
1215
|
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
1200
1216
|
cwd: process.cwd() + '/public/',
|
|
1201
1217
|
absolute: true,
|
|
@@ -1203,7 +1219,7 @@ async function Build() {
|
|
|
1203
1219
|
scannedPublicFiles.forEach(async (file) => {
|
|
1204
1220
|
file = file.replace(/\\/g, '/');
|
|
1205
1221
|
file = file.split('/public/')[1]
|
|
1206
|
-
let data =
|
|
1222
|
+
let data = fs.readFileSync(process.cwd() + "/public/" + file);
|
|
1207
1223
|
bundleSize += fs.statSync(process.cwd() + "/public/" + file).size;
|
|
1208
1224
|
await writer(process.cwd() + "/dist/public/" + file, data);
|
|
1209
1225
|
})
|
|
@@ -1232,21 +1248,22 @@ async function Build() {
|
|
|
1232
1248
|
let data = await reader(process.cwd() + "/node_modules/vaderjs/runtime/" + file)
|
|
1233
1249
|
await writer(process.cwd() + "/dist/" + file, data);
|
|
1234
1250
|
});
|
|
1251
|
+
|
|
1235
1252
|
|
|
1236
1253
|
}
|
|
1237
1254
|
|
|
1238
1255
|
globalThis.isBuilding = false
|
|
1239
|
-
console.log(`📦 Build completed: Build Size -> ${Math.round(bundleSize / 1000)}kb`)
|
|
1240
1256
|
|
|
1257
|
+
globalThis.isProduction ? console.log(`Total Bundle Size: ${Math.round(bundleSize / 1000)}kb`) : null
|
|
1241
1258
|
bundleSize = 0;
|
|
1242
1259
|
|
|
1243
1260
|
return true
|
|
1244
1261
|
}
|
|
1245
|
-
const s = () => {
|
|
1262
|
+
const s = (port) => {
|
|
1246
1263
|
|
|
1247
1264
|
const server = http.createServer((req, res) => {
|
|
1248
1265
|
|
|
1249
|
-
const validExtensions = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg']
|
|
1266
|
+
const validExtensions = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg', '.map']
|
|
1250
1267
|
|
|
1251
1268
|
if (!validExtensions.some(ext => req.url.endsWith(ext))) {
|
|
1252
1269
|
req.url = req.url !== '/' ? req.url.split('/')[1] : req.url;
|
|
@@ -1269,6 +1286,7 @@ const s = () => {
|
|
|
1269
1286
|
let ws = new WebSocket('ws://localhost:${process.env.PORT || 3000}')
|
|
1270
1287
|
ws.onmessage = (e) => {
|
|
1271
1288
|
if(e.data === 'reload'){
|
|
1289
|
+
console.log('Reloading...')
|
|
1272
1290
|
window.location.reload()
|
|
1273
1291
|
}
|
|
1274
1292
|
}
|
|
@@ -1290,7 +1308,7 @@ const s = () => {
|
|
|
1290
1308
|
|
|
1291
1309
|
|
|
1292
1310
|
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'
|
|
1311
|
+
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
1312
|
switch (ext) {
|
|
1295
1313
|
case '.js':
|
|
1296
1314
|
return 'text/javascript';
|
|
@@ -1302,6 +1320,8 @@ const s = () => {
|
|
|
1302
1320
|
return 'text/javascript';
|
|
1303
1321
|
case '.html':
|
|
1304
1322
|
return 'text/html';
|
|
1323
|
+
case '.map':
|
|
1324
|
+
return 'application/json';
|
|
1305
1325
|
case '.json':
|
|
1306
1326
|
return 'application/json';
|
|
1307
1327
|
case '.png':
|
|
@@ -1324,35 +1344,30 @@ const s = () => {
|
|
|
1324
1344
|
return 'application/octet-stream';
|
|
1325
1345
|
}
|
|
1326
1346
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1347
|
+
|
|
1348
|
+
server.listen(port, () => {
|
|
1349
|
+
console.log(`Server is running on port ${port}`);
|
|
1350
|
+
globalThis.ws = ws
|
|
1331
1351
|
});
|
|
1332
|
-
let i =
|
|
1333
|
-
setInterval(() => {
|
|
1334
|
-
if (globalThis.isBuilding && globalThis.devMode) {
|
|
1335
1352
|
|
|
1336
|
-
ws.clients.forEach((client) => {
|
|
1337
|
-
client.send('reload')
|
|
1338
|
-
})
|
|
1339
|
-
} else {
|
|
1340
|
-
clearInterval(i)
|
|
1341
|
-
}
|
|
1342
|
-
}, 120)
|
|
1343
1353
|
|
|
1344
1354
|
}
|
|
1345
1355
|
|
|
1346
1356
|
|
|
1347
1357
|
switch (true) {
|
|
1348
|
-
case process.argv.includes('
|
|
1358
|
+
case process.argv.includes('dev') && !process.argv.includes('build') && !process.argv.includes('start'):
|
|
1349
1359
|
|
|
1350
1360
|
globalThis.devMode = true
|
|
1361
|
+
globalThis.isProduction = false
|
|
1362
|
+
|
|
1363
|
+
let p = process.env.PORT || config.port || process.argv.includes('-p') ? process.argv[process.argv.indexOf('-p') + 1] : 3000
|
|
1364
|
+
globalThis.oneAndDone = false
|
|
1351
1365
|
console.log(`
|
|
1352
|
-
Vader.js
|
|
1366
|
+
Vader.js v${fs.readFileSync(process.cwd() + '/node_modules/vaderjs/package.json', 'utf8').split('"version": "')[1].split('"')[0]}
|
|
1353
1367
|
- Watching for changes in ./pages
|
|
1354
1368
|
- Watching for changes in ./src
|
|
1355
1369
|
- Watching for changes in ./public
|
|
1370
|
+
- Serving on port ${p}
|
|
1356
1371
|
`)
|
|
1357
1372
|
!globalThis.isBuilding ? Build() : null
|
|
1358
1373
|
|
|
@@ -1364,51 +1379,63 @@ Vader.js v1.3.3
|
|
|
1364
1379
|
if (event == 'change'
|
|
1365
1380
|
&& !globalThis.isBuilding
|
|
1366
1381
|
) {
|
|
1382
|
+
if (globalThis.ws && !globalThis.isWriting) {
|
|
1383
|
+
globalThis.ws.clients.forEach((client) => {
|
|
1384
|
+
console.log('Reloading...')
|
|
1385
|
+
client.send('reload')
|
|
1386
|
+
})
|
|
1387
|
+
}
|
|
1367
1388
|
|
|
1389
|
+
console.log('\nRebuilding...')
|
|
1390
|
+
globalThis.isBuilding = true
|
|
1368
1391
|
Build()
|
|
1369
1392
|
}
|
|
1370
1393
|
}).on('error', (err) => console.log(err))
|
|
1371
|
-
})
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
process.env.PORT = p
|
|
1375
|
-
s()
|
|
1394
|
+
})
|
|
1395
|
+
s(p)
|
|
1376
1396
|
|
|
1377
1397
|
globalThis.listen = true;
|
|
1378
1398
|
|
|
1379
1399
|
break;
|
|
1380
|
-
case process.argv.includes('
|
|
1400
|
+
case process.argv.includes('build') && !process.argv.includes('dev') && !process.argv.includes('start'):
|
|
1381
1401
|
globalThis.devMode = false
|
|
1402
|
+
globalThis.isProduction = true
|
|
1403
|
+
globalThis.routeStates = []
|
|
1382
1404
|
console.log(`
|
|
1383
1405
|
Vader.js v1.3.3
|
|
1384
1406
|
Building to ./dist
|
|
1385
1407
|
`)
|
|
1408
|
+
if (fs.existsSync(process.cwd() + '/dist/src/maps')) {
|
|
1409
|
+
fs.rmSync(process.cwd() + '/dist/src/maps', { recursive: true })
|
|
1410
|
+
}
|
|
1386
1411
|
Build()
|
|
1387
1412
|
|
|
1388
1413
|
break;
|
|
1389
|
-
case process.argv.includes('
|
|
1390
|
-
let port = process.argv[process.argv.indexOf('
|
|
1391
|
-
|
|
1414
|
+
case process.argv.includes('start') && !process.argv.includes('dev') && !process.argv.includes('build'):
|
|
1415
|
+
let port = process.env.PORT || config.port || process.argv.includes('-p') ? process.argv[process.argv.indexOf('-p') + 1] : 3000
|
|
1416
|
+
console.log(port)
|
|
1392
1417
|
globalThis.devMode = false
|
|
1393
1418
|
console.log(`
|
|
1394
1419
|
Vader.js v1.3.3
|
|
1395
1420
|
Serving ./dist on port ${port}
|
|
1396
1421
|
url: http://localhost:${port}
|
|
1397
1422
|
`)
|
|
1398
|
-
s()
|
|
1423
|
+
s(port)
|
|
1399
1424
|
break;
|
|
1400
1425
|
default:
|
|
1401
|
-
|
|
1426
|
+
// add color
|
|
1427
|
+
console.log(`
|
|
1402
1428
|
Vader.js is a reactive framework for building interactive applications for the web built ontop of bun.js!
|
|
1403
1429
|
|
|
1404
1430
|
Usage: vader <command>
|
|
1405
1431
|
|
|
1406
1432
|
Commands:
|
|
1407
|
-
|
|
1433
|
+
|
|
1434
|
+
vaderjs dev -p <number> Start the development server
|
|
1408
1435
|
|
|
1409
|
-
|
|
1436
|
+
vaderjs build Build the project to ./dist
|
|
1410
1437
|
|
|
1411
|
-
|
|
1438
|
+
vaderjs start -p <number> Production Mode (default 3000 or process.env.PORT)
|
|
1412
1439
|
|
|
1413
1440
|
Learn more about vader: https://vader-js.pages.dev/
|
|
1414
1441
|
|