vaderjs 1.4.2-mpiml56 → 1.4.2-npiml56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -4
- package/binaries/Kalix/index.js +13 -3
- package/binaries/compiler/main.js +25 -13
- package/binaries/watcher/hmr.js +1 -0
- package/client/runtime/index.js +9 -1
- package/config/index.ts +20 -1
- package/package.json +1 -1
- package/plugins/cloudflare/functions/index.js +4 -0
- package/plugins/cloudflare/toCopy/@server/Kalix/index.js +62 -14
- package/plugins/cloudflare/toCopy/src/client.js +240 -252
- package/plugins/tailwindcss/index.ts +93 -0
- package/router/index.ts +22 -6
- package/server/index.js +15 -1
package/README.md
CHANGED
|
@@ -39,8 +39,8 @@ Keyword folders - all files are passed from these folders to the build folder
|
|
|
39
39
|
|
|
40
40
|
```md
|
|
41
41
|
1. pages - used for jsx route files
|
|
42
|
-
2. src - used for your jsx components / javascript files
|
|
43
|
-
3. public - used for anything
|
|
42
|
+
2. src - used for your jsx components / javascript -typescript files
|
|
43
|
+
3. public - used for anything / css / json etc
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
|
|
@@ -49,18 +49,28 @@ Keyword folders - all files are passed from these folders to the build folder
|
|
|
49
49
|
```ts
|
|
50
50
|
import { defineConfig } from "vaderjs/config";
|
|
51
51
|
import cloudflare from "vaderjs/plugins/cloudflare/functions"
|
|
52
|
+
import tailwindcss from "vaderjs/plugins/tailwindcss"
|
|
52
53
|
export default defineConfig({
|
|
53
54
|
target: "web",
|
|
54
55
|
host: {
|
|
55
56
|
hostname: "localhost",
|
|
56
|
-
provider:'cloudflare'
|
|
57
|
+
provider:'cloudflare' // used for ssg or ssr
|
|
57
58
|
},
|
|
58
59
|
env: {
|
|
59
60
|
PORT: 3000,
|
|
60
61
|
SSR: true,
|
|
61
62
|
apiRoute: "https://api.example.com"
|
|
62
63
|
},
|
|
63
|
-
|
|
64
|
+
Router: {
|
|
65
|
+
tls: {
|
|
66
|
+
cert: "cert.pem",
|
|
67
|
+
key: "key.pem"
|
|
68
|
+
},
|
|
69
|
+
headers: {
|
|
70
|
+
"cache-control": "public, max-age=0, must-revalidate"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
plugins: [cloudflare, tailwindcss],
|
|
64
74
|
});
|
|
65
75
|
|
|
66
76
|
```
|
package/binaries/Kalix/index.js
CHANGED
|
@@ -111,7 +111,7 @@ export class HTMLElement {
|
|
|
111
111
|
if (key !== 'style' && key !== 'ref' && !key.startsWith('on')) {
|
|
112
112
|
props += `${key}="${this.props[key]}" `
|
|
113
113
|
}
|
|
114
|
-
}
|
|
114
|
+
}
|
|
115
115
|
let children = this.children
|
|
116
116
|
.map((child) => {
|
|
117
117
|
return child.toString();
|
|
@@ -351,7 +351,7 @@ export class HTMLElement {
|
|
|
351
351
|
this.textContent = this.toString("innerText");
|
|
352
352
|
this.children.forEach((c) => {
|
|
353
353
|
if (c.children) {
|
|
354
|
-
child = c.children.find((child) => {
|
|
354
|
+
child = c.children.find((child) => {
|
|
355
355
|
child.outerHTML = child.toString("outerHTML");
|
|
356
356
|
child.innerHTML = child.toString("innerHTML");
|
|
357
357
|
return child.tagName === selector;
|
|
@@ -561,7 +561,17 @@ function handleStyles(styles, nodeEl) {
|
|
|
561
561
|
*/
|
|
562
562
|
export function Element(tag, props = {}, ...children) {
|
|
563
563
|
if(typeof tag === 'function'){
|
|
564
|
-
let
|
|
564
|
+
let childObj = children.map((child) => {
|
|
565
|
+
if (child.tagName === "TEXT_ELEMENT") {
|
|
566
|
+
return new HTMLTextNode(child);
|
|
567
|
+
}
|
|
568
|
+
if (child instanceof HTMLElement) {
|
|
569
|
+
return child;
|
|
570
|
+
}
|
|
571
|
+
return new HTMLElement(child.tagName, child.props, child.children);
|
|
572
|
+
})
|
|
573
|
+
childObj = childObj[0]
|
|
574
|
+
let el = tag({...props, children: childObj})
|
|
565
575
|
return el
|
|
566
576
|
}
|
|
567
577
|
if(props === null){
|
|
@@ -332,15 +332,8 @@ export async function Compile(){
|
|
|
332
332
|
copy = copy.replace(old, newStatereducer);
|
|
333
333
|
break;
|
|
334
334
|
case line.includes('vaderjs/client') && line.includes('import') || line.includes('vaderjs') && line.includes('import'):
|
|
335
|
-
let b4 = line
|
|
336
|
-
|
|
337
|
-
let replacement = isUsingProvider === 'cloudflare' ? 'remove' : '/src/client.js'
|
|
338
|
-
if(replacement === 'remove'){
|
|
339
|
-
copy = copy.replace(b4, '')
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
|
-
let after = line.replace('vaderjs/client', replacement).replace('vaderjs', replacement)
|
|
343
|
-
copy = copy.replace(b4, after)
|
|
335
|
+
let b4 = line
|
|
336
|
+
copy = copy.replace(b4, '')
|
|
344
337
|
break;
|
|
345
338
|
|
|
346
339
|
case line.includes('import') && !line.includes('vaderjs/client') && !line.includes('vaderjs') && !line.includes('import.meta') && !line.includes('import.meta.url') && !line.includes('import.meta.env'):
|
|
@@ -359,9 +352,7 @@ export async function Compile(){
|
|
|
359
352
|
|
|
360
353
|
}
|
|
361
354
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
355
|
+
|
|
365
356
|
return copy
|
|
366
357
|
}
|
|
367
358
|
|
|
@@ -450,6 +441,11 @@ export async function Compile(){
|
|
|
450
441
|
absolute: true,
|
|
451
442
|
ignore: ["**/node_modules/**"]
|
|
452
443
|
});
|
|
444
|
+
|
|
445
|
+
const publics = new Glob("/public/**/*", {
|
|
446
|
+
absolute: true,
|
|
447
|
+
ignore: ["**/node_modules/**"]
|
|
448
|
+
})
|
|
453
449
|
let srcArray = await Array.fromAsync(src.scan())
|
|
454
450
|
srcArray = srcArray.map((file) => {
|
|
455
451
|
file = file.replaceAll('\\', '/')
|
|
@@ -489,9 +485,25 @@ export async function Compile(){
|
|
|
489
485
|
});
|
|
490
486
|
})
|
|
491
487
|
file = file.split('/src')[1]
|
|
492
|
-
|
|
488
|
+
fs.mkdirSync(process.cwd() + '/build/src/' + file.split('/').slice(0, -1).join('/'), { recursive: true })
|
|
493
489
|
fs.writeFileSync(process.cwd() + '/build/src' + file, contents)
|
|
494
490
|
}
|
|
491
|
+
|
|
492
|
+
let publicArray = await Array.fromAsync(publics.scan())
|
|
493
|
+
publicArray = publicArray.map((file) => {
|
|
494
|
+
file = file.replaceAll('\\', '/')
|
|
495
|
+
file ='./' + file
|
|
496
|
+
return file
|
|
497
|
+
})
|
|
498
|
+
|
|
499
|
+
for(var file of publicArray){
|
|
500
|
+
file = file.split('/public')[1]
|
|
501
|
+
fs.mkdirSync(process.cwd() + '/build/public/' + file.split('/').slice(0, -1).join('/'), { recursive: true })
|
|
502
|
+
let out = `/build/public${file}`
|
|
503
|
+
let contents = await Bun.file(process.cwd() + '/public' + file).text()
|
|
504
|
+
fs.writeFileSync(process.cwd() + out, contents)
|
|
505
|
+
|
|
506
|
+
}
|
|
495
507
|
|
|
496
508
|
resolve()
|
|
497
509
|
})
|
package/binaries/watcher/hmr.js
CHANGED
|
@@ -17,6 +17,7 @@ export function watchDir(cwd, _){
|
|
|
17
17
|
continue;
|
|
18
18
|
}
|
|
19
19
|
watch(process.cwd() + '/' + path, { recursive: true, absolute:true }, (event, filename) => {
|
|
20
|
+
if(!filename.endsWith('.ts') && !filename.endsWith('.tsx') && !filename.endsWith('.js') && !filename.endsWith('.jsx')) return
|
|
20
21
|
if(filename && !filename.includes('node_modules') && !globalThis.hasLogged){
|
|
21
22
|
console.log(`\x1b[36mwait \x1b[0m - compiling (client and server)`)
|
|
22
23
|
globalThis.hasLogged = true
|
package/client/runtime/index.js
CHANGED
|
@@ -67,7 +67,14 @@ function generateJSX(tag, props, ...children) {
|
|
|
67
67
|
let comp = new Component({ $$key: node._key })
|
|
68
68
|
tag = tag.bind(comp)
|
|
69
69
|
comp.render = () => {
|
|
70
|
-
|
|
70
|
+
let childObj = children.map((child) => {
|
|
71
|
+
if (typeof child === 'function') {
|
|
72
|
+
return generateJSX(child, props, ...child.children)
|
|
73
|
+
}
|
|
74
|
+
return child
|
|
75
|
+
})
|
|
76
|
+
console.log(childObj)
|
|
77
|
+
return tag({...props, children:childObj[0] || childObj})
|
|
71
78
|
}
|
|
72
79
|
node.firstChild = comp.render()
|
|
73
80
|
node.firstChild.htmlNode._key = node._key
|
|
@@ -102,6 +109,7 @@ let hasBeenCalled = []
|
|
|
102
109
|
* @returns {Object} - The virtual DOM element
|
|
103
110
|
*/
|
|
104
111
|
function Element(tag, props, ...children) {
|
|
112
|
+
console.log(tag)
|
|
105
113
|
!props ? props = {} : null
|
|
106
114
|
if (!props?.['$$key']) {
|
|
107
115
|
props['$$key'] = tag.name || Math.random().toString(36).substring(7)
|
package/config/index.ts
CHANGED
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
* @param {string} [config.mode] - The mode for the configuration.
|
|
27
27
|
* @param {Array} [config.plugins] - The plugins for the configuration.
|
|
28
28
|
* @param {Object} [config.env] - The environment variables for the configuration.
|
|
29
|
+
* @param {Array} [config.Router] - The router configuration.
|
|
30
|
+
* @param {Object} [config.Router.tls] - The tls configuration - allows you to switch the server to https.
|
|
31
|
+
* @param {string} [config.Router.tls.cert] - The certificate for the tls configuration.
|
|
32
|
+
* @param {string} [config.Router.tls.key] - The key for the tls configuration.
|
|
33
|
+
* @param {Object} [config.Router.headers] - The headers for the router configuration.
|
|
29
34
|
* @returns {Object} The configured object.
|
|
30
35
|
*/
|
|
31
36
|
export const defineConfig = (config: {
|
|
@@ -46,10 +51,24 @@ export const defineConfig = (config: {
|
|
|
46
51
|
outDir?: string,
|
|
47
52
|
},
|
|
48
53
|
mode?: string,
|
|
54
|
+
/**
|
|
55
|
+
* @type {any[]}
|
|
56
|
+
* @description Allows you to extend the functionality of vaderjs
|
|
57
|
+
*/
|
|
49
58
|
plugins?: any[]
|
|
50
59
|
env?: {
|
|
51
60
|
[key: string]: any
|
|
52
|
-
}
|
|
61
|
+
},
|
|
62
|
+
Router?: {
|
|
63
|
+
tls?: {
|
|
64
|
+
cert?: string,
|
|
65
|
+
key?: string
|
|
66
|
+
},
|
|
67
|
+
headers?: {
|
|
68
|
+
[key: string]: string
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
[key: string]: any
|
|
53
72
|
}) => {
|
|
54
73
|
// add config.env to globalThis.env
|
|
55
74
|
let env = {}
|
package/package.json
CHANGED
|
@@ -8,6 +8,10 @@ const glob = new Glob("/**/*.{ts,tsx,js,jsx}", {
|
|
|
8
8
|
*/
|
|
9
9
|
async function generate(){
|
|
10
10
|
let config = await import(process.cwd() + '/vader.config.js').then((config) => { return config.default })
|
|
11
|
+
if(!config?.env || !config?.env.SSR){
|
|
12
|
+
console.error('\x1b[31m[CloudFlare Functions] \x1b[0m - Please add an SSR environment variable to your vader.config.js file')
|
|
13
|
+
return
|
|
14
|
+
}
|
|
11
15
|
let start = Date.now()
|
|
12
16
|
for(var i of glob.scanSync({cwd: process.cwd() + '/routes', absolute: true})){
|
|
13
17
|
let data = await Bun.file(i).text()
|
|
@@ -10,10 +10,40 @@ export class DOMParser {
|
|
|
10
10
|
*/
|
|
11
11
|
parseFromString(html) {
|
|
12
12
|
let doc = new Document();
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
let t = new Bun.Transpiler({
|
|
14
|
+
loader: "tsx", // "js | "jsx" | "ts" | "tsx",
|
|
15
|
+
target: "browser",
|
|
16
|
+
define: {
|
|
17
|
+
"jsxDEV": "Element",
|
|
18
|
+
"jsx": "Element"
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
let el = t.transformSync(`
|
|
23
|
+
|
|
24
|
+
const html = ${html}
|
|
25
|
+
function Doc() {
|
|
26
|
+
return (
|
|
27
|
+
<html>
|
|
28
|
+
<body>${html}</body>
|
|
29
|
+
</html>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
return Doc()
|
|
33
|
+
` )
|
|
34
|
+
el = el.replaceAll(`jsxDEV`, `Element`)
|
|
35
|
+
let evaluated = eval(`(function(){${el}})()`)
|
|
36
|
+
evaluated.children.forEach((child) => {
|
|
37
|
+
child.outerHTML = child.toString()
|
|
38
|
+
})
|
|
39
|
+
doc.tree = evaluated.children
|
|
40
|
+
doc.body = evaluated.children[0]
|
|
41
|
+
doc.body.outerHTML = evaluated.children[0].toString()
|
|
42
|
+
doc.body.firstChild = evaluated.children[0].children[0]
|
|
43
|
+
doc.documentElement = evaluated
|
|
44
|
+
doc.documentElement.outerHTML = evaluated.children[0].toString()
|
|
45
|
+
this.tree = evaluated.children
|
|
46
|
+
return doc
|
|
17
47
|
}
|
|
18
48
|
/**
|
|
19
49
|
* @description - Returns a string containing the HTML serialization of the element's descendants.
|
|
@@ -37,7 +67,7 @@ export class HTMLTextNode {
|
|
|
37
67
|
}
|
|
38
68
|
|
|
39
69
|
insertBefore(node) {
|
|
40
|
-
this.nodeValue = `${node.
|
|
70
|
+
this.nodeValue = `${node.nodeValue}${this.nodeValue}`;
|
|
41
71
|
return this;
|
|
42
72
|
}
|
|
43
73
|
}
|
|
@@ -81,7 +111,7 @@ export class HTMLElement {
|
|
|
81
111
|
if (key !== 'style' && key !== 'ref' && !key.startsWith('on')) {
|
|
82
112
|
props += `${key}="${this.props[key]}" `
|
|
83
113
|
}
|
|
84
|
-
}
|
|
114
|
+
}
|
|
85
115
|
let children = this.children
|
|
86
116
|
.map((child) => {
|
|
87
117
|
return child.toString();
|
|
@@ -123,7 +153,9 @@ export class HTMLElement {
|
|
|
123
153
|
}
|
|
124
154
|
})
|
|
125
155
|
.join("");
|
|
126
|
-
return string;
|
|
156
|
+
return string;
|
|
157
|
+
|
|
158
|
+
|
|
127
159
|
default:
|
|
128
160
|
break;
|
|
129
161
|
}
|
|
@@ -150,8 +182,8 @@ export class HTMLElement {
|
|
|
150
182
|
* @returns {HTMLElement}
|
|
151
183
|
*/
|
|
152
184
|
setContent(content) {
|
|
153
|
-
let textNode = new
|
|
154
|
-
this.children = [textNode];
|
|
185
|
+
let textNode = new HTMLTextNode(content)
|
|
186
|
+
this.children = [textNode];
|
|
155
187
|
this.outerHTML = this.toString("outerHTML");
|
|
156
188
|
this.innerHTML = this.toString("innerHTML");
|
|
157
189
|
return this;
|
|
@@ -319,7 +351,7 @@ export class HTMLElement {
|
|
|
319
351
|
this.textContent = this.toString("innerText");
|
|
320
352
|
this.children.forEach((c) => {
|
|
321
353
|
if (c.children) {
|
|
322
|
-
child = c.children.find((child) => {
|
|
354
|
+
child = c.children.find((child) => {
|
|
323
355
|
child.outerHTML = child.toString("outerHTML");
|
|
324
356
|
child.innerHTML = child.toString("innerHTML");
|
|
325
357
|
return child.tagName === selector;
|
|
@@ -407,6 +439,9 @@ export class Document {
|
|
|
407
439
|
* @returns {HTMLElement}
|
|
408
440
|
*/
|
|
409
441
|
createElement(nodeData) {
|
|
442
|
+
if(!nodeData){
|
|
443
|
+
return new HTMLElement("div", {}, [])
|
|
444
|
+
}
|
|
410
445
|
if (typeof nodeData === 'string') {
|
|
411
446
|
return new HTMLElement(nodeData, {}, [])
|
|
412
447
|
}
|
|
@@ -526,7 +561,17 @@ function handleStyles(styles, nodeEl) {
|
|
|
526
561
|
*/
|
|
527
562
|
export function Element(tag, props = {}, ...children) {
|
|
528
563
|
if(typeof tag === 'function'){
|
|
529
|
-
let
|
|
564
|
+
let childObj = children.map((child) => {
|
|
565
|
+
if (child.tagName === "TEXT_ELEMENT") {
|
|
566
|
+
return new HTMLTextNode(child);
|
|
567
|
+
}
|
|
568
|
+
if (child instanceof HTMLElement) {
|
|
569
|
+
return child;
|
|
570
|
+
}
|
|
571
|
+
return new HTMLElement(child.tagName, child.props, child.children);
|
|
572
|
+
})
|
|
573
|
+
childObj = childObj[0]
|
|
574
|
+
let el = tag({...props, children: childObj})
|
|
530
575
|
return el
|
|
531
576
|
}
|
|
532
577
|
if(props === null){
|
|
@@ -592,9 +637,12 @@ export function Element(tag, props = {}, ...children) {
|
|
|
592
637
|
|
|
593
638
|
node.children = children
|
|
594
639
|
delete props.children
|
|
595
|
-
}
|
|
596
|
-
|
|
640
|
+
}
|
|
597
641
|
for (var i = 0; i < children.length; i++) {
|
|
642
|
+
if(typeof children[i] === 'undefined'){
|
|
643
|
+
delete children[i]
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
598
646
|
if (typeof children[i] === "string" || typeof children[i] === "number") {
|
|
599
647
|
children[i] = {
|
|
600
648
|
tagName: "TEXT_ELEMENT",
|
|
@@ -607,7 +655,7 @@ export function Element(tag, props = {}, ...children) {
|
|
|
607
655
|
} else {
|
|
608
656
|
if (children[i]) {
|
|
609
657
|
children[i].parentNode = { tagName: tag, props: props, children: children };
|
|
610
|
-
}
|
|
658
|
+
}
|
|
611
659
|
|
|
612
660
|
children[i] = new HTMLElement(children[i].tagName, children[i].props, children[i].children)
|
|
613
661
|
}
|
|
@@ -2,6 +2,7 @@ window.vader = {
|
|
|
2
2
|
version: '1.0.0'
|
|
3
3
|
}
|
|
4
4
|
globalThis.isServer = false
|
|
5
|
+
globalThis.preRender = false;
|
|
5
6
|
window.hasRan = []
|
|
6
7
|
globalThis.memoizedFunctions = []
|
|
7
8
|
const memoizedRefs = []
|
|
@@ -11,40 +12,40 @@ const memoizedRefs = []
|
|
|
11
12
|
* @param {HTMLElement} newNode
|
|
12
13
|
* @returns
|
|
13
14
|
*/
|
|
14
|
-
function calculateDiff(oldNode, newNode){
|
|
15
|
-
if(oldNode === undefined || newNode === undefined){
|
|
15
|
+
function calculateDiff(oldNode, newNode) {
|
|
16
|
+
if (oldNode === undefined || newNode === undefined) {
|
|
16
17
|
return []
|
|
17
18
|
}
|
|
18
|
-
let diff = []
|
|
19
|
-
if(oldNode?.children.length > 0){
|
|
20
|
-
for(var i = 0; i < oldNode.children.length; i++){
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
19
|
+
let diff = []
|
|
20
|
+
if (oldNode?.children.length > 0) {
|
|
21
|
+
for (var i = 0; i < oldNode.children.length; i++) {
|
|
22
|
+
diff.push(...calculateDiff(oldNode.children[i], newNode.children[i]))
|
|
23
|
+
|
|
24
|
+
}
|
|
24
25
|
return diff
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if(oldNode.nodeType === 3 && oldNode.nodeValue !== newNode.nodeValue){
|
|
28
|
-
diff.push({type: 'REPLACE', oldNode, newNode})
|
|
26
|
+
}
|
|
27
|
+
if (!oldNode?._isRoot) {
|
|
28
|
+
if (oldNode.nodeType === 3 && oldNode.nodeValue !== newNode.nodeValue) {
|
|
29
|
+
diff.push({ type: 'REPLACE', oldNode, newNode })
|
|
29
30
|
}
|
|
30
|
-
else if(oldNode.nodeType === 1 && oldNode.innerHTML !== newNode.innerHTML
|
|
31
|
-
){
|
|
32
|
-
diff.push({type: 'REPLACE', oldNode, newNode})
|
|
31
|
+
else if (oldNode.nodeType === 1 && oldNode.innerHTML !== newNode.innerHTML
|
|
32
|
+
) {
|
|
33
|
+
diff.push({ type: 'REPLACE', oldNode, newNode })
|
|
33
34
|
}
|
|
34
|
-
else if(oldNode.nodeType === 1 && oldNode.tagName === newNode.tagName){
|
|
35
|
-
for(var i = 0; i < oldNode.attributes.length; i++){
|
|
36
|
-
if(oldNode.attributes[i].value !== newNode.attributes[i].value){
|
|
37
|
-
diff.push({type: 'PROPS', oldNode, newNode})
|
|
35
|
+
else if (oldNode.nodeType === 1 && oldNode.tagName === newNode.tagName) {
|
|
36
|
+
for (var i = 0; i < oldNode.attributes.length; i++) {
|
|
37
|
+
if (oldNode.attributes[i].value !== newNode.attributes[i].value) {
|
|
38
|
+
diff.push({ type: 'PROPS', oldNode, newNode })
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
|
-
}
|
|
42
|
+
}
|
|
43
|
+
|
|
42
44
|
|
|
43
|
-
|
|
44
45
|
|
|
45
46
|
return diff
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
+
|
|
48
49
|
/**
|
|
49
50
|
* @description This function is used to generate functonal components
|
|
50
51
|
* @param {Function} tag
|
|
@@ -52,38 +53,51 @@ function calculateDiff(oldNode, newNode){
|
|
|
52
53
|
* @param {...any} children
|
|
53
54
|
* @returns {Object} - The first child of the functional component
|
|
54
55
|
*/
|
|
55
|
-
function generateJSX(tag, props, ...children){
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
function generateJSX(tag, props, ...children) {
|
|
57
|
+
let node = {
|
|
58
|
+
state: {},
|
|
59
|
+
mainFunction: tag,
|
|
60
|
+
_key: tag.name || Math.random().toString(36).substring(7),
|
|
61
|
+
$$typeof: 'JSX_CHILD',
|
|
62
|
+
firstChild: null,
|
|
63
|
+
children: children,
|
|
64
|
+
_name: tag.name,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let comp = new Component({ $$key: node._key })
|
|
68
|
+
tag = tag.bind(comp)
|
|
69
|
+
comp.render = () => {
|
|
70
|
+
children = children.flat(Infinity)
|
|
71
|
+
let childObj = children.map((child) => {
|
|
72
|
+
if (typeof child === 'function') {
|
|
73
|
+
return generateJSX(child, props, child.props.children)
|
|
74
|
+
}
|
|
75
|
+
return child
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
return tag({...props, children:childObj[0] || childObj})
|
|
79
|
+
}
|
|
80
|
+
node.firstChild = comp.render()
|
|
81
|
+
node.firstChild.htmlNode._key = node._key
|
|
68
82
|
node.firstChild.htmlRoot = node
|
|
69
|
-
node.firstChild.htmlNode._isRoot = true
|
|
70
|
-
node.firstChild.props = props || {}
|
|
83
|
+
node.firstChild.htmlNode._isRoot = true
|
|
84
|
+
node.firstChild.props = props || {}
|
|
71
85
|
node.firstChild._isRoot = true
|
|
72
86
|
node.firstChild._key = node._key
|
|
73
|
-
node.firstChild.props['key'] = node._key
|
|
74
|
-
return
|
|
75
|
-
|
|
87
|
+
node.firstChild.props['key'] = node._key
|
|
88
|
+
return node.firstChild
|
|
89
|
+
|
|
76
90
|
|
|
77
91
|
}
|
|
78
|
-
function handleStyles(styles, nodeEl) {
|
|
92
|
+
function handleStyles(styles, nodeEl) {
|
|
79
93
|
|
|
80
94
|
for (let key in styles) {
|
|
81
|
-
if(typeof styles[key] === 'object'){
|
|
95
|
+
if (typeof styles[key] === 'object') {
|
|
82
96
|
handleStyles(styles[key], nodeEl)
|
|
83
97
|
}
|
|
84
98
|
nodeEl.style[key] = styles[key];
|
|
85
99
|
}
|
|
86
|
-
|
|
100
|
+
|
|
87
101
|
}
|
|
88
102
|
|
|
89
103
|
|
|
@@ -95,166 +109,166 @@ let hasBeenCalled = []
|
|
|
95
109
|
* @param {...any} children
|
|
96
110
|
* @returns {Object} - The virtual DOM element
|
|
97
111
|
*/
|
|
98
|
-
function Element(tag, props, ...children){
|
|
112
|
+
function Element(tag, props, ...children) {
|
|
99
113
|
!props ? props = {} : null
|
|
100
|
-
if(!props?.['$$key']){
|
|
114
|
+
if (!props?.['$$key']) {
|
|
101
115
|
props['$$key'] = tag.name || Math.random().toString(36).substring(7)
|
|
102
116
|
}
|
|
103
117
|
|
|
104
|
-
if(typeof tag === 'function'){
|
|
105
|
-
|
|
118
|
+
if (typeof tag === 'function') {
|
|
119
|
+
return generateJSX(tag, props, children)
|
|
106
120
|
}
|
|
107
121
|
let node = {
|
|
108
122
|
tag: tag,
|
|
109
123
|
props: props,
|
|
110
|
-
children: children,
|
|
124
|
+
children: children,
|
|
111
125
|
_key: props['$$key'],
|
|
112
126
|
events: [],
|
|
113
127
|
staticEl: document.createElement(tag),
|
|
114
128
|
parentNode: null
|
|
115
129
|
}
|
|
116
|
-
for(var i = 0; i < children.length; i++){
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
130
|
+
for (var i = 0; i < children.length; i++) {
|
|
131
|
+
if (typeof children[i] === 'string' || typeof children[i] === 'number') {
|
|
132
|
+
children[i] = {
|
|
133
|
+
tag: 'TEXT_ELEMENT',
|
|
134
|
+
props: { nodeValue: children[i] },
|
|
135
|
+
_key: props['$$key'],
|
|
136
|
+
parentNode: { tag: tag, props: props, children: children, _key: props['$$key'] },
|
|
137
|
+
children: []
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
if (children[i]) {
|
|
141
|
+
children[i].parentNode = { tag: tag, props: props, children: children }
|
|
142
|
+
}
|
|
124
143
|
}
|
|
125
|
-
|
|
126
|
-
if(children[i]){
|
|
127
|
-
children[i].parentNode = {tag: tag, props: props, children: children}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
144
|
+
}
|
|
131
145
|
let nodeEl = node.tag === 'TEXT_ELEMENT' ? document.createTextNode('') : document.createElement(node.tag)
|
|
132
146
|
node.staticEl = nodeEl
|
|
133
|
-
|
|
134
|
-
for(var key in props){
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if(nodeEl && nodeEl.nodeType === 1){
|
|
147
|
+
|
|
148
|
+
for (var key in props) {
|
|
149
|
+
if (key.toLowerCase().startsWith('on')) {
|
|
150
|
+
nodeEl.addEventListener(key.substring(2).toLowerCase(), props[key])
|
|
151
|
+
node.events.push({ type: key.substring(2).toLowerCase(), listener: props[key] })
|
|
152
|
+
continue
|
|
153
|
+
}
|
|
154
|
+
if (key === '$$key' && !nodeEl._key && nodeEl.nodeType === 1
|
|
155
|
+
) {
|
|
156
|
+
Object.defineProperty(nodeEl, '_key', {
|
|
157
|
+
value: props[key],
|
|
158
|
+
writable: true
|
|
159
|
+
})
|
|
160
|
+
continue
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (nodeEl && nodeEl.nodeType === 1) {
|
|
150
164
|
nodeEl.setAttribute(key, props[key])
|
|
151
165
|
}
|
|
152
|
-
|
|
166
|
+
|
|
153
167
|
}
|
|
154
|
-
if(props.style){
|
|
168
|
+
if (props.style) {
|
|
155
169
|
handleStyles(props.style, nodeEl)
|
|
156
170
|
}
|
|
157
171
|
|
|
158
|
-
if(props.id){
|
|
172
|
+
if (props.id) {
|
|
159
173
|
nodeEl.id = props.id
|
|
160
174
|
}
|
|
161
|
-
if(props.ref){
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
175
|
+
if (props.ref) {
|
|
176
|
+
switch (true) {
|
|
177
|
+
case Array.isArray(props.ref.current):
|
|
178
|
+
if (!props.ref.current.find((el) => el === nodeEl)) {
|
|
179
|
+
props.ref.current.push(nodeEl)
|
|
180
|
+
}
|
|
181
|
+
break;
|
|
182
|
+
case props.ref.current === HTMLElement:
|
|
183
|
+
props.ref.current = nodeEl
|
|
184
|
+
break;
|
|
185
|
+
case props.ref.current === null:
|
|
186
|
+
props.ref.current = nodeEl
|
|
187
|
+
break;
|
|
188
|
+
case typeof props.ref === 'function' && !window.hasRan.includes(props.ref):
|
|
189
|
+
window.hasRan.push(props.ref)
|
|
190
|
+
props.ref(nodeEl)
|
|
191
|
+
setTimeout(() => {
|
|
192
|
+
window.hasRan.filter((el) => el !== props.ref)
|
|
193
|
+
}, 0)
|
|
194
|
+
break;
|
|
195
|
+
default:
|
|
196
|
+
props.ref.current = nodeEl
|
|
197
|
+
break;
|
|
198
|
+
|
|
199
|
+
}
|
|
186
200
|
}
|
|
187
201
|
node['htmlNode'] = nodeEl
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if(nodeEl.nodeType === 1){
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
if (nodeEl.nodeType === 1) {
|
|
205
|
+
for (var i = 0; i < children.length; i++) {
|
|
206
|
+
if (children[i]) {
|
|
207
|
+
if (children[i].tag === 'TEXT_ELEMENT') {
|
|
208
|
+
nodeEl.appendChild(document.createTextNode(children[i].props.nodeValue))
|
|
209
|
+
}
|
|
210
|
+
nodeEl.appendChild(Element(children[i].tag, children[i].props, ...children[i].children).htmlNode)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
}
|
|
215
|
+
|
|
202
216
|
return node;
|
|
203
217
|
}
|
|
204
|
-
|
|
205
218
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
219
|
+
|
|
220
|
+
function handleDiff(diff) {
|
|
221
|
+
for (var i = 0; i < diff.length; i++) {
|
|
222
|
+
switch (true) {
|
|
223
|
+
case diff[i].type === 'REPLACE' && !diff[i].oldNode._isRoot:
|
|
224
|
+
let parent = diff[i].oldNode.parentNode
|
|
211
225
|
diff[i].oldNode.parentNode.replaceChild(diff[i].newNode, diff[i].oldNode)
|
|
212
226
|
break;
|
|
213
|
-
|
|
227
|
+
case diff[i].type === 'PROPS':
|
|
214
228
|
break;
|
|
215
|
-
|
|
229
|
+
}
|
|
216
230
|
}
|
|
217
231
|
|
|
218
232
|
}
|
|
219
233
|
let states = {}
|
|
220
|
-
export const useState = (name,
|
|
221
|
-
export function useRef(name,
|
|
234
|
+
export const useState = (name, initialValue) => { }
|
|
235
|
+
export function useRef(name, initialValue) {
|
|
222
236
|
let ref = initialValue
|
|
223
|
-
if(!memoizedRefs.find((el) => el.name === name)){
|
|
224
|
-
memoizedRefs.push({name, ref})
|
|
225
|
-
}
|
|
226
|
-
let getRef = () =>
|
|
227
|
-
let setRef = (newValue) => {
|
|
228
|
-
memoizedRefs.find((el) => el.name === name).ref = newValue
|
|
229
|
-
}
|
|
230
|
-
return
|
|
237
|
+
if (!memoizedRefs.find((el) => el.name === name)) {
|
|
238
|
+
memoizedRefs.push({ name, ref })
|
|
239
|
+
}
|
|
240
|
+
let getRef = () => memoizedRefs.find((el) => el.name === name).ref
|
|
241
|
+
let setRef = (newValue) => {
|
|
242
|
+
memoizedRefs.find((el) => el.name === name).ref = newValue
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
231
245
|
current: getRef(),
|
|
232
246
|
name,
|
|
233
247
|
}
|
|
234
248
|
}
|
|
235
|
-
export function Mounted(fn, node){
|
|
236
|
-
let el = Array.from(document.querySelectorAll('*')).find((el) =>
|
|
237
|
-
if(el && !hasBeenCalled.find((el) => el === node)){
|
|
249
|
+
export function Mounted(fn, node) {
|
|
250
|
+
let el = Array.from(document.querySelectorAll('*')).find((el) => el._key === memoizedFunctions.find((el) => el.mainFunction === node)._key)
|
|
251
|
+
if (el && !hasBeenCalled.find((el) => el === node)) {
|
|
238
252
|
fn()
|
|
239
253
|
hasBeenCalled.push(node)
|
|
240
254
|
}
|
|
241
|
-
else{
|
|
255
|
+
else {
|
|
242
256
|
setTimeout(() => {
|
|
243
257
|
Mounted(fn, node)
|
|
244
258
|
}, 0)
|
|
245
259
|
}
|
|
246
260
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
let effects = [];
|
|
250
261
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
262
|
+
|
|
263
|
+
let effects = [];
|
|
264
|
+
|
|
265
|
+
export function useEffect(fn, deps) {
|
|
266
|
+
if (!effects.find((el) => el.fn.toString() === fn.toString())) {
|
|
267
|
+
effects.push({ fn, deps })
|
|
254
268
|
}
|
|
255
|
-
else{
|
|
269
|
+
else {
|
|
256
270
|
let effect = effects.find((el) => el.fn.toString() === fn.toString())
|
|
257
|
-
if(effect.deps.toString() !== deps.toString()){
|
|
271
|
+
if (effect.deps.toString() !== deps.toString()) {
|
|
258
272
|
effect.deps = deps
|
|
259
273
|
effect.fn()
|
|
260
274
|
}
|
|
@@ -264,169 +278,143 @@ export function useEffect(fn, deps){
|
|
|
264
278
|
}
|
|
265
279
|
|
|
266
280
|
}
|
|
267
|
-
export function useReducer(name, reducer, vnode, initialState){
|
|
281
|
+
export function useReducer(name, reducer, vnode, initialState) {
|
|
268
282
|
let [state, setState] = useState(name, vnode, initialState)
|
|
269
283
|
let dispatch = (action) => {
|
|
270
284
|
let newState = reducer(state, action)
|
|
271
285
|
setState(newState)
|
|
272
286
|
}
|
|
273
287
|
|
|
274
|
-
return
|
|
288
|
+
return [state, dispatch]
|
|
275
289
|
|
|
276
290
|
}
|
|
277
291
|
|
|
278
292
|
class Component {
|
|
279
|
-
constructor(props){
|
|
293
|
+
constructor(props) {
|
|
280
294
|
this.props = props
|
|
281
295
|
this._key = props['$$key'] || Math.random().toString(36).substring(7)
|
|
282
296
|
this.state = {}
|
|
283
297
|
this.htmlNode = null
|
|
284
298
|
this.firstChild = null
|
|
285
299
|
this.Element = Element
|
|
286
|
-
this.
|
|
300
|
+
this.passiveProps = {}
|
|
287
301
|
}
|
|
288
302
|
|
|
289
303
|
|
|
290
|
-
setState(newState){
|
|
304
|
+
setState(newState) {
|
|
291
305
|
this.state = newState
|
|
292
306
|
}
|
|
293
307
|
|
|
294
|
-
handleDiff(diff){
|
|
295
|
-
for(var i = 0; i < diff.length; i++){
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
let parent = diff[i].oldNode.parentNode
|
|
308
|
+
handleDiff(diff) {
|
|
309
|
+
for (var i = 0; i < diff.length; i++) {
|
|
310
|
+
switch (true) {
|
|
311
|
+
case diff[i].type === 'REPLACE' && !diff[i].oldNode._isRoot:
|
|
312
|
+
let parent = diff[i].oldNode.parentNode
|
|
299
313
|
diff[i].oldNode.parentNode.replaceChild(diff[i].newNode, diff[i].oldNode)
|
|
300
314
|
break;
|
|
301
|
-
|
|
315
|
+
case diff[i].type === 'PROPS':
|
|
302
316
|
break;
|
|
303
|
-
|
|
317
|
+
}
|
|
304
318
|
}
|
|
305
319
|
}
|
|
306
|
-
calculateDiff(oldNode, newNode){
|
|
307
|
-
if(oldNode === undefined || newNode === undefined){
|
|
320
|
+
calculateDiff(oldNode, newNode) {
|
|
321
|
+
if (oldNode === undefined || newNode === undefined) {
|
|
308
322
|
return []
|
|
309
323
|
}
|
|
310
|
-
let diff = []
|
|
311
|
-
if(oldNode?.children.length > 0){
|
|
312
|
-
for(var i = 0; i < oldNode.children.length; i++){
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
324
|
+
let diff = []
|
|
325
|
+
if (oldNode?.children.length > 0) {
|
|
326
|
+
for (var i = 0; i < oldNode.children.length; i++) {
|
|
327
|
+
diff.push(...this.calculateDiff(oldNode.children[i], newNode.children[i]))
|
|
328
|
+
|
|
329
|
+
}
|
|
316
330
|
return diff
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
if(oldNode.nodeType === 3 && oldNode.nodeValue !== newNode.nodeValue){
|
|
320
|
-
diff.push({type: 'REPLACE', oldNode, newNode})
|
|
331
|
+
}
|
|
332
|
+
if (!oldNode?._isRoot) {
|
|
333
|
+
if (oldNode.nodeType === 3 && oldNode.nodeValue !== newNode.nodeValue) {
|
|
334
|
+
diff.push({ type: 'REPLACE', oldNode, newNode })
|
|
321
335
|
}
|
|
322
|
-
else if(oldNode.nodeType === 1 && oldNode.innerHTML !== newNode.innerHTML
|
|
323
|
-
){
|
|
324
|
-
diff.push({type: 'REPLACE', oldNode, newNode})
|
|
336
|
+
else if (oldNode.nodeType === 1 && oldNode.innerHTML !== newNode.innerHTML
|
|
337
|
+
) {
|
|
338
|
+
diff.push({ type: 'REPLACE', oldNode, newNode })
|
|
325
339
|
}
|
|
326
|
-
else if(oldNode.nodeType === 1 && oldNode.tagName === newNode.tagName){
|
|
327
|
-
for(var i = 0; i < oldNode.attributes.length; i++){
|
|
328
|
-
if(oldNode.attributes[i].value !== newNode.attributes[i].value){
|
|
329
|
-
diff.push({type: 'PROPS', oldNode, newNode})
|
|
340
|
+
else if (oldNode.nodeType === 1 && oldNode.tagName === newNode.tagName) {
|
|
341
|
+
for (var i = 0; i < oldNode.attributes.length; i++) {
|
|
342
|
+
if (oldNode.attributes[i].value !== newNode.attributes[i].value) {
|
|
343
|
+
diff.push({ type: 'PROPS', oldNode, newNode })
|
|
330
344
|
}
|
|
331
345
|
}
|
|
332
346
|
}
|
|
333
|
-
}
|
|
347
|
+
}
|
|
348
|
+
|
|
334
349
|
|
|
335
|
-
|
|
336
350
|
|
|
337
351
|
return diff
|
|
338
352
|
}
|
|
339
|
-
|
|
340
|
-
if(!this.
|
|
341
|
-
this.effects.push({fn, deps})
|
|
342
|
-
}
|
|
343
|
-
else{
|
|
344
|
-
let effect = this.effects.find((el) => el.fn.toString() === fn.toString())
|
|
345
|
-
if(effect.deps.toString() !== deps.toString()){
|
|
346
|
-
effect.deps = deps
|
|
347
|
-
effect.fn()
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
return () => {
|
|
351
|
-
this.effects = this.effects.filter((el) => el.fn !== fn)
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
useState(name, initialValue){
|
|
355
|
-
if(!this.state[name]){
|
|
353
|
+
useState(name, initialValue) {
|
|
354
|
+
if (!this.state[name]) {
|
|
356
355
|
this.state[name] = initialValue
|
|
357
|
-
}
|
|
358
|
-
|
|
356
|
+
}
|
|
357
|
+
|
|
359
358
|
let getState = () => this.state[name]
|
|
360
|
-
let setState = (newValue) => {
|
|
361
|
-
let dEl =
|
|
362
|
-
if(dEl.tagName === 'HTML'){
|
|
363
|
-
|
|
364
|
-
dEl =
|
|
365
|
-
}
|
|
366
|
-
this.state[name] = newValue
|
|
367
|
-
let el = Array.from(document.querySelectorAll('*')).find((el) =>{
|
|
359
|
+
let setState = (newValue) => {
|
|
360
|
+
let dEl = this.firstChild.htmlNode
|
|
361
|
+
if (dEl.tagName === 'HTML') {
|
|
362
|
+
dEl = dEl.querySelector('body')
|
|
363
|
+
dEl.firstChild._key = this._key
|
|
364
|
+
}
|
|
365
|
+
this.state[name] = newValue
|
|
366
|
+
let el = Array.from(document.querySelectorAll('*')).find((el) => {
|
|
368
367
|
return el._key === dEl._key
|
|
369
|
-
})
|
|
370
|
-
let diff = calculateDiff(el, this.render().htmlNode.tagName === 'HTML' ? this.render().htmlNode.querySelector('body')
|
|
368
|
+
})
|
|
369
|
+
let diff = calculateDiff(el, this.render(this.passiveProps).htmlNode.tagName === 'HTML' ? this.render(this.passiveProps).htmlNode.querySelector('body') : this.render(this.passiveProps).htmlNode)
|
|
371
370
|
handleDiff(diff)
|
|
372
|
-
|
|
373
|
-
}
|
|
374
|
-
return
|
|
371
|
+
|
|
372
|
+
}
|
|
373
|
+
return [getState, setState]
|
|
375
374
|
|
|
376
375
|
}
|
|
377
|
-
|
|
376
|
+
useEffect = useEffect
|
|
377
|
+
useReducer(name, reducer, initialState) {
|
|
378
378
|
let [state, setState] = this.useState(name, initialState)
|
|
379
379
|
let dispatch = (action) => {
|
|
380
|
-
let newState = reducer(state(), action)
|
|
380
|
+
let newState = reducer(state(), action)
|
|
381
381
|
setState(newState)
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
-
return
|
|
384
|
+
return [state, dispatch]
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
-
render(){
|
|
387
|
+
render() {
|
|
388
388
|
return null
|
|
389
389
|
}
|
|
390
390
|
|
|
391
391
|
}
|
|
392
|
-
|
|
393
|
-
export async function render(vnode, container, ...passProps){
|
|
394
|
-
|
|
395
|
-
if(!vnode){
|
|
392
|
+
|
|
393
|
+
export async function render(vnode, container, ...passProps) {
|
|
394
|
+
|
|
395
|
+
if (!vnode) {
|
|
396
396
|
throw new Error('No vnode was provided')
|
|
397
397
|
}
|
|
398
398
|
// create an object for the node then bind to firstChild
|
|
399
|
-
let comp = new Component({$$key:
|
|
399
|
+
let comp = new Component({ $$key: vnode.name || Math.random().toString(36).substring(7) })
|
|
400
400
|
vnode = vnode.bind(comp)
|
|
401
|
-
|
|
402
|
-
|
|
401
|
+
if(passProps.length > 0){
|
|
402
|
+
|
|
403
|
+
passProps = {
|
|
404
|
+
req: passProps[0],
|
|
405
|
+
res: passProps[1]
|
|
406
|
+
}
|
|
407
|
+
comp.passiveProps = passProps
|
|
408
|
+
}
|
|
409
|
+
comp.render = () => {
|
|
410
|
+
return vnode(comp.passiveProps)
|
|
403
411
|
}
|
|
404
|
-
|
|
412
|
+
|
|
405
413
|
comp.firstChild = comp.render()
|
|
406
414
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
if(hasHead){
|
|
412
|
-
document.head.innerHTML = comp.firstChild.htmlNode.querySelector('head').innerHTML
|
|
413
|
-
comp.firstChild.children = comp.firstChild.children.filter((el) =>{
|
|
414
|
-
return el.htmlNode.tagName !== 'HEAD'
|
|
415
|
-
})
|
|
416
|
-
}
|
|
417
|
-
if(hasBody){
|
|
418
|
-
comp.firstChild.children = comp.firstChild.children.filter((el) =>{
|
|
419
|
-
if(el.htmlNode.tagName == 'BODY'){
|
|
420
|
-
comp.firstChild = el.children[0]
|
|
421
|
-
}
|
|
422
|
-
})
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
container.innerHTML = ''
|
|
426
|
-
|
|
427
|
-
container.appendChild(comp.firstChild.htmlNode)
|
|
428
|
-
|
|
429
|
-
|
|
415
|
+
container.innerHTML = ''
|
|
416
|
+
container.replaceWith(comp.firstChild.htmlNode)
|
|
417
|
+
|
|
430
418
|
}
|
|
431
|
-
|
|
419
|
+
|
|
432
420
|
export default Element
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
function checkIFtailwindInstalled() {
|
|
3
|
+
try {
|
|
4
|
+
require.resolve('tailwindcss');
|
|
5
|
+
return true;
|
|
6
|
+
} catch (e) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
name: "tailwind",
|
|
14
|
+
description: "A plugin to install tailwindcss",
|
|
15
|
+
once: true,
|
|
16
|
+
init: async () => {
|
|
17
|
+
let config = require(process.cwd() + "/vader.config.js").default;
|
|
18
|
+
const fs = require("fs");
|
|
19
|
+
const path = require("path");
|
|
20
|
+
const { exec} = require("child_process");
|
|
21
|
+
const tailwindConfig = `
|
|
22
|
+
/** @type {import('tailwindcss').Config} */
|
|
23
|
+
module.exports = {
|
|
24
|
+
content: ['./src/**/*.{jsx,tsx,js,ts}', './pages/**/*.{jsx,tsx,js,ts}', './components/**/*.{jsx,tsx,js,ts}'],
|
|
25
|
+
theme: {
|
|
26
|
+
${
|
|
27
|
+
config?.tailwind?.theme ? JSON.stringify(config.tailwind.theme, null, 2) : ``
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
plugins: [
|
|
31
|
+
${
|
|
32
|
+
config?.tailwind?.plugins ? config?.tailwind?.plugins.map((plugin) => {
|
|
33
|
+
return `require('${plugin}')`
|
|
34
|
+
}).join(",") : ``
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
fs.writeFileSync(
|
|
40
|
+
path.join(process.cwd(), "tailwind.config.js"),
|
|
41
|
+
tailwindConfig
|
|
42
|
+
);
|
|
43
|
+
if (!checkIFtailwindInstalled()) {
|
|
44
|
+
console.log(`\x1b[36mwait \x1b[0m - installing tailwindcss & ${config?.tailwind?.plugins ? config?.tailwind?.plugins.length + " plugins" : ""} (First time only)`);
|
|
45
|
+
let npmPath = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
46
|
+
Bun.spawnSync({
|
|
47
|
+
cmd: [npmPath, "install", "tailwindcss", "postcss", "autoprefixer" , ...config?.tailwind?.plugins || []],
|
|
48
|
+
cwd: process.cwd(),
|
|
49
|
+
stderr: "inherit",
|
|
50
|
+
})
|
|
51
|
+
console.log(`\x1b[32msuccess \x1b[0m - tailwindcss installed`)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
const postcssConfig = `
|
|
55
|
+
module.exports = {
|
|
56
|
+
plugins: {
|
|
57
|
+
tailwindcss: {},
|
|
58
|
+
autoprefixer: {},
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
fs.mkdirSync(path.join(process.cwd(), "src/public/styles"), {
|
|
63
|
+
recursive: true,
|
|
64
|
+
});
|
|
65
|
+
fs.writeFileSync(
|
|
66
|
+
path.join(process.cwd(), "src/public/styles/tailwind.css"),
|
|
67
|
+
`@import 'tailwindcss/base'; @import 'tailwindcss/components'; @import 'tailwindcss/utilities';`
|
|
68
|
+
);
|
|
69
|
+
fs.writeFileSync(
|
|
70
|
+
path.join(process.cwd(), "postcss.config.js"),
|
|
71
|
+
postcssConfig
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if(!fs.existsSync(path.join(process.cwd(), "src/public/styles/tailwind.css"))){
|
|
76
|
+
fs.mkdirSync(path.join(process.cwd(), "src/public/styles"), {
|
|
77
|
+
recursive: true,
|
|
78
|
+
});
|
|
79
|
+
fs.writeFileSync(
|
|
80
|
+
path.join(process.cwd(), "src/public/styles/tailwind.css"),
|
|
81
|
+
`@import 'tailwindcss/base'; @import 'tailwindcss/components'; @import 'tailwindcss/utilities';`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let cmd = process.platform === "win32" ? "npx.cmd" : "npx";
|
|
86
|
+
Bun.spawn({
|
|
87
|
+
cmd: [ cmd, "tailwindcss", process.cwd() + '/tailwind.config.js' , "-i", "src/public/styles/tailwind.css", "-o", config?.tailwind?.output || "public/styles/tailwind.css", "--minify"],
|
|
88
|
+
cwd: process.cwd(),
|
|
89
|
+
stdin: "inherit",
|
|
90
|
+
stderr: "inherit",
|
|
91
|
+
});
|
|
92
|
+
},
|
|
93
|
+
}
|
package/router/index.ts
CHANGED
|
@@ -56,7 +56,11 @@ function spawn_ssr_server(config: any ){
|
|
|
56
56
|
let fileType = handleContentTypes(file)
|
|
57
57
|
if(fs.existsSync(file)){
|
|
58
58
|
let content = await Bun.file(file).text()
|
|
59
|
-
|
|
59
|
+
let data = Buffer.from(content, 'utf-8');
|
|
60
|
+
const compressed = Bun.gzipSync(data);
|
|
61
|
+
return new Response(compressed, {status: 200, headers: {'Content-Type': fileType, 'x-powered-by': 'Vader',
|
|
62
|
+
'Content-Encoding':'gzip',
|
|
63
|
+
...config?.routes.find(route => route.pathname === "*" || route.pathname === url.pathname)?.headers}})
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
let routeMatch = routesRouter.match(url.pathname)
|
|
@@ -76,6 +80,7 @@ function spawn_ssr_server(config: any ){
|
|
|
76
80
|
if(response instanceof Response){
|
|
77
81
|
// set x-powered-by header
|
|
78
82
|
response.headers.set('x-powered-by', 'Vader')
|
|
83
|
+
response.headers.set('Content-Type', 'text/html')
|
|
79
84
|
return response
|
|
80
85
|
}
|
|
81
86
|
throw new Error(`Route ${routeMatch.filePath.split('/routes')[1]} did not return a response in file ${routeMatch.filePath}`)
|
|
@@ -89,11 +94,12 @@ function spawn_ssr_server(config: any ){
|
|
|
89
94
|
}
|
|
90
95
|
}
|
|
91
96
|
let server = Bun.serve({
|
|
92
|
-
port: config
|
|
93
|
-
hostname: config
|
|
97
|
+
port: config?.env?.PORT || 3000,
|
|
98
|
+
hostname: config?.host?.hostname || 'localhost',
|
|
94
99
|
reusePort: true,
|
|
95
100
|
lowMemoryMode: true,
|
|
96
101
|
development: false,
|
|
102
|
+
...(config?.Router?.tls && {tls: {cert: config.Router.tls.cert, key: config.Router.tls.key}}),
|
|
97
103
|
websocket: {
|
|
98
104
|
message(event){
|
|
99
105
|
|
|
@@ -142,7 +148,12 @@ function spawnServer(config: any){
|
|
|
142
148
|
let fileType = handleContentTypes(file)
|
|
143
149
|
if(fs.existsSync(file)){
|
|
144
150
|
let content = await Bun.file(file).text()
|
|
145
|
-
|
|
151
|
+
let data = Buffer.from(content, 'utf-8');
|
|
152
|
+
const compressed = Bun.gzipSync(data);
|
|
153
|
+
|
|
154
|
+
return new Response(compressed, {status: 200, headers: {'Content-Type': fileType, 'x-powered-by': 'Vader', 'x-powered-by': 'Vader',
|
|
155
|
+
'Content-Encoding':'gzip',
|
|
156
|
+
'Accept-Encoding': 'gzip, deflate, br','Connection': 'keep-alive', 'Cache-Control': 'no-cache', 'Pragma': 'no-cache', 'Expires': '0', ...config?.Router?.headers}})
|
|
146
157
|
}
|
|
147
158
|
}
|
|
148
159
|
let route = router.match(url.pathname)
|
|
@@ -161,8 +172,13 @@ function spawnServer(config: any){
|
|
|
161
172
|
window.location.reload()
|
|
162
173
|
}
|
|
163
174
|
</script>
|
|
164
|
-
`
|
|
165
|
-
|
|
175
|
+
`
|
|
176
|
+
const data = Buffer.from(html, 'utf-8');
|
|
177
|
+
const compressed = Bun.gzipSync(data);
|
|
178
|
+
return new Response(compressed, {status: 200, headers: {'Content-Type': 'text/html', 'x-powered-by': 'Vader',
|
|
179
|
+
'Content-Encoding':'gzip',
|
|
180
|
+
'Accept-Encoding': 'gzip, deflate, br','Connection': 'keep-alive', 'Cache-Control': 'no-cache', 'Pragma': 'no-cache', 'Expires': '0',
|
|
181
|
+
...config?.Router?.headers}})
|
|
166
182
|
}
|
|
167
183
|
return new Response('Not Found', {status: 404})
|
|
168
184
|
}
|
package/server/index.js
CHANGED
|
@@ -48,7 +48,21 @@ class Component {
|
|
|
48
48
|
|
|
49
49
|
}
|
|
50
50
|
export async function renderToString(element, args = []) {
|
|
51
|
-
|
|
51
|
+
globalThis.isServer = true
|
|
52
|
+
globalThis.preRender = true
|
|
53
|
+
let data = typeof element === 'function' ? await element(args) : element
|
|
54
|
+
if(data?.tagName === 'html'){
|
|
55
|
+
let body = data.querySelector('body') || new Document().createElement('body')
|
|
56
|
+
let innerHTML = body.innerHTML
|
|
57
|
+
innerHTML = `${innerHTML}`
|
|
58
|
+
body.tagName = 'div'
|
|
59
|
+
body.setAttribute('id', 'root')
|
|
60
|
+
body.innerHTML = innerHTML
|
|
61
|
+
data.removeChild(data.querySelector('body'))
|
|
62
|
+
data.appendChild(body)
|
|
63
|
+
}else if(data){
|
|
64
|
+
data.firstChild.setAttribute('id', 'root')
|
|
65
|
+
}
|
|
52
66
|
let doc = new Document()
|
|
53
67
|
let el = doc.createElement(data)
|
|
54
68
|
|