vaderjs 1.3.3-4944326ca411 → 1.3.3-612-hotfix

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.
Files changed (3) hide show
  1. package/package.json +4 -2
  2. package/runtime/vader.js +1 -1
  3. package/vader.js +285 -291
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "vaderjs",
3
3
  "description": "A Reactive library aimed to helping you build reactive applications inspired by react.js",
4
4
  "module": "vader.js",
5
- "version": "1.3.3-4944326ca411",
5
+ "version": "1.3.3-612-hotfix",
6
6
  "bin": {
7
7
  "vader": "./vader.js"
8
8
  },
@@ -29,7 +29,9 @@
29
29
  "dependencies": {
30
30
  "glob": "latest",
31
31
  "puppeteer":"latest",
32
- "dotenv":"latest"
32
+ "dotenv":"latest",
33
+ "prettier": "latest",
34
+ "source-map": "latest"
33
35
 
34
36
  }
35
37
  }
package/runtime/vader.js CHANGED
@@ -1 +1 @@
1
- window.Vader={version:"1.3.3"},window.componentRegistry={};let errors={"SyntaxError: Unexpected token '<'":"You forgot to enclose tags in a fragment <></>"},mounts=[],hasRan=[];export const strictMount=(e,t)=>{let s=setInterval((()=>{document.querySelector(`[key="${e}"]`)&&!hasRan.includes(e)&&(clearInterval(s),t(),hasRan.push(e))}),120)};export class Component{constructor(){this.state={},this.key=null,this.components={},this.mounted=!1,this.checkIFMounted(),this.memoizes=[],this.functions=[],this.children=[],this.parentNode={},this.request={headers:{},method:"GET",params:{},path:"",query:{}},this.response={json:e=>{},send:e=>{},redirect:e=>{},render:async e=>{},log:e=>{},setQuery:e=>{}},this.router={use:e=>{}}}createComponent(e,t,s){function isClass(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}let r=isClass(e)?new e(t):null;if(!e)throw new Error("Component must be defined");let i=new Component(t);if(isClass(e))r.props=t||{},r.props.children=s.join("")||[],r.props.children=s.join(""),r.parentNode=this,r.request=this.request,r.response=this.response,r.key=r.props.key?r.props.key:Math.random(),i=r;else{e.toString();i.key=e.toString().split('key="')[1]?e.toString().split('key="')[1].split('"')[0]:null;let r=[];Object.keys(t).forEach((e=>{if(e.startsWith("$props")&&(r.push(t[e]),delete t[e]),e.startsWith("$_ternary")){let s=t[e];delete t[e],Object.keys(s).forEach((e=>{t[e]=s[e]}))}})),t=t?{...t,...r.reduce(((e,t)=>({...e,...t})),{}),children:s.join("")||[]}:{children:s.join("")||[]};let n={key:i.key?i.key:Math.random(),isUnique:!!i.key,render:()=>e.apply(i,[t]),request:this.request,isChild:!0,response:this.response,params:this.request.params,queryParams:this.request.query,reset:i.reset.bind(i),onMount:i.onMount.bind(i),useState:null,router:{use:i.router.use.bind(i)},bindMount:i.bindMount.bind(i),memoize:i.memoize.bind(i),createComponent:i.createComponent.bind(i),isChild:!1,useState:i.useState.bind(i),parseStyle:i.parseStyle.bind(i),bind:i.bind.bind(i),useRef:i.useRef.bind(i),request:this.request,response:this.response,useReducer:i.useReducer.bind(i),hydrate:i.hydrate.bind(i),onUnmount:i.onUnmount.bind(i),parentNoe:this,props:{...t,children:s.join("")||[]}};i.render=n.render,i=n,i.props.children=s.join("")||[]}return this.components[i.key]||(this.components[i.key]=i),!this.children.includes(i)&&this.children.push(i),this.components[i.key]}reset(){Object.keys(this.components).forEach((e=>{this.components[e].onUnmount(),delete this.components[e]})),this.state={},this.children=[]}memoize(e){if(!0==!this.memoizes.includes(e.key))this.memoizes.push(e.key),this.components[e.key]=e;let t=this.components[e.key];t.bindMount(),t.parentNode=this,t.props=e.props,t.request=this.request,t.response=this.response,t.onMount=e.onMount.bind(e),t.onUnmount=e.onUnmount.bind(e);let s=t.render();return s&&s.split(">,").length>1&&(s=s.replaceAll(">,",">")),t.nokey?s:`<div key="${t.key}">${s}</div>`}parseStyle(e){let t="";return Object.keys(e).forEach((s=>{let r=e[s];s=s.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,"$1-$2").toLowerCase(),t+=`${s}:${r};`})),t}bindMount(){mounts.push(this)}domDifference(e,t){let s=[];for(let r=0;r<e.length;r++){let i=e[r],n=t[r];i&&n&&!i.isEqualNode(n)&&s.push({type:"replace",old:i,new:n.cloneNode(!0)})}return s}updateChangedElements(e){e.forEach((e=>{switch(e.type){case"replace":e.old.replaceWith(e.new);break;case"remove":e.old.remove();break;case"add":e.old.appendChild(e.new.cloneNode(!0))}}))}hydrate(e){if(e){console.log("hydrating");let t=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelector(`[ref="${e}"]`);document.querySelector(`[ref="${e}"]`);document.querySelector(`[ref="${e}"]`).replaceWith(t)}else{if(this.key?document.querySelector(`[key="${this.key}"]`):null){let e=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelector(`[key="${this.key}"]`),t=document.querySelector(`[key="${this.key}"]`),s=this.domDifference(t.children,e.children);this.updateChangedElements(s)}}}patch(e,t){const s=this.domDifference(e,t);this.updateChangedElements(s)}handleObject(obj){try{obj=JSON.parse(obj)}catch(e){}return eval(obj)}bind(e,t,s,r,...i){return s+=this.key,window["callFunctions"+this.key]=(e,t)=>{console.log("called");let s=this.functions.find((t=>t.ref===e));s&&s.func(t)},this.functions.find((e=>e.ref===s))||this.functions.push({ref:s,func:e}),t?e:`((event)=>{callFunctions${this.key} ? callFunctions${this.key}('${s}', event) : null})(event)`}setState(e,t){this.state=e,this.hydrate(t)}useState(e,t){this.state.hasOwnProperty(e)||(this.state[e]=t);return[(()=>this.state[e])(),(t,s)=>{this.state[e]=t,this.hydrate(s)}]}useRef(e=null,t){this.state[e]||(this.state[e]=t);return{bind:e+this.key,current:(()=>document.querySelector(`[ref="${e+this.key}"]`)||t)()}}useReducer(e=null,t,s=null){this.state[e]||(this.state[e]=t);const getValue=()=>this.state[e];let r=getValue();return[getValue(),(t,i)=>{const n=s(r,t)??t;this.state[e]=n,this.hydrate(i),r=getValue()}]}render(){}checkIFMounted(){new MutationObserver((e=>{e.forEach((e=>{e.target.querySelector(`[key="${this.key}"]`)&&!this.mounted&&(this.onMount(),this.mounted=!0),Array.from(e.removedNodes).find((e=>e.attributes&&e.attributes.key&&e.attributes.key.value===this.key))&&(this.onUnmount(),this.reset())}))})).observe(document.body,{childList:!0,subtree:!0})}onMount(){}onUnmount(){}}export const useState=(e,t)=>{this.state[e]||(this.state[e]=t);return[states[e],(t,s)=>{states[e]=t,this.hydrate(s)}]};export const useReducer=(e,t)=>[e,e=>{}];export const useRef=e=>({current:e,bind:""});export class Link extends Component{constructor(e){super(e),this.props=e,this.link=document.createElement("a"),this.key=e.href+Math.random(),this.nokey=!0}render(){return this.link.innerHTML=this.props.children,this.link.setAttribute("id",this.props?.href),this.link.style=this.props?.style,this.link.setAttribute("class",this.props?.class),this.link.setAttribute("onclick",`window.history.pushState({}, '', '${this.props?.href}'); window.dispatchEvent(new Event('popstate'));`),this.link.outerHTML}}export class Image extends Component{constructor(e){super(e),this.props={src:e.src,class:e.class,style:e.style,blur:e.blur,width:e.width,height:e.height,optimize:e.optimize||!0,loader:e.loader||!0,alt:e.alt||"image",ref:e.ref||null},this.key=e.src+Math.random(),this.img=document.createElement("img"),this.placeholder=document.createElement("div")}render(){if(window.isServer)return"";let[e,t]=this.useState("loaded",!1),s=this.useRef("hookref",null),r=this.props.width?this.props.width:window.innerWidth/2,i=this.props.height?this.props.height:window.innerHeight/2;if(!this.props.src)throw new Error("Image src is required");return this.img.setAttribute("src",this.props.src),this.img.setAttribute("class",this.props.class),this.img.setAttribute("style",this.props.style?this.props.style:""),this.img.setAttribute("width",r),this.img.setAttribute("ref",s.bind),this.img.referrerPolicy="no-referrer",this.img.setAttribute("height",i),this.img.setAttribute("loading","lazy"),this.img.setAttribute("alt",this.props.alt),this.props.blur&&this.img.setAttribute("style",`filter: blur(${this.props.blur}px);`),this.props.optimize&&this.img.setAttribute("style",`image-rendering: -webkit-optimize-contrast; object-fit: cover; object-position: center; ${this.props.style?this.props.style:""}`),!this.props.loader||e||window.isServer||(this.placeholder.setAttribute("style",`width: ${r}px; height: ${i}px; background: #eee;`),this.placeholder.setAttribute("class","vader-image-placeholder"),this.placeholder.innerHTML=this.props.loader,window.isServer)?void 0:(this.img.onload=()=>{t(!0,s.bind)},`<span ref="${s.bind}">${e?this.img.outerHTML:this.placeholder.outerHTML}</span>`)}}export class Html extends Component{constructor(e){super(e),this.props={children:e.children,lang:e.lang||"en",attributes:e.attributes||{}},this.key="html",this.html=document.createElement("div")}render(){return window.isServer?(this.html.innerHTML=this.props.children,this.html.setAttribute("lang",this.props.lang?this.props.lang:"en"),this.props.attributes&&Object.keys(this.props.attributes).forEach((e=>{this.html.setAttribute(e,this.props.attributes[e])})),this.html.innerHTML):this.props.children}onMount(){console.log("Document Has Been Mounted")}}export class Head extends Component{constructor(e){super(e),this.props=e,this.key="head",this.head=document.createElement("head")}render(){return""}onMount(){if(!this.state.hasMounted&&window.isServer){document.head.innerHTML=this.props.children+document.head.innerHTML,document.querySelectorAll("script[eager]").forEach((async e=>{if(!e.getAttribute("src"))throw new Error("Eager scripts must be external");e.remove();let t=e.getAttribute("src"),s=document.createElement("script"),r=await fetch(t).then((e=>e.text()));s.innerHTML=r,s.setAttribute("srcid",t),document.querySelector(`[srcid="${t}"]`)||document.head.prepend(s)})),this.state.hasMounted=!0}}}export class Script extends Component{constructor(e){super(e),this.props={children:e.children},this.key="script",this.script=document.createElement("script")}render(){return this.script.innerHTML=this.props.children.split("\n").join(";\n"),this.script.outerHTML}onMount(){document.head.appendChild(this.script),document.body.querySelector(`[key="${this.key}"]`).remove()}}export default{Component:Component,useRef:useRef,useReducer:useReducer,useState:useState,strictMount:strictMount,Link:Link,Image:Image,Head:Head,Script:Script,Html:Html};
1
+ window.Vader={version:"1.3.3"},window.componentRegistry={};let errors={"SyntaxError: Unexpected token '<'":"You forgot to enclose tags in a fragment <></>"},mounts=[],hasRan=[];export const strictMount=(e,t)=>{let s=setInterval((()=>{document.querySelector(`[key="${e}"]`)&&!hasRan.includes(e)&&(clearInterval(s),t(),hasRan.push(e))}),120)};export class Component{constructor(){this.$_vaderElement=!0,this.state={},this.key=null,this.components={},this.mounted=!1,this.checkIFMounted(),this.memoizes=[],this.functions=[],this.children=[],this.noKey=!1,this.parentNode={},this.request={headers:{},method:"GET",params:{},path:"",query:{}},this.response={json:e=>{},send:e=>{},redirect:e=>{},render:async e=>{},log:e=>{},setQuery:e=>{}},this.router={use:e=>{}}}createComponent(e,t,s){function r(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}let i=r(e)?new e(t):null;if(!e)throw new Error("Component must be defined");let n=[];Object.keys(t).forEach((e=>{if(e.startsWith("$props")&&(n.push(t[e]),delete t[e]),e.startsWith("$_ternary")){let s=t[e];delete t[e],Object.keys(s).forEach((e=>{t[e]=s[e]}))}}));let o=new Component(t);if(r(e))i.props=t||{},i.props.children=s.join("")||[],i.props.children=s.join(""),i.parentNode=this,i.type="class ",i.request=this.request,i.response=this.response,i.key=i.props.key?i.props.key:Math.random(),o=i;else{e.toString();o.key=e.toString().split('key="')[1]?e.toString().split('key="')[1].split('"')[0]:null,t=t?{...t,...n.reduce(((e,t)=>({...e,...t})),{}),children:s.join("")||[]}:{children:s.join("")||[]};let r={key:o.key?o.key:Math.random(),isUnique:!!o.key,render:()=>e.apply(o,[t]),request:this.request,isChild:!0,response:this.response,params:this.request.params,queryParams:this.request.query,reset:o.reset.bind(o),onMount:o.onMount.bind(o),useState:null,router:{use:o.router.use.bind(o)},bindMount:o.bindMount.bind(o),memoize:o.memoize.bind(o),createComponent:o.createComponent.bind(o),isChild:!1,useState:o.useState.bind(o),parseStyle:o.parseStyle.bind(o),bind:o.bind.bind(o),useRef:o.useRef.bind(o),request:this.request,response:this.response,useReducer:o.useReducer.bind(o),hydrate:o.hydrate.bind(o),onUnmount:o.onUnmount.bind(o),type:"function",parentNoe:this,props:{...t,children:s.join("")||[]}};o.render=r.render,o=r,o.props.children=s.join("")||[]}return this.components[o.key]||(this.components[o.key]=o),!this.children.includes(o)&&this.children.push(o),this.components[o.key]}reset(){Object.keys(this.components).forEach((e=>{this.components[e].onUnmount(),delete this.components[e]})),this.state={},this.children=[]}memoize(e){if(!0==!this.memoizes.includes(e.key))this.memoizes.push(e.key),this.components[e.key]=e;let t=this.components[e.key];"class"!==t.type||t.$_vaderElement||console.error(`class ${t.constructor.name} must extend Component`),t.bindMount(),t.parentNode=this,t.props=e.props,t.request=this.request,t.response=this.response,t.onMount=e.onMount.bind(e),t.onUnmount=e.onUnmount.bind(e);let s=t.render();return s&&s.split(">,").length>1&&(s=s.replaceAll(">,",">")),t.nokey||t.noKey?s:`<div key="${t.key}">${s}</div>`}parseStyle(e){let t="";return Object.keys(e).forEach((s=>{let r=e[s];s=s.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,"$1-$2").toLowerCase(),t+=`${s}:${r};`})),t}bindMount(){mounts.push(this)}domDifference(e,t){let s=[];for(let r=0;r<e.length;r++){let i=e[r],n=t[r];if(i&&n&&i.childNodes.length>0&&n.childNodes.length>0){console.log("equal");let e=this.domDifference(Array.from(i.childNodes),Array.from(n.childNodes));s.push(...e)}i&&n&&0===i.childNodes.length&&0===n.childNodes.length?i.isEqualNode(n)||s.push({type:"replace",old:i,new:n}):i&&n&&Array.from(i.attributes).length!==Array.from(n.attributes).length&&s.push({type:"replace",old:i,new:n})}return s}updateChangedElements(e){e.forEach((e=>{if(e)switch(e.type){case"replace":e.old.replaceWith(e.new);break;case"remove":e.old.remove();break;case"add":e.old.appendChild(e.new.cloneNode(!0))}}))}hydrate(e){if(e){console.log(e.bind);let t=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelectorAll(`[ref="${e.bind?e.bind:e}"]`),s=document.querySelectorAll(`[ref="${e?e.bind:e}"]`);t.forEach((e=>{let t=Array.from(s).find((t=>t.getAttribute("ref")===e.getAttribute("ref")));if(t){let s=this.domDifference(Array.from(t.childNodes),Array.from(e.childNodes))[0];this.updateChangedElements([s])}}))}else{let e=this.key?document.querySelector(`[key="${this.key}"]`):null;if(console.log(e),e){let t=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelector(`[key="${this.key}"]`),s=e,r=this.domDifference([s],[t]);this.updateChangedElements(r)}}}patch(e,t){const s=this.domDifference(e,t);this.updateChangedElements(s)}handleObject(obj){try{obj=JSON.parse(obj)}catch(e){}return eval(obj)}bind(e,t,s,r,...i){return s+=this.key,window["callFunctions"+this.key]=(e,t)=>{let s=this.functions.find((t=>t.ref===e));s&&s.func(t)},this.functions.find((e=>e.ref===s))||this.functions.push({ref:s,func:e}),t?e:`((event)=>{callFunctions${this.key} ? callFunctions${this.key}('${s}', event) : null})(event)`}setState(e,t){this.state=e,this.hydrate(t)}useState(e,t){this.state.hasOwnProperty(e)||(this.state[e]=t);return[(()=>this.state[e])(),(t,s)=>{this.state[e]=t,this.hydrate(s)}]}useRef(e=null,t){this.state[e]||(this.state[e]=t);return{bind:e+this.key,current:(()=>document.querySelector(`[ref="${e+this.key}"]`)||t)()}}useReducer(e=null,t,s=null){this.state[e]||(this.state[e]=t);const r=()=>this.state[e];let i=r();return[r(),(t,n)=>{const o=s(i,t)??t;this.state[e]=o,this.hydrate(n),i=r()}]}render(){}checkIFMounted(){new MutationObserver((e=>{e.forEach((e=>{e.target.querySelector(`[key="${this.key}"]`)&&!this.mounted&&(this.onMount(),this.mounted=!0),Array.from(e.removedNodes).find((e=>e.attributes&&e.attributes.key&&e.attributes.key.value===this.key))&&(this.onUnmount(),this.reset())}))})).observe(document.body,{childList:!0,subtree:!0})}onMount(){}onUnmount(){}}export const useState=(e,t)=>{this.state[e]||(this.state[e]=t);return[states[e],(t,s)=>{states[e]=t,this.hydrate(s)}]};export const useReducer=(e,t)=>[e,e=>{}];export const useRef=e=>({current:e,bind:""});export class Link extends Component{constructor(e){super(e),this.props=e,this.link=document.createElement("a"),this.key=e.href+Math.random(),this.nokey=!0}render(){return this.link.innerHTML=this.props.children,this.link.setAttribute("id",this.props?.href),this.link.style=this.props?.style,this.link.setAttribute("class",this.props?.class||this.props?.className),this.link.setAttribute("onclick",`window.history.pushState({}, '', '${this.props?.href}'); window.dispatchEvent(new Event('popstate'));`),this.link.outerHTML}}export class Image extends Component{constructor(e){super(e),this.props={src:e.src,class:e.class,style:e.style,blur:e.blur,width:e.width,height:e.height,optimize:e.optimize||!0,loader:e.loader||!0,alt:e.alt||"image",ref:e.ref||null},this.key=e.src+Math.random(),this.img=document.createElement("img"),this.placeholder=document.createElement("div")}render(){if(window.isServer)return"";let[e,t]=this.useState("loaded",!1),s=this.useRef("hookref",null),r=this.props.width?this.props.width:window.innerWidth/2,i=this.props.height?this.props.height:window.innerHeight/2;if(!this.props.src)throw new Error("Image src is required");return this.img.setAttribute("src",this.props.src),this.img.setAttribute("class",this.props.class),this.img.setAttribute("style",this.props.style?this.props.style:""),this.img.setAttribute("width",r),this.img.setAttribute("ref",s.bind),this.img.referrerPolicy="no-referrer",this.img.setAttribute("height",i),this.img.setAttribute("loading","lazy"),this.img.setAttribute("alt",this.props.alt),this.props.blur&&this.img.setAttribute("style",`filter: blur(${this.props.blur}px);`),this.props.optimize&&this.img.setAttribute("style",`image-rendering: -webkit-optimize-contrast; object-fit: cover; object-position: center; ${this.props.style?this.props.style:""}`),!this.props.loader||e||window.isServer||(this.placeholder.setAttribute("style",`width: ${r}px; height: ${i}px; background: #eee;`),this.placeholder.setAttribute("class","vader-image-placeholder"),this.placeholder.innerHTML=this.props.loader,window.isServer)?void 0:(this.img.onload=()=>{t(!0,s.bind)},`<span ref="${s.bind}">${e?this.img.outerHTML:this.placeholder.outerHTML}</span>`)}}export class Html extends Component{constructor(e){super(e),this.props={children:e.children,lang:e.lang||"en",attributes:e.attributes||{}},this.key="html",this.html=document.createElement("div")}render(){return window.isServer?(this.html.innerHTML=this.props.children,this.html.setAttribute("lang",this.props.lang?this.props.lang:"en"),this.props.attributes&&Object.keys(this.props.attributes).forEach((e=>{this.html.setAttribute(e,this.props.attributes[e])})),this.html.innerHTML):this.props.children}onMount(){console.log("Document Has Been Mounted")}}export class Head extends Component{constructor(e){super(e),this.props=e,this.key="head",this.head=document.createElement("head")}render(){return""}onMount(){if(!this.state.hasMounted&&window.isServer){console.log(this.props.children),document.head.innerHTML=this.props.children+document.head.innerHTML,document.querySelectorAll("script[eager]").forEach((async e=>{if(!e.getAttribute("src"))throw new Error("Eager scripts must be external");e.remove();let t=e.getAttribute("src"),s=document.createElement("script"),r=null;await fetch(t).then((e=>{if(404===e.status)throw document.documentElement.setAttribute("error",JSON.stringify({error:`File ${t} not found`,status:404})),new Error(`File ${t} not found`);return e.text()})).then((e=>{r=e})).catch((e=>{throw e})),s.innerHTML=r,s.setAttribute("srcid",t),document.querySelector(`[srcid="${t}"]`)||document.head.prepend(s)})),this.state.hasMounted=!0}}}export class Script extends Component{constructor(e){super(e),this.props={children:e.children},this.key="script",this.script=document.createElement("script")}render(){return this.script.innerHTML=this.props.children.split("\n").join(";\n"),this.script.outerHTML}onMount(){document.head.appendChild(this.script),document.body.querySelector(`[key="${this.key}"]`).remove()}}export default{Component:Component,useRef:useRef,useReducer:useReducer,useState:useState,strictMount:strictMount,Link:Link,Image:Image,Head:Head,Script:Script,Html:Html};
package/vader.js CHANGED
@@ -1,11 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from "fs";
3
3
  import { glob, globSync, globStream, globStreamSync, Glob, } from 'glob'
4
- import puppeteer from 'puppeteer';
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
@@ -23,15 +52,7 @@ let writer = async (file, data) => {
23
52
  return { _written: true };
24
53
  };
25
54
 
26
- let start = Date.now()
27
55
  let bundleSize = 0;
28
- let errorCodes = {
29
- "SyntaxError: Unexpected token '<'": "You forgot to enclose tags in a fragment <></>",
30
- }
31
- /**
32
- * define directories
33
- */
34
-
35
56
 
36
57
  if (!fs.existsSync(process.cwd() + '/dist')) {
37
58
  fs.mkdirSync(process.cwd() + '/dist')
@@ -41,133 +62,46 @@ if (!fs.existsSync(process.cwd() + '/dist')) {
41
62
 
42
63
 
43
64
  if (typeof process.env.isCloudflare !== "undefined" || !fs.existsSync(process.cwd() + '/dist/index.html')) {
44
- let htmlFile = fs.readFileSync(process.cwd() + "/node_modules/vaderjs/runtime/index.html", 'utf8')
45
- fs.writeFileSync(process.cwd() + "/dist/index.html", htmlFile)
65
+ fs.writeFileSync(process.cwd() + "/dist/index.html", '')
46
66
  }
47
67
 
48
68
 
49
69
 
50
70
  function Compiler(func, file) {
51
71
  let string = func;
52
- // Remove block comments
53
-
54
72
  let returns = []
55
73
  let comments = string.match(/\{\s*\/\*.*\*\/\s*}/gs)?.map((comment) => comment.trim());
56
74
 
57
- let savedfuncnames = [];
58
- let functions = string.match(
59
- /(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
60
- )
61
- ?.map((match) => match.trim());
62
-
63
- let functionNames = [];
64
-
65
-
66
- functions && functions.forEach((func) => {
67
- if (
68
- !func.match(
69
- /(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
70
- )
71
- ) {
72
- return;
73
- }
74
-
75
- let name = func.split(" ")[1].split("(")[0].trim();
76
-
77
- let lines = string.match(/return\s*\<>.*\<\/>/gs);
78
-
79
- if (lines) {
80
- for (let i = 0; i < lines.length; i++) {
81
- let line = lines[i];
82
-
83
- if (!functionNames.includes(name)) {
84
- functionNames.push(name);
85
- }
86
- }
87
- }
88
- });
89
75
 
90
- // get all Obj({}) and parse to JSON.stringify
91
76
 
92
- let objects = string.match(/Obj\({.*}\)/gs);
93
77
 
94
- objects && objects.forEach((obj) => {
95
- let key = obj.split("Obj")[1].split("(")[1].split(")")[0].trim();
96
- let newobj = obj.replaceAll(`Obj(${key})`, `${key}`);
97
- // let newobj = obj.replaceAll(`Obj(${key})`, `JSON.parse('${key}')`)
98
- string = string.replaceAll(obj, `this.handleObject('${newobj}')`);
99
- });
100
78
 
101
79
 
102
80
  let childs = [];
103
81
 
104
- const spreadAttributeRegex = /\s*([a-zA-Z0-9_-]+)(\s*\$\s*=\s*{{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)}})/gs;
105
- let spreadMatch;
106
- while ((spreadMatch = spreadAttributeRegex.exec(string)) !== null) {
107
- let [, element, spread] = spreadMatch;
108
- let isJSXComponent = element.match(/[A-Z]/) ? true : false;
109
- if (isJSXComponent) {
110
- continue
111
-
112
- }
113
- let old = spread;
114
-
115
- // turn spread into attributes
116
- spread = spread.replace(/\s*$\s*=\s*/, "");
117
- spread = spread.replace(/{{/, "");
118
- spread = spread.replace(/}}/, "");
119
- spread = spread.replace(/\$\s*=\s*/, "");
120
-
121
- // turn : into =
122
-
123
- // do not split inner Objects ex: {color: 'red', background: {color: 'blue'}} -> {color: 'red', background: {color: 'blue'}}
124
- let splitByCommas = spread.split(/,(?![^{]*})/g);
125
- splitByCommas = splitByCommas.map((e) => e.trim())
126
- splitByCommas = splitByCommas.map((e) => {
127
- switch (true) {
128
- case e.includes('function') || e.includes('=>'):
129
- e = e.replace(/:(.*)/gs, '={$1}')
130
- break;
131
- case e.includes('style'):
132
- e = e.replace(/:(.*)/gs, '="${this.parseStyle($1)}"')
133
- break;
134
- case e.includes('[') && e.includes(']'):
135
- e = e.replace(/:(.*)/gs, '={$1.join(" ")}')
136
- break;
137
- default:
138
- }
139
-
140
- return e.trim()
141
- })
142
82
 
143
- let newSpread = `\t` + splitByCommas.join(' ') + `\t`
144
-
145
- string = string.replace(old, newSpread);
146
-
147
- }
83
+ const spreadAttributeRegex = /\s*([a-zA-Z0-9_-]+)\s*(\$\s*=\s*\{\s*\{[^]*?\}\s*\})/gs;
84
+
148
85
 
149
86
 
150
87
 
151
88
  function extractAttributes(code) {
152
- // Match elements with opening tags
153
- const elementRegex = /<([a-zA-Z0-9_-]+)([^>]*)>/gs;
89
+ // grab $={...} and ={...}
90
+ const elementRegex = /<([a-zA-Z0-9_-]+)([^>]*)>/gs;
154
91
 
155
92
  // Match attributes in an opening tag, including those with ={}
156
93
  // Match attributes in an opening tag, including those with ={...}
157
94
  const attributeRegex =
158
- /\s*([a-zA-Z0-9_-]+)(\s*=\s*("([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}|(?:\([^)]*\)|\{[^}]*\}|()=>\s*(?:\{[^}]*\})?)|\[[^\]]*\]))?/gs;
159
-
160
- // <div $={{color: 'red'}}></div>
95
+ /\s*([a-zA-Z0-9_-]+)(\s*=\s*("(?:[^"\\]*(?:\\.[^"\\]*)*)"|'(?:[^'\\]*(?:\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}|(?:\([^)]*\)|\{[^}]*\}|()=>\s*(?:\{[^}]*\})?)|\[[^\]]*\]))?/gs;
96
+
161
97
 
162
98
 
163
-
164
- // only return elements with attribute {()=>{}} or if it also has parameters ex: onclick={(event)=>{console.log(event)}} also get muti line functions or onClick=()=>{}
165
- const functionAttributeRegex = /\s*([a-zA-Z0-9_-]+)(\s*=\s*{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)})/gs;
99
+ const functionAttributeRegex = /\s*([a-zA-Z0-9_-]+)\s*(=\s*{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)})/gs;
166
100
 
167
101
  let attributesList = [];
168
102
 
169
103
  let spreadAttributes = [];
170
- let spreadMatch;
104
+
171
105
  /**
172
106
  * @search - handle spread for html elements
173
107
  * @keywords - spread, spread attributes, spread props, spread html attributes
@@ -180,36 +114,22 @@ function Compiler(func, file) {
180
114
  *
181
115
  */
182
116
  let functionAttributes = [];
117
+ let spreadFunctions = [];
183
118
  let functionMatch;
184
119
  while ((functionMatch = functionAttributeRegex.exec(code)) !== null) {
185
120
 
186
121
  let [, attributeName, attributeValue] = functionMatch;
187
122
  let attribute = {};
188
123
 
189
- if (attributeValue && attributeValue.includes("=>") || attributeValue && attributeValue.includes("function")
124
+ if (attributeValue && attributeValue.includes("=>")
125
+ && !attributeValue.includes("this.bind")
126
+ || attributeValue && attributeValue.includes("function")
190
127
  && !spreadFunctions.includes(attributeValue)
191
128
  ) {
192
- let functionparams = [];
193
- // ref with no numbers
129
+
194
130
  let ref = Math.random().toString(36).substring(2).split('').filter((e) => !Number(e)).join('')
195
131
  let old = `${attributeName}${attributeValue}`
196
- functionNames.forEach((name) => {
197
- string.split("\n").forEach((line) => {
198
- if (line.includes(name) && line.includes("function")) {
199
- line = line.trim();
200
- line = line.replace(/\s+/g, " ");
201
-
202
- let ps = line.split("(").slice(1).join("(").split(")")[0].trim();
203
-
204
- // remove comments
205
- ps = ps.match(/\/\*.*\*\//gs)
206
- ? ps.replace(ps.match(/\/\*.*\*\//gs)[0], "")
207
- : ps;
208
- functionparams.push({ ref: ref, name: name, params: ps });
209
132
 
210
- }
211
- });
212
- });
213
133
  let elementMatch = string.match(/<([a-zA-Z0-9_-]+)([^>]*)>/gs);
214
134
  let isJSXComponent = false;
215
135
  elementMatch.forEach((element) => {
@@ -227,6 +147,7 @@ function Compiler(func, file) {
227
147
 
228
148
  let newvalue = attributeValue.includes('=>') ? attributeValue.split("=>").slice(1).join("=>").trim() : attributeValue.split("function").slice(1).join("function").trim()
229
149
 
150
+ // add ; after newlines
230
151
 
231
152
 
232
153
  newvalue = newvalue.trim();
@@ -263,7 +184,7 @@ function Compiler(func, file) {
263
184
  newvalue = newvalue.replace(/}\s*$/, '');
264
185
 
265
186
 
266
- functionparams.length > 0 ? params = params + ',' + functionparams.map((e) => e.name).join(',') : null
187
+
267
188
 
268
189
  newvalue = newvalue.replaceAll(',,', ',')
269
190
  let paramnames = params ? params.split(',').map((e) => e.trim()) : null
@@ -273,6 +194,8 @@ function Compiler(func, file) {
273
194
 
274
195
  // add ; after newlines
275
196
  newvalue = newvalue.replaceAll(/\n/g, ";\n")
197
+ // remove () from newvalue
198
+ newvalue = newvalue.replace(/\(\s*=>/gs, '=>').replace(/\function\s*\([^\)]*\)\s*\{/gs, '{')
276
199
 
277
200
  let bind = isJSXComponent ? `${attributeName}='function(${params}){${newvalue}}'` : `${attributeName}="\$\{this.bind(function(){${newvalue}}.bind(this), ${isJSXComponent}, "${ref}", "${paramnames ? paramnames.map((e, index) => {
278
201
  if (e.length < 1) return ''
@@ -294,6 +217,7 @@ function Compiler(func, file) {
294
217
  while ((match = elementRegex.exec(code)) !== null) {
295
218
  let [, element, attributes] = match;
296
219
 
220
+
297
221
  let attributesMatch;
298
222
  let elementAttributes = {};
299
223
 
@@ -305,6 +229,81 @@ function Compiler(func, file) {
305
229
 
306
230
  attributesList.push({ element, attributes: elementAttributes });
307
231
  }
232
+
233
+ let spreadMatch;
234
+ while ((spreadMatch = spreadAttributeRegex.exec(string)) !== null) {
235
+ let [, element, spread] = spreadMatch;
236
+
237
+ let isJSXComponent = element.match(/[A-Z]/) ? true : false;
238
+ if (isJSXComponent) {
239
+ continue
240
+
241
+ }
242
+ let old = spread;
243
+ // turn spread into attributes
244
+ spread = spread.replace(/\s*$\s*=\s*/, "");
245
+ spread = spread.replace(/\$\s*=\s*/, "");
246
+ spread = spread.replace('{{', '')
247
+ spread = spread.replace(/,$/, '');
248
+
249
+
250
+
251
+ let splitByCommas = spread.split(/,(?![^{}]*})/gs).map((e) => {
252
+
253
+
254
+
255
+ switch (true) {
256
+ case e.includes('function') || e.includes('=>'):
257
+ e = e.replace(/\,\s*$/, '');
258
+ // replace commas
259
+ e = e.replace(/,\s*/gs, ',');
260
+ // remove space between (.*) =>
261
+ e = e.replace(/\(\s*=>/gs, '=>');
262
+ e = e.replace(/\s*=>\s*\{/gs, '=>{');
263
+
264
+ // add ; after newlines
265
+ e = e.replace(/\s*(\w+)\s*=>\s*\{/gs, '$1=>{');
266
+ // turn (e) => {e} into function(e){e}
267
+ e = e.replace(/\(([^)]*)\)\s*=>\s*\{/gs, 'function($1){\n');
268
+ e = e.replace(/;/g, ';\n ');
269
+ e = e.replace(/,\s*}\s*$/gs, '}');
270
+
271
+
272
+
273
+ e = e.replace(/:(.*)/gs, '="\${this.bind($1, ' + false + ', "' + Math.random().toString(36).substring(2).split('').filter((e) => !Number(e)).join('') + '", "")}"');
274
+
275
+ break;
276
+ case e.includes('style'):
277
+ e = e.replace(/,\s*$/gs, '');
278
+ e = e.replace(/}\s*$/gs, '');
279
+ e = e.replaceAll(/{\s*$/gs, '');
280
+ e = e.replaceAll(/}\s*$/gs, '');
281
+ e = e.replace(/style:(.*)/gs, 'style="\${this.parseStyle($1)}"');
282
+
283
+
284
+ break;
285
+ case e.includes('[') && e.includes(']'):
286
+ e = e.replace(/:(.*)/gs, '={$1.join(" ")}');
287
+ break;
288
+ default:
289
+ e = e.replace(/:(.*)/gs, '="${$1}"');
290
+ e = e.replace(/,\s*$/gs, '');
291
+ e = e.replace(/}\s*$/gs, '');
292
+ e = e.replaceAll(/{\s*$/gs, '');
293
+
294
+ break;
295
+ }
296
+
297
+ return e.trim();
298
+ });
299
+
300
+ let newSpread = splitByCommas.join(' ').trim().replace(/,$/, '');
301
+
302
+ // remove trailing }
303
+ newSpread = newSpread.replace(/}\s*$/, '')
304
+ newSpread = newSpread.trim().replace(/{\s*$/gs, '')
305
+ string = string.replace(old, newSpread);
306
+ }
308
307
 
309
308
  return attributesList;
310
309
  }
@@ -315,7 +314,6 @@ function Compiler(func, file) {
315
314
 
316
315
  return returns || [];
317
316
  }
318
- // throw error if return is not wrapped in <></> or
319
317
  if (string.match(/return\s*\<>|return\s*\(.*\)/gs) && !string.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs)
320
318
  || string.match(/return\s*\<[a-zA-Z0-9_-]+.*>/gs)
321
319
  ) {
@@ -348,35 +346,41 @@ function Compiler(func, file) {
348
346
  }
349
347
  let usesBraces = returnStatement.match(/return\s*\(/gs) ? true : false;
350
348
 
351
-
352
- // Remove trailing ']' or trailing )
349
+ let attributes = extractAttributes(contents);
353
350
  contents = contents.trim().replace(/\]$/, "")
354
351
  contents = contents.replace(/\)$/, "");
355
352
  usesBraces ? !contents.includes('<>') ? contents = `<>${contents}</>` : null : null
356
353
  updatedContents = contents;
357
- let attributes = extractAttributes(contents);
354
+
358
355
 
359
356
  let newAttributes = [];
360
357
  let oldAttributes = [];
361
358
  attributes.forEach((attribute) => {
362
359
  const { element, attributes } = attribute;
360
+ // make sure it isnt a jsx component
361
+ let isJSXComponent = element.match(/[A-Z]/) ? true : false;
362
+ if (isJSXComponent) {
363
+ return;
364
+ }
363
365
  if (Object.keys(attributes).length === 0) return;
364
366
 
365
367
 
366
368
  newAttributes.push(attribute);
367
369
  for (let key in attributes) {
368
370
 
369
- let value = attributes[key];
371
+ let value = attributes[key];
370
372
  let oldvalue = value;
371
373
  if (value && !value.new) {
374
+
372
375
  if (value && value.includes("={")) {
376
+
373
377
  value = value.replace("=", "");
374
378
  value == "undefined" ? (value = '"') : (value = value);
375
379
 
376
380
  key == 'style'
377
381
  && value.includes("{{")
378
382
  ? value = `{this.parseStyle({${value.split('{{')[1].split('}}')[0]}})}` : null
379
-
383
+
380
384
 
381
385
 
382
386
  value = `="\$${value}",`;
@@ -433,9 +437,7 @@ function Compiler(func, file) {
433
437
  valuestate = valuestate.match(regex) ? valuestate.match(regex)[0].split("useState(")[1].split(")")[0].trim() : valuestate
434
438
 
435
439
 
436
- let newState = `${varType} [${key}, ${setKey}] = this.useState('${key}', ${valuestate}
437
-
438
- `;
440
+ let newState = `${varType} [${key}, ${setKey}] = this.useState('${key}', ${valuestate}`;
439
441
  string = string.replace(line, newState);
440
442
  break;
441
443
  case line.includes("useRef") && !line.includes("import"):
@@ -497,16 +499,12 @@ function Compiler(func, file) {
497
499
 
498
500
  let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
499
501
  let componentAttributes = component.split("<")[1].split(">")[0].split(" ").join(" ").replace(name, "").trim();
500
- // some components will have props that have html inside of them we need to only get the props ex: <Header title={<h1>hello</h1>}></Header> -> title={<h1>hello</h1>} // also spread props ex: <Header {...props}></Header> -> {...props} or {...props, title: 'hello'} or {...props, color:{color: 'red'}}
501
- // grab ...( spread props )
502
- const dynamicAttributesRegex = /(\w+)(?:="([^"]*)")?(?:='([^']*)')?(?:=\{([^}]*)\})?(?:=\{(.*?)\})?(?:={([^}]*)})?(?:{([^}]*)})?|(?:{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|(\.{3}\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|\$=\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\}/gs;
503
-
504
-
502
+ const dynamicAttributesRegex = /(\w+)(?:="([^"]*?)"|='([^']*?)'|(?:=\{([^}]*?)\})?|(?:=\{(.*?)*\})?|(?:={([^}]*?)})?|(?:{([^}]*?)})?|(?:}))?|\$=\s*\{\s*\{\s*([^]*?)\s*\}\s*\}/gs;
505
503
 
506
504
 
507
505
 
508
506
  let props = component.match(dynamicAttributesRegex)
509
-
507
+
510
508
  let filteredProps = [];
511
509
  let isWithinComponent = false;
512
510
  let componentName = name
@@ -518,17 +516,14 @@ function Compiler(func, file) {
518
516
 
519
517
  if (prop === componentName) {
520
518
 
521
- // If the component is encountered, start collecting props
522
519
  isWithinComponent = true;
523
520
  filteredProps.push(prop);
524
521
  } else if (isWithinComponent && prop.includes('=')) {
525
-
522
+
526
523
  if (prop.startsWith('$=')) {
527
524
  let old = prop
528
- prop = prop.replace('$=', '$_ternary=')
529
-
530
- // remove trailing }
531
- prop = prop.replace(/}\s*$/, '')
525
+ prop = prop.replace(/\$\s*=\s*\{\s*\{/, '').replace(/\}\s*\}/, '')
526
+
532
527
  component = component.replace(old, prop)
533
528
  componentAttributes = componentAttributes.replace(old, prop)
534
529
 
@@ -536,14 +531,12 @@ function Compiler(func, file) {
536
531
 
537
532
  }
538
533
  else if (prop.includes('${')) {
539
- // if it has an object inside of it then we should just do soemting:object else we should do something: `${object}`
540
-
541
- prop = prop.replace('="', ':').replace('}"', '}')
542
- if (prop.includes('${')) {
534
+
535
+
536
+ prop = prop.replace('="', ':')
537
+ if (prop.includes('${')) {
543
538
  prop = prop.replace('="', ':')
544
- prop = prop.replace('${', '')
545
- prop = prop.replace('}', '')
546
-
539
+ prop = prop.replace('${', '')
547
540
  }
548
541
  if (prop.includes('="${{')) {
549
542
  prop = prop.replace('${{', '{')
@@ -553,12 +546,21 @@ function Compiler(func, file) {
553
546
  }
554
547
 
555
548
  }
556
- else if (prop.startsWith('={')) {
557
- prop = prop.replace('={', ':`${')
558
- prop.replace('} ', '}`')
549
+ if (prop.includes('={')) {
550
+ let value = prop.split('={')
551
+ let isObj = value[1].match(/^{.*}$/gs) ? true : false
552
+ if (!isObj) {
553
+ // remove trailing }
554
+ value[1] = value[1].replace(/}\s*$/, '')
555
+ }
556
+
557
+ if(value[0] == 'style' && isObj){
558
+ value[1] = `this.parseStyle(${value[1]})`
559
+ }
560
+ prop = `${value[0]}:${value[1]}`
559
561
  }
560
562
 
561
- if (prop.includes('function')) {
563
+ if (prop.includes('function') || prop.includes('=>')){
562
564
  // parse 'function' to function
563
565
  prop = prop.replace("'", '')
564
566
 
@@ -567,13 +569,15 @@ function Compiler(func, file) {
567
569
 
568
570
  }
569
571
 
570
- prop = prop.replace('=function', ':function')
572
+ prop = prop.replace('=function', ':function')
571
573
  }
572
-
574
+
573
575
  filteredProps.push(prop);
574
576
 
575
577
 
576
578
 
579
+ }else if (isWithinComponent && prop.includes('}')) {
580
+
577
581
  }
578
582
 
579
583
 
@@ -588,14 +592,13 @@ function Compiler(func, file) {
588
592
  component = component.replace(prop, '')
589
593
  })
590
594
 
591
- let children = component.split(`<${name}`)[1].split(`</${name}>`)[0].trim().replace(/\s+/g, " ").trim().replace(/,$/, '').replace('>', '').replace(/\/$/, '').trim()
592
-
595
+ let children = new RegExp(`<${name}[^>]*>([^]*)<\/${name}>`, 'gs').exec(component)?.[1] || null;
593
596
 
594
597
  props = filteredProps.join(',').replace(/\s+/g, " ").trim().replace(/,$/, '')
595
598
 
596
599
  let savedname = name;
597
600
 
598
-
601
+
599
602
 
600
603
  name = name + Math.random().toString(36).substring(2);
601
604
  if (children && children.match(componentRegex)) {
@@ -618,6 +621,7 @@ function Compiler(func, file) {
618
621
  }
619
622
 
620
623
  myChildrens.push(child.children);
624
+ childs = childs.filter((e) => e.parent !== name);
621
625
  }
622
626
  });
623
627
 
@@ -680,10 +684,10 @@ function Compiler(func, file) {
680
684
  let text = fs.readFileSync(file, "utf8");
681
685
  if (!file.endsWith('.js') && file.endsWith('.jsx')) {
682
686
  text = Compiler(text, file);
687
+
683
688
  }
684
689
  let dest = file.split('node_modules')[1]
685
- dest = dest.split(baseFolder)[1]
686
- // write to dist
690
+ dest = dest.split(baseFolder)[1]
687
691
  writer(process.cwd() + '/dist/src/' + baseFolder + dest, text)
688
692
  let importname = match.split('import')[1].split('from')[0].trim()
689
693
  let oldImportstring = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
@@ -891,26 +895,20 @@ const glb = await glob("**/**/**/**.{jsx,js}", {
891
895
  });
892
896
  async function Build() {
893
897
  globalThis.isBuilding = true
894
- console.log('Compiling......')
898
+ console.log(globalThis.isProduction ? 'Creating Optimized Production Build\n' : '')
899
+ let str = `Page \t\t\t\t Size\n`
900
+ globalThis.isProduction ? console.log('\x1b[32m%s\x1b[0m', str) : null
895
901
  let reader = async (file) => {
896
902
  let text = await fs.readFileSync(file, "utf8");
897
903
  return text;
898
904
  };
899
905
 
900
906
 
901
-
902
-
903
-
904
-
905
- // Process files in the 'pages' directory
906
- let appjs = '';
907
- let hasWritten = []
907
+
908
908
  function ssg(routes = []) {
909
- globalThis.isBuilding = true
910
- console.log(`Generating html files for ${routes.length} routes`)
909
+ globalThis.isBuilding = true
911
910
  routes.forEach(async (route) => {
912
- if (route.url.includes(':')) {
913
- console.log('Route ' + route.url + ' is a dynamic route and will not be generated')
911
+ if (route.url.includes(':')) {
914
912
  return
915
913
  }
916
914
  let equalparamroute = routes.map((e) => {
@@ -938,65 +936,24 @@ async function Build() {
938
936
  <meta charset="UTF-8">
939
937
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
940
938
  <script type="module" id="meta">
941
- window.history.pushState({}, '', '${route.url}')
942
- window.module = await import('/${route.fileName.replace('.jsx', '.js')}')
943
- let metadata = await module.$metadata
944
- if(metadata && metadata.title){
945
- document.head.innerHTML += '<title>' + metadata.title + '</title>'
946
- }
947
- if(metadata && metadata.description){
948
- document.head.innerHTML += '<meta name="description" content="' + metadata.description + '">'
949
- }
950
- if(metadata && metadata.keywords){
951
- document.head.innerHTML += '<meta name="keywords" content="' + metadata.keywords + '">'
952
- }
953
- if(metadata && metadata.author){
954
- document.head.innerHTML += '<meta name="author" content="' + metadata.author + '">'
955
- }
956
- if(metadata && metadata.image){
957
- let image = metadata.image.file
958
- let type = metadata.image.type
959
-
960
- document.head.innerHTML += '<meta property="og:image" content="' + image + '">'
961
- document.head.innerHTML += '<meta property="og:image:type" content="' + type + '">'
962
- }
963
- if(metadata && metadata.url){
964
- document.head.innerHTML += '<meta property="og:url" content="' + metadata.url + '">'
965
- }
939
+ window.history.pushState({}, '', '${route.url}')
966
940
 
967
- if(metadata && metadata.robot){
968
- document.head.innerHTML += '<meta name="robots" content="' + metadata.robot + '">'
969
- }
970
- if(metadata && metadata.manifest){
971
- document.head.innerHTML += '<link rel="manifest" href="' + metadata.manifest + '">'
972
- }
973
- if(metadata && metadata.tags){
974
- metadata.tags.forEach(tag => {
975
- document.head.innerHTML += tag
976
- })
977
- }
978
-
979
- if(metadata && metadata.styles){
980
- metadata.styles.forEach(style => {
981
- style = style.replaceAll('./', '/')
982
- style = style.replaceAll('../', '/')
983
- style = style.replace("'", '')
984
- document.head.innerHTML += '<link rel="stylesheet" href="' + style + '">'
985
- })
986
- }
987
- if(metadata && metadata.icon){
988
- document.head.innerHTML += '<link rel="icon" href="' + metadata.icon + '">'
989
- }
990
941
  </script>
991
942
  <script type="module" id="router">
992
943
  import VaderRouter from '/router.js'
993
944
  const router = new VaderRouter('${route.url}', 3000)
994
945
  router.get('${route.url}', async (req, res) => {
995
- let module = await import('/${route.fileName.replace('.jsx', '.js')}')
996
- if(Object.keys(module).includes('$prerender') && !module.$prerender){
997
- document.head.setAttribute('prerender', 'false')
946
+ try{
947
+ let module = await import('/${route.fileName.replace('.jsx', '.js')}')
948
+ if(Object.keys(module).includes('$prerender') && !module.$prerender){
949
+ document.head.setAttribute('prerender', 'false')
950
+ }
951
+ res.render(module, req, res, module.$metadata)
952
+ }
953
+ catch(error){
954
+ document.documentElement.setAttribute('error', JSON.stringify({stack: error.stack, message: error.message, at: '${route.fileName}', line: error.lineNumber}))
955
+ throw new Error({stack: error.stack, message: error.message})
998
956
  }
999
- res.render(module, req, res, module.$metadata)
1000
957
  })
1001
958
  ${equalparamroute.length > 0 ? equalparamroute.map((e) => {
1002
959
 
@@ -1057,52 +1014,76 @@ async function Build() {
1057
1014
  globalThis.listen = true;
1058
1015
 
1059
1016
  const browser = await puppeteer.launch({
1060
- headless: "new", args: ['--no-sandbox', '--disable-setuid-sandbox'],
1017
+ headless: "new", args: ['--no-sandbox', '--disable-setuid-sandbox'],
1061
1018
  warning: false,
1062
- })
1063
-
1064
- const browserPID = browser.process().pid
1019
+ })
1065
1020
  try {
1066
1021
 
1067
1022
  route.url = route.url.replaceAll(/\/:[a-zA-Z0-9_-]+/gs, '')
1068
1023
  let page = await browser.newPage();
1069
- await page.goto(`http://localhost:${port}/`, { waitUntil: 'networkidle2' });
1070
- await page.waitForSelector('#root', { timeout: 10000 })
1024
+ // Handle browser errors
1025
+ page.on('error', (err) => {
1026
+ console.error('BROWSER ERROR:', err);
1027
+ });
1028
+ await page.evaluate(() => {
1029
+ window.onerror = function (msg, url, lineNo, columnNo, error) {
1030
+ console.log(msg, url, lineNo, columnNo, error)
1031
+ }
1032
+ })
1033
+ try {
1034
+ page.on('pageerror', async err => {
1035
+ let errorObj = await page.evaluate(() => document.documentElement.getAttribute('error'))
1036
+ console.log('\x1b[31m%s\x1b[0m', 'PAGE ERROR:', errorObj);
1037
+
1038
+ });
1039
+ } catch (error) {
1040
+ browser.close()
1041
+ }
1042
+ // Handle page crashes
1043
+ page.on('crash', () => {
1044
+ console.error('PAGE CRASHED');
1045
+ });
1046
+ page.on('requestfailed', request => {
1047
+ console.error('REQUEST FAILED:', request.url(), request.failure().errorText);
1048
+ });
1049
+ await page.goto(`http://localhost:${port}/`, { waitUntil: 'networkidle2' });
1050
+
1051
+
1052
+
1053
+
1054
+
1055
+
1056
+
1071
1057
  await page.evaluate(() => {
1072
1058
  document.getElementById('meta').remove()
1073
1059
  document.querySelector('#isServer').innerHTML = 'window.isServer = false'
1074
1060
  if (document.head.getAttribute('prerender') === 'false') {
1075
1061
  document.querySelector('#root').innerHTML = ''
1062
+ console.log(`Disabled prerendering for ${window.location.pathname}`)
1076
1063
  }
1077
- })
1078
- const html = await page.content();
1064
+ })
1065
+ let html = await page.content();
1079
1066
 
1080
- await page.close();
1067
+ html = await prettier.format(html, { parser: "html" })
1068
+
1069
+
1081
1070
  await writer(process.cwd() + '/dist/' + (route.url === '/' ? 'index.html' : `${route.url}/` + 'index.html'), html)
1082
- await browser.close();
1083
- server.close()
1071
+
1084
1072
 
1085
1073
  } catch (error) {
1086
- server.close()
1087
- await browser.close();
1088
- }
1074
+ console.log(error)
1075
+ }
1076
+
1089
1077
  finally {
1090
- await browser.close();
1091
- server.close()
1078
+ browser.close()
1079
+ server.close()
1092
1080
  }
1093
- try {
1094
- process.kill(browserPID)
1095
- } catch (error) {
1096
- }
1097
-
1098
-
1099
1081
  })
1100
1082
 
1101
1083
  let timeout = setTimeout(() => {
1102
1084
  globalThis.isBuilding = false
1103
1085
  clearTimeout(timeout)
1104
- }, 1000)
1105
- console.log(`Generated ${routes.length} html files for ${routes.length} routes`)
1086
+ }, 1000)
1106
1087
  }
1107
1088
 
1108
1089
  globalThis.routes = []
@@ -1134,17 +1115,14 @@ async function Build() {
1134
1115
 
1135
1116
 
1136
1117
  let data = await fs.readFileSync(origin, "utf8");
1137
- data = Compiler(data, origin);
1138
-
1139
-
1140
-
1141
- await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), data).then(async () => {
1142
-
1143
-
1144
-
1145
- await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), data)
1146
-
1147
- })
1118
+
1119
+ // gen sourcemap if not production
1120
+ let size = fs.statSync(origin).size;
1121
+ if(!globalThis.isProduction){
1122
+ let { sourceMap } = sourceMapGen({origin:origin, fileName:fileName}, await Compiler(data, origin))
1123
+ await writer(process.cwd() + "/dist/src/maps/" + fileName.replace('.jsx', '.js.map'), JSON.stringify(sourceMap, null, 2))
1124
+ }
1125
+ await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), await Compiler(data, origin))
1148
1126
 
1149
1127
  // configure routing for each page
1150
1128
 
@@ -1208,8 +1186,18 @@ async function Build() {
1208
1186
 
1209
1187
  globalThis.routes.push({ fileName: fileName, url: obj.url, html: '/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html') })
1210
1188
 
1211
-
1212
-
1189
+
1190
+ let stats = {route: obj.url.padEnd(30),
1191
+ size: Math.round(size / 1000) + 'kb',
1192
+ letParentFolder: obj.url.split('/').slice(0, -1).join('/'),
1193
+ isChildRoute: obj.url.split('/').slice(0, -1).join('/').includes(':') ? true : false,
1194
+ parentRoute: obj.url.split('/').slice(0, -1).join('/').split(':')[0],
1195
+
1196
+ }
1197
+ stats.isChildRoute ? stats.route = `? ${obj.url}` : null
1198
+ let string = `${isBasePath ? '+' : '+'} ${stats.route.padEnd(30)} ${stats.size}`
1199
+
1200
+ globalThis.isProduction ? console.log(string) : null
1213
1201
  }
1214
1202
 
1215
1203
  ssg(globalThis.routes)
@@ -1246,10 +1234,7 @@ async function Build() {
1246
1234
  if (name.includes('.jsx')) {
1247
1235
  data = Compiler(data, process.cwd() + "/src/" + name);
1248
1236
 
1249
- await writer(process.cwd() + "/dist/src/" + name.split('.jsx').join('.js'), data).then(async () => {
1250
- await writer(process.cwd() + "/dist/src/" + name.replace('.jsx', '.js'), data)
1251
-
1252
- })
1237
+ await writer(process.cwd() + "/dist/src/" + name.split('.jsx').join('.js'), data)
1253
1238
  return
1254
1239
  }
1255
1240
  bundleSize += fs.statSync(process.cwd() + "/src/" + name).size;
@@ -1297,7 +1282,7 @@ async function Build() {
1297
1282
  }
1298
1283
 
1299
1284
  globalThis.isBuilding = false
1300
- console.log(`📦 Build completed: Build Size -> ${Math.round(bundleSize / 1000)}kb`)
1285
+ console.log(`\nTotal bundle size: ${Math.round(bundleSize / 1000)}kb`)
1301
1286
 
1302
1287
  bundleSize = 0;
1303
1288
 
@@ -1307,7 +1292,7 @@ const s = () => {
1307
1292
 
1308
1293
  const server = http.createServer((req, res) => {
1309
1294
 
1310
- const validExtensions = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg'];
1295
+ const validExtensions = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg', '.map']
1311
1296
 
1312
1297
  if (!validExtensions.some(ext => req.url.endsWith(ext))) {
1313
1298
  req.url = req.url !== '/' ? req.url.split('/')[1] : req.url;
@@ -1330,6 +1315,7 @@ const s = () => {
1330
1315
  let ws = new WebSocket('ws://localhost:${process.env.PORT || 3000}')
1331
1316
  ws.onmessage = (e) => {
1332
1317
  if(e.data === 'reload'){
1318
+ console.log('Reloading...')
1333
1319
  window.location.reload()
1334
1320
  }
1335
1321
  }
@@ -1351,7 +1337,7 @@ const s = () => {
1351
1337
 
1352
1338
 
1353
1339
  function getContentType(filePath) {
1354
- let ext = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg'].includes(path.extname(filePath)) ? path.extname(filePath) : '.html'
1340
+ 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'
1355
1341
  switch (ext) {
1356
1342
  case '.js':
1357
1343
  return 'text/javascript';
@@ -1363,6 +1349,8 @@ const s = () => {
1363
1349
  return 'text/javascript';
1364
1350
  case '.html':
1365
1351
  return 'text/html';
1352
+ case '.map':
1353
+ return 'application/json';
1366
1354
  case '.json':
1367
1355
  return 'application/json';
1368
1356
  case '.png':
@@ -1389,26 +1377,18 @@ const s = () => {
1389
1377
  const PORT = process.env.PORT || 3000;
1390
1378
  server.listen(PORT, () => {
1391
1379
  console.log(`Server is running on port ${PORT}`);
1380
+ globalThis.ws = ws
1392
1381
  });
1393
- let i =
1394
- setInterval(() => {
1395
- if (globalThis.isBuilding && globalThis.devMode) {
1396
-
1397
- ws.clients.forEach((client) => {
1398
- client.send('reload')
1399
- })
1400
- } else {
1401
- clearInterval(i)
1402
- }
1403
- }, 120)
1382
+
1404
1383
 
1405
1384
  }
1406
1385
 
1407
1386
 
1408
1387
  switch (true) {
1409
- case process.argv.includes('--watch') && !process.argv.includes('--build') && !process.argv.includes('--serve'):
1388
+ case process.argv.includes('dev') && !process.argv.includes('build') && !process.argv.includes('start'):
1410
1389
 
1411
1390
  globalThis.devMode = true
1391
+ globalThis.isProduction = false
1412
1392
  console.log(`
1413
1393
  Vader.js v1.3.3
1414
1394
  - Watching for changes in ./pages
@@ -1425,12 +1405,19 @@ Vader.js v1.3.3
1425
1405
  if (event == 'change'
1426
1406
  && !globalThis.isBuilding
1427
1407
  ) {
1408
+ if(globalThis.ws && !globalThis.isWriting){
1409
+ globalThis.ws.clients.forEach((client) => {
1410
+ console.log('Reloading...')
1411
+ client.send('reload')
1412
+ })
1413
+ }
1428
1414
 
1415
+ globalThis.isBuilding = true
1429
1416
  Build()
1430
1417
  }
1431
1418
  }).on('error', (err) => console.log(err))
1432
1419
  })
1433
- let p = process.argv[process.argv.indexOf('--watch') + 1] || process.env.PORT || 3000
1420
+ let p = process.argv[process.argv.indexOf('dev') + 1] || 3000
1434
1421
 
1435
1422
  process.env.PORT = p
1436
1423
  s()
@@ -1438,16 +1425,21 @@ Vader.js v1.3.3
1438
1425
  globalThis.listen = true;
1439
1426
 
1440
1427
  break;
1441
- case process.argv.includes('--build') && !process.argv.includes('--watch') && !process.argv.includes('--serve'):
1428
+ case process.argv.includes('build') && !process.argv.includes('dev') && !process.argv.includes('start'):
1442
1429
  globalThis.devMode = false
1430
+ globalThis.isProduction = true
1431
+ globalThis.routeStates = []
1443
1432
  console.log(`
1444
1433
  Vader.js v1.3.3
1445
1434
  Building to ./dist
1446
1435
  `)
1436
+ if(fs.existsSync(process.cwd() + '/dist/src/maps')){
1437
+ fs.rmSync(process.cwd() + '/dist/src/maps', { recursive: true })
1438
+ }
1447
1439
  Build()
1448
1440
 
1449
1441
  break;
1450
- case process.argv.includes('--serve') && !process.argv.includes('--watch') && !process.argv.includes('--build'):
1442
+ case process.argv.includes('start') && !process.argv.includes('dev') && !process.argv.includes('build'):
1451
1443
  let port = process.argv[process.argv.indexOf('--serve') + 1] || 3000
1452
1444
  process.env.PORT = port
1453
1445
  globalThis.devMode = false
@@ -1459,17 +1451,19 @@ url: http://localhost:${port}
1459
1451
  s()
1460
1452
  break;
1461
1453
  default:
1462
- console.log(`
1454
+ // add color
1455
+ console.log(`
1463
1456
  Vader.js is a reactive framework for building interactive applications for the web built ontop of bun.js!
1464
1457
 
1465
1458
  Usage: vader <command>
1466
1459
 
1467
1460
  Commands:
1468
- --watch (port) Watch the pages folder for changes with hot reloading
1461
+
1462
+ vaderjs dev Start the development server
1469
1463
 
1470
- --build Build the project to ./dist
1464
+ vaderjs build Build the project to ./dist
1471
1465
 
1472
- --serve (400) Serve the project on a port (default 3000 or process.env.PORT)
1466
+ vaderjs start <port> Production Mode (default 3000 or process.env.PORT)
1473
1467
 
1474
1468
  Learn more about vader: https://vader-js.pages.dev/
1475
1469