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 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
- plugins: [cloudflare],
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
  ```
@@ -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 el = tag(props, children)
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
- let isUsingProvider = config?.host?.provider
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
- if(!contents.includes('import Element')){
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
  })
@@ -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
@@ -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
- return tag(props, ...children)
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vaderjs",
3
3
  "description": "A reactive framework for building fast and scalable web applications",
4
- "version": "1.4.2-mpiml56",
4
+ "version": "1.4.2-npiml56",
5
5
  "author": {
6
6
  "name": "Malikwhitten67",
7
7
  "email": "malikwhitterb@gmail.com"
@@ -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
- return {
14
- error: "Not implemented",
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.toString()}${this.nodeValue}`;
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 HTMLTextNode(content);
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 el = tag(props, children)
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
- diff.push(...calculateDiff(oldNode.children[i], newNode.children[i]))
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
- if(!oldNode?._isRoot){
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
- let node = {
57
- state: {},
58
- mainFunction: tag,
59
- _key: tag.name || Math.random().toString(36).substring(7),
60
- $$typeof: 'JSX_CHILD',
61
- firstChild:null,
62
- children: children,
63
- _name: tag.name,
64
- }
65
-
66
- node.firstChild = tag()
67
- node.firstChild.htmlNode._key = node._key
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 node.firstChild
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
- return generateJSX(tag, props, children)
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
- if(typeof children[i] === 'string' || typeof children[i] === 'number'){
118
- children[i] = {
119
- tag: 'TEXT_ELEMENT',
120
- props: {nodeValue: children[i]},
121
- _key: props['$$key'],
122
- parentNode: {tag: tag, props: props, children: children, _key: props['$$key']},
123
- children: []
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
- }else{
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
- if(key.toLowerCase().startsWith('on')){
136
- nodeEl.addEventListener(key.substring(2).toLowerCase(), props[key])
137
- node.events.push({type: key.substring(2).toLowerCase(), listener: props[key]})
138
- continue
139
- }
140
- if(key === '$$key' && !nodeEl._key && nodeEl.nodeType === 1
141
- ){
142
- Object.defineProperty(nodeEl, '_key', {
143
- value: props[key],
144
- writable: true
145
- })
146
- continue
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
- switch(true){
163
- case Array.isArray(props.ref.current):
164
- if(!props.ref.current.find((el) => el === nodeEl)){
165
- props.ref.current.push(nodeEl)
166
- }
167
- break;
168
- case props.ref.current === HTMLElement:
169
- props.ref.current = nodeEl
170
- break;
171
- case props.ref.current === null:
172
- props.ref.current = nodeEl
173
- break;
174
- case typeof props.ref === 'function' && !window.hasRan.includes(props.ref):
175
- window.hasRan.push(props.ref)
176
- props.ref(nodeEl)
177
- setTimeout(() => {
178
- window.hasRan.filter((el) => el !== props.ref)
179
- }, 0)
180
- break;
181
- default:
182
- props.ref.current = nodeEl
183
- break;
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
- for(var i = 0; i < children.length; i++){
192
- if(children[i]){
193
- if(children[i].tag === 'TEXT_ELEMENT'){
194
- nodeEl.appendChild(document.createTextNode(children[i].props.nodeValue))
195
- }
196
- nodeEl.appendChild(Element(children[i].tag, children[i].props, ...children[i].children).htmlNode)
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
- function handleDiff(diff){
207
- for(var i = 0; i < diff.length; i++){
208
- switch(true){
209
- case diff[i].type === 'REPLACE' && !diff[i].oldNode._isRoot:
210
- let parent = diff[i].oldNode.parentNode
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
- case diff[i].type === 'PROPS':
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, initialValue) => {}
221
- export function useRef(name, initialValue){
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 = () => memoizedRefs.find((el) => el.name === name).ref
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) => el._key === memoizedFunctions.find((el) => el.mainFunction === node)._key)
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
- export function useEffect(fn, deps){
252
- if(!effects.find((el) => el.fn.toString() === fn.toString())){
253
- effects.push({fn, deps})
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 [state, dispatch]
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.effects = []
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
- switch(true){
297
- case diff[i].type === 'REPLACE' && !diff[i].oldNode._isRoot:
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
- case diff[i].type === 'PROPS':
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
- diff.push(...this.calculateDiff(oldNode.children[i], newNode.children[i]))
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
- if(!oldNode?._isRoot){
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
- useEffect(fn, deps){
340
- if(!this.effects.find((el) => el.fn.toString() === fn.toString())){
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 = this.firstChild.htmlNode
362
- if(dEl.tagName === 'HTML'){
363
- let firstChild = dEl.querySelector('body').firstChild
364
- dEl = firstChild
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').firstChild : this.render().htmlNode)
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 [getState, setState]
371
+
372
+ }
373
+ return [getState, setState]
375
374
 
376
375
  }
377
- useReducer(name, reducer, initialState){
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 [state, dispatch]
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: vnode.name || Math.random().toString(36).substring(7)})
399
+ let comp = new Component({ $$key: vnode.name || Math.random().toString(36).substring(7) })
400
400
  vnode = vnode.bind(comp)
401
- comp.render = () => {
402
- return vnode(...passProps)
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
- if(comp.firstChild.htmlNode.tagName === 'HTML'){
408
- let hasHead = comp.firstChild.htmlNode.querySelector('head') ? true : false
409
- let hasBody = comp.firstChild.htmlNode.querySelector('body') ? true : false
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
- return new Response(content, {status: 200, headers: {'Content-Type': fileType, 'x-powered-by': 'Vader'}})
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.env.PORT || 3000,
93
- hostname: config.host.hostname || 'localhost',
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
- return new Response(content, {status: 200, headers: {'Content-Type': fileType, 'x-powered-by': 'Vader'}})
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
- return new Response(html, {status: 200, headers: {'Content-Type': 'text/html', 'x-powered-by': 'Vader'}})
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
- let data = typeof element === 'function' ? await element(args) : element
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