vaderjs 1.3.3-alpha-150 → 1.3.3-alpha-152
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 +11 -40
- package/package.json +1 -1
- package/runtime/vader.js +1 -1
- package/vader.js +275 -264
package/README.md
CHANGED
|
@@ -66,56 +66,27 @@ vader's compiler automatically handles routing so you wont need to! - it uses a
|
|
|
66
66
|
For pages that have [params] you can derive it using this.request
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Class based components
|
|
69
|
+
# Usage
|
|
72
70
|
|
|
71
|
+
|
|
73
72
|
```jsx
|
|
74
73
|
// pages/home.jsx
|
|
75
74
|
import {Component, useState, useRef} = from 'vaderjs/client'
|
|
76
75
|
import Mycomponent from './src/mycomponent.jsx'
|
|
77
76
|
|
|
78
|
-
export default class extends Component {
|
|
79
|
-
constructor() {
|
|
80
|
-
super();
|
|
81
|
-
this.key = 2 // you can explicitly set key
|
|
82
|
-
}
|
|
83
|
-
render() {
|
|
84
|
-
return <>
|
|
85
|
-
${/**
|
|
86
|
-
or set it directly to the element and hydration will grab it
|
|
87
|
-
**/}
|
|
88
|
-
<div key={2}>
|
|
89
|
-
<p>Hello World</p>
|
|
90
|
-
</div>
|
|
91
|
-
<Mycomponent ..props />
|
|
92
|
-
</>
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
77
|
|
|
97
|
-
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
Function based components
|
|
101
|
-
|
|
102
|
-
```jsx
|
|
103
|
-
import Mycomponent from './src/mycomponent.jsx'
|
|
104
|
-
// function components have direct access to request and response both param way and using this.request or this.response!
|
|
105
78
|
export default function(req, res){
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<h1>hello world</>
|
|
114
|
-
<Mycomponent {...props }/>
|
|
115
|
-
</div>
|
|
116
|
-
</>
|
|
79
|
+
let counterRef = useRef(null)
|
|
80
|
+
let [count, setCount] = useState(0)
|
|
81
|
+
|
|
82
|
+
return <>
|
|
83
|
+
<h1>${count}</h1>
|
|
84
|
+
<button onClick={(count, setCount)=>{setCount(count + 1)}}>
|
|
85
|
+
</>
|
|
117
86
|
}
|
|
87
|
+
|
|
118
88
|
|
|
89
|
+
|
|
119
90
|
```
|
|
120
91
|
|
|
121
92
|
# ServerSide Site Generation (SSG)
|
package/package.json
CHANGED
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 r(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}let n=r(e)?new e(t):null;if(!e)throw new Error("Component must be defined");let i=[];Object.keys(t).forEach((e=>{e.startsWith("$props")&&(i.push(t[e]),delete t[e])})),t=t?{...t,...i.reduce(((e,t)=>({...e,...t})),{}),children:s.join("")||[]}:{children:s.join("")||[]};let o=new Component(t);if(r(e))n.props=t||{},n.props.children=s.join("")||[],n.props.children=s.join(""),n.parentNode=this,n.request=this.request,n.response=this.response,n.key=n.props.key?n.props.key:Math.random(),o=n;else{e.toString();o.key=e.toString().split('key="')[1]?e.toString().split('key="')[1].split('"')[0]:null;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),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];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(">,",">")),`<span key="${e.key}" >${s}</span>`}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 n=e[r],i=t[r];n&&i&&!n.isEqualNode(i)&&s.push({type:"replace",old:n,new:i.cloneNode(!0)})}return s}updateChangedElements(e){e.forEach((e=>{switch(e.type){case"replace":e.old.parentNode.replaceChild(e.new,e.old);break;case"remove":e.old.remove();break;case"add":e.old.appendChild(e.new.cloneNode(!0))}}))}hydrate(e){if(e){(new DOMParser).parseFromString(this.render(),"text/html").body.querySelector(`[ref="${e}"]`),document.querySelector(`[ref="${e}"]`)}else{let e=this.key?document.querySelector(`[key="${this.key}"]`):null,t=(new DOMParser).parseFromString(this.render(),"text/html").body;if(t=document.createElement("div").appendChild(t),!e&&(e=document.querySelector(`[key="${t.attributes?.key?.value||null}"]`)),!e)return void console.error('Hydration failed, component not found got ensure you have set key="a value" on the component or this.key inside of function or render method body');t.querySelectorAll("*").forEach((e=>{e.hasAttribute("key")&&e.innerHTML!==document.querySelector(`[key="${e.attributes.key.value}"]`).innerHTML&&document.querySelector(`[key="${e.attributes.key.value}"]`).replaceWith(e)}))}}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,...n){s=s+this.key||2022;let i={},o=(r=r.replace(/,,/g,",")).replaceAll(",,",",");for(var h in n){let e=n[h];i[o.split(",")[h]]=e}r=r.replace(",,",",");let l=null;e=e.split("\n").join(";");try{l=new Function(`event, ${r}`,` \n return (async (event, ${r}) => { \n ${e.toString()}\n })(event, ${Object.keys(i).join(",")}) \n `)}catch(e){let{message:t}=e;console.error(`Error in function ${s} ${t}`)}return l=l.bind(this),this.functions.find((e=>e.ref===s))||document.addEventListener(`$dispatch_#id=${s}`,(e=>{let{name:t,event:r}=e.detail;if(t===s){let e=this.functions.find((e=>e.ref===s)).params;Object.keys(e).forEach((t=>{e[t]instanceof CustomEvent&&delete e[t],void 0===e[t]?delete e[t]:e[t]})),l(r,...Object.values(e))}})),window.callFunction=(e,t)=>{document.dispatchEvent(new CustomEvent(`$dispatch_#id=${e}`,{detail:{name:e,params:null,event:t}}))},!this.functions.find((e=>e.ref===s))&&this.functions.push({ref:s,params:i}),t?e:`((event)=>{event.target.ev = event; callFunction('${s}', event.target.ev)})(event)`}useState(e,t){this.state[e]||(this.state[e]=t);let s=()=>this.state[e],r=s();return[r,(t,n)=>{this.state[e]=t,this.hydrate(n),r=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 n=r();return[r(),(t,i)=>{const o=s(n,t)??t;this.state[e]=o,this.hydrate(i),n=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)=>{states[e]||(states[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()}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,n=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",n),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: ${n}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.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 r(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}let n=r(e)?new e(t):null;if(!e)throw new Error("Component must be defined");let i=new Component(t);if(r(e))n.props=t||{},n.props.children=s.join("")||[],n.props.children=s.join(""),n.parentNode=this,n.request=this.request,n.response=this.response,n.key=n.props.key?n.props.key:Math.random(),i=n;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=>{e.startsWith("$props")&&(r.push(t[e]),delete t[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(">,",">")),`<span key="${e.key}" >${s}</span>`}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 n=e[r],i=t[r];n&&i&&!n.isEqualNode(i)&&s.push({type:"replace",old:n,new:i.cloneNode(!0)})}return s}updateChangedElements(e){e.forEach((e=>{switch(e.type){case"replace":e.old.parentNode.replaceChild(e.new,e.old);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{let e=this.key?document.querySelector(`[key="${this.key}"]`):null;e&&(e.innerHTML=this.render())}}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,...n){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)`}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 n=r();return[r(),(t,i)=>{const o=s(n,t)??t;this.state[e]=o,this.hydrate(i),n=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()}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,n=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",n),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: ${n}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};
|
package/vader.js
CHANGED
|
@@ -4,10 +4,10 @@ import { glob, globSync, globStream, globStreamSync, Glob, } from 'glob'
|
|
|
4
4
|
import puppeteer from 'puppeteer';
|
|
5
5
|
import http from 'http'
|
|
6
6
|
import { WebSocketServer } from 'ws'
|
|
7
|
-
import { watch } from "fs";
|
|
7
|
+
import { watch } from "fs";
|
|
8
8
|
import path from 'path'
|
|
9
|
-
let config =
|
|
10
|
-
|
|
9
|
+
let config = await import('file://' + process.cwd() + '/vader.config.js').then((e) => e.default || e)
|
|
10
|
+
|
|
11
11
|
|
|
12
12
|
let start = Date.now()
|
|
13
13
|
let bundleSize = 0;
|
|
@@ -31,7 +31,7 @@ if (typeof process.env.isCloudflare !== "undefined" || !fs.existsSync(process.cw
|
|
|
31
31
|
fs.writeFileSync(process.cwd() + "/dist/index.html", htmlFile)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
|
|
36
36
|
function Compiler(func, file) {
|
|
37
37
|
let string = func;
|
|
@@ -108,6 +108,7 @@ function Compiler(func, file) {
|
|
|
108
108
|
let functionMatch;
|
|
109
109
|
while ((functionMatch = functionAttributeRegex.exec(code)) !== null) {
|
|
110
110
|
let [, attributeName, attributeValue] = functionMatch;
|
|
111
|
+
|
|
111
112
|
let attribute = {};
|
|
112
113
|
|
|
113
114
|
if (attributeValue && attributeValue.includes("=>") || attributeValue && attributeValue.includes("function")) {
|
|
@@ -143,7 +144,7 @@ function Compiler(func, file) {
|
|
|
143
144
|
.split(" ")[0];
|
|
144
145
|
isJSXComponent = elementTag.match(/^[A-Z]/) ? true : false;
|
|
145
146
|
}
|
|
146
|
-
});
|
|
147
|
+
});
|
|
147
148
|
// add ; after newlines
|
|
148
149
|
|
|
149
150
|
|
|
@@ -193,16 +194,18 @@ function Compiler(func, file) {
|
|
|
193
194
|
paramnames = paramnames ? paramnames.filter((e) => e.length > 0) : null
|
|
194
195
|
// remove comments
|
|
195
196
|
paramnames = paramnames ? paramnames.map((e) => e.match(/\/\*.*\*\//gs) ? e.replace(e.match(/\/\*.*\*\//gs)[0], "") : e) : null
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
|
|
198
|
+
// add ; after newlines
|
|
199
|
+
newvalue = newvalue.replaceAll(/\n/g, ";\n")
|
|
200
|
+
|
|
201
|
+
let bind = isJSXComponent ? `${attributeName}='function(${params}){${newvalue}}'` : `${attributeName}="\$\{this.bind(function(){${newvalue}}.bind(this), ${isJSXComponent}, "${ref}", "${paramnames ? paramnames.map((e, index) => {
|
|
199
202
|
if (e.length < 1) return ''
|
|
200
203
|
if (e.length > 0) {
|
|
201
204
|
index == 0 ? e : ',' + e
|
|
202
205
|
}
|
|
203
206
|
return e
|
|
204
207
|
}) : ''}" ${params ? params.split(',').map((e) => e.trim()).filter(Boolean).map((e) => `,${e}`).join('') : ''})}"`
|
|
205
|
-
|
|
208
|
+
|
|
206
209
|
string = string.replace(old, bind);
|
|
207
210
|
}
|
|
208
211
|
}
|
|
@@ -228,15 +231,21 @@ function Compiler(func, file) {
|
|
|
228
231
|
|
|
229
232
|
function extractOuterReturn(code) {
|
|
230
233
|
// match return [...]
|
|
231
|
-
let returns = code.match(/return\s
|
|
234
|
+
let returns = code.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs);
|
|
232
235
|
|
|
233
236
|
return returns || [];
|
|
234
237
|
}
|
|
235
|
-
// throw error if return is not wrapped in <></>
|
|
236
|
-
if (string.match(/return\s
|
|
238
|
+
// throw error if return is not wrapped in <></> or
|
|
239
|
+
if (string.match(/return\s*\<>|return\s*\(.*\)/gs) && !string.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs)
|
|
237
240
|
|| string.match(/return\s*\<[a-zA-Z0-9_-]+.*>/gs)
|
|
238
241
|
) {
|
|
239
|
-
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
throw new SyntaxError("You forgot to enclose jsx in a fragment return <> jsx html </> or return (<> jsx html </>) at line " + string.split(/return\s*\<[a-zA-Z0-9_-]+.*>/gs)[0].split('\n').length + ' in file ' + file)
|
|
245
|
+
} catch (error) {
|
|
246
|
+
console.error(error)
|
|
247
|
+
process.exit(1)
|
|
248
|
+
}
|
|
240
249
|
}
|
|
241
250
|
|
|
242
251
|
let outerReturn = extractOuterReturn(string);
|
|
@@ -248,16 +257,20 @@ function Compiler(func, file) {
|
|
|
248
257
|
|
|
249
258
|
for (let i = 0; i < lines.length; i++) {
|
|
250
259
|
let line = lines[i];
|
|
251
|
-
if (line.match(/return\s
|
|
260
|
+
if (line.match(/return\s*\<>|return\s*\(/gs)) {
|
|
252
261
|
continue;
|
|
253
262
|
}
|
|
254
263
|
contents += line + "\n";
|
|
255
264
|
}
|
|
265
|
+
let usesBraces = returnStatement.match(/return\s*\(/gs) ? true : false;
|
|
256
266
|
|
|
257
|
-
// Remove trailing ']'
|
|
258
|
-
contents = contents.trim().replace(/\]$/, "");
|
|
259
|
-
updatedContents = contents;
|
|
260
267
|
let attributes = extractAttributes(contents);
|
|
268
|
+
// Remove trailing ']' or trailing )
|
|
269
|
+
contents = contents.trim().replace(/\]$/, "")
|
|
270
|
+
contents = contents.replace(/\)$/, "");
|
|
271
|
+
usesBraces ? !contents.includes('<>') ? contents = `<>${contents}</>` : null : null
|
|
272
|
+
updatedContents = contents;
|
|
273
|
+
|
|
261
274
|
|
|
262
275
|
let newAttributes = [];
|
|
263
276
|
let oldAttributes = [];
|
|
@@ -281,6 +294,7 @@ function Compiler(func, file) {
|
|
|
281
294
|
? value = `{this.parseStyle({${value.split('{{')[1].split('}}')[0]}})}` : null
|
|
282
295
|
|
|
283
296
|
|
|
297
|
+
|
|
284
298
|
value = `="\$${value}",`;
|
|
285
299
|
string = string.replace(oldvalue, value);
|
|
286
300
|
|
|
@@ -292,34 +306,13 @@ function Compiler(func, file) {
|
|
|
292
306
|
|
|
293
307
|
}
|
|
294
308
|
} else if (value && value.new) {
|
|
295
|
-
string = string.replace(
|
|
309
|
+
string = string.replace(oldvalue, value.new);
|
|
296
310
|
}
|
|
297
311
|
}
|
|
298
312
|
});
|
|
299
313
|
});
|
|
300
314
|
|
|
301
|
-
let retursnString = [];
|
|
302
|
-
let outerReturnString = extractOuterReturn(string);
|
|
303
315
|
|
|
304
|
-
outerReturnString.forEach((returnStatement) => {
|
|
305
|
-
let lines = returnStatement.split("\n");
|
|
306
|
-
let code = "";
|
|
307
|
-
for (let i = 0; i < lines.length; i++) {
|
|
308
|
-
let line = lines[i];
|
|
309
|
-
|
|
310
|
-
code += line + "\n";
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
code = code.trim().replace(/\<\/\>$/, "");
|
|
314
|
-
retursnString.push(code);
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
retursnString.forEach((returnStatement, index) => {
|
|
318
|
-
let old = outerReturnString[index];
|
|
319
|
-
|
|
320
|
-
let newReturn = `${returnStatement}</>`;
|
|
321
|
-
string = string.replace(old, newReturn);
|
|
322
|
-
});
|
|
323
316
|
|
|
324
317
|
if (comments) {
|
|
325
318
|
comments.forEach((comment) => {
|
|
@@ -408,149 +401,154 @@ function Compiler(func, file) {
|
|
|
408
401
|
let componentMatch = body.match(componentRegex);
|
|
409
402
|
let topComponent = "";
|
|
410
403
|
componentMatch?.forEach(async (component) => {
|
|
411
|
-
|
|
404
|
+
|
|
412
405
|
let [, element, attributes] = component;
|
|
413
|
-
|
|
406
|
+
|
|
414
407
|
|
|
415
408
|
!isChild ? (topComponent = component) : null;
|
|
416
|
-
let before = component;
|
|
409
|
+
let before = component;
|
|
417
410
|
|
|
418
411
|
let myChildrens = [];
|
|
419
412
|
|
|
420
413
|
let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
|
|
421
414
|
// 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'}}
|
|
422
415
|
// grab ...( spread props )
|
|
423
|
-
const dynamicAttributesRegex = /(\w+)(?:="([^"]*)")?(?:='([^']*)')?(?:=\{([^}]*)\})?(?:=\{(.*?)\})?(?:={([^}]*)})?(?:{([^}]*)})?|(\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})/gs;
|
|
416
|
+
const dynamicAttributesRegex = /(\w+)(?:="([^"]*)")?(?:='([^']*)')?(?:=\{([^}]*)\})?(?:=\{(.*?)\})?(?:={([^}]*)})?(?:{([^}]*)})?|(?:{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|(\.{3}\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})/gs;
|
|
417
|
+
|
|
418
|
+
|
|
424
419
|
|
|
425
420
|
|
|
426
421
|
|
|
427
422
|
|
|
428
|
-
|
|
429
423
|
let props = component.match(dynamicAttributesRegex)
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
424
|
+
|
|
425
|
+
let filteredProps = [];
|
|
426
|
+
let isWithinComponent = false;
|
|
427
|
+
let componentName = name
|
|
428
|
+
|
|
429
|
+
for (let prop of props) {
|
|
430
|
+
|
|
431
|
+
if (prop.includes(componentName)) {
|
|
432
|
+
// If the component is encountered, start collecting props
|
|
433
|
+
isWithinComponent = true;
|
|
434
|
+
filteredProps.push(prop);
|
|
435
|
+
} else if (isWithinComponent && prop.includes('=')) {
|
|
436
|
+
|
|
437
|
+
if (prop.includes('${')) {
|
|
438
|
+
// if it has an object inside of it then we should just do soemting:object else we should do something: `${object}`
|
|
439
|
+
|
|
440
|
+
prop = prop.replace('="', ':').replace('}"', '}')
|
|
441
|
+
if (prop.includes('${')) {
|
|
442
|
+
prop = prop.replace('="', ':')
|
|
443
|
+
prop = prop.replace('${', '')
|
|
444
|
+
prop = prop.replace('}', '')
|
|
445
|
+
|
|
446
|
+
}
|
|
447
|
+
if (prop.includes('="${{')) {
|
|
448
|
+
prop = prop.replace('${{', '{')
|
|
449
|
+
prop = prop.replace('}}', '}')
|
|
450
|
+
prop = prop.replace('="', ':')
|
|
451
|
+
prop = prop.replace('}"', '}')
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
}
|
|
455
|
+
if (prop.startsWith('={')) {
|
|
456
|
+
prop = prop.replace('={', ':`${')
|
|
457
|
+
prop.replace('} ', '}`')
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (prop.includes('function')) {
|
|
461
|
+
// parse 'function' to function
|
|
462
|
+
prop = prop.replace("'", '')
|
|
463
|
+
|
|
464
|
+
if (prop.endsWith("}'")) {
|
|
465
|
+
prop = prop.replace("}'", '}')
|
|
466
|
+
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
prop = prop.replace('=function', ':function')
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
filteredProps.push(prop);
|
|
473
|
+
|
|
474
|
+
|
|
474
475
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
476
|
+
else if (isWithinComponent && prop.includes('...')) {
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
// Check if spread props are within curly braces
|
|
481
|
+
if (prop.startsWith('{') && prop.endsWith('}')) {
|
|
482
|
+
const spreadObject = prop
|
|
483
|
+
const hasOtherObjects = spreadObject.split(',').filter((e) => e.includes(':')).length > 0;
|
|
484
|
+
|
|
485
|
+
const isValidSpread = spreadObject.includes('...');
|
|
486
|
+
|
|
487
|
+
let processedSpreadObject = '';
|
|
488
|
+
if (isValidSpread) {
|
|
489
|
+
// Split the spreadObject by commas and process each part individually
|
|
490
|
+
const parts = spreadObject.split(',').map((part) => {
|
|
491
|
+
if (part.trim().startsWith('{') && part.trim().endsWith('}')) {
|
|
492
|
+
const nestedParts = part
|
|
493
|
+
.trim()
|
|
494
|
+
.slice(1, -1) // Remove outer {}
|
|
495
|
+
.split(',')
|
|
496
|
+
.map((nestedPart) => {
|
|
497
|
+
return nestedPart.includes('...') ? nestedPart.trim().replace(/\.\.\./, '') : `...${nestedPart.trim()}`;
|
|
498
|
+
});
|
|
499
|
+
return `{${nestedParts.join(',')}}`;
|
|
500
|
+
} else {
|
|
501
|
+
return part.includes('...') ? part.trim() : part.trim().startsWith('{') ? `...${part.trim()}` : `${part.trim()}`;
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
if (!parts.join(',').includes('{(')) {
|
|
478
505
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
if (part.trim().startsWith('{') && part.trim().endsWith('}')) {
|
|
499
|
-
// Handle nested spreads within the object
|
|
500
|
-
const nestedParts = part
|
|
501
|
-
.trim()
|
|
502
|
-
.slice(1, -1) // Remove outer {}
|
|
503
|
-
.split(',')
|
|
504
|
-
.map((nestedPart) => {
|
|
505
|
-
return nestedPart.includes('...') ? nestedPart.trim().replace(/\.\.\./, '') : `...${nestedPart.trim()}`;
|
|
506
|
-
});
|
|
507
|
-
return `{${nestedParts.join(',')}}`;
|
|
508
|
-
} else {
|
|
509
|
-
return part.includes('...') ? part.trim() : part.trim().startsWith('{') ? `...${part.trim()}` : `${part.trim()}`;
|
|
506
|
+
processedSpreadObject = `${parts.join(',')}`
|
|
507
|
+
|
|
508
|
+
} else {
|
|
509
|
+
let prop = parts.join(',')
|
|
510
|
+
prop = prop.replaceAll('{(', '(')
|
|
511
|
+
prop = prop.replaceAll(')}', ')')
|
|
512
|
+
processedSpreadObject = prop
|
|
513
|
+
}
|
|
514
|
+
if (prop.includes('{{')) {
|
|
515
|
+
let prop = parts.join(',')
|
|
516
|
+
prop = prop.replaceAll('{{', '{')
|
|
517
|
+
prop = prop.replaceAll('}}', '}')
|
|
518
|
+
processedSpreadObject = prop
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
} else {
|
|
523
|
+
// Process nested structures within the object
|
|
524
|
+
processedSpreadObject = `{...${spreadObject}}`;
|
|
510
525
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
processedSpreadObject = `${parts.join(',')}`
|
|
515
|
-
|
|
516
|
-
}else{
|
|
517
|
-
let prop = parts.join(',')
|
|
518
|
-
prop = prop.replaceAll('{(', '(')
|
|
519
|
-
prop = prop.replaceAll(')}', ')')
|
|
520
|
-
processedSpreadObject = prop
|
|
526
|
+
|
|
527
|
+
const $propsKey = `$props_${Math.random().toString(36).substring(2)}`;
|
|
528
|
+
filteredProps.push(`${$propsKey}:${processedSpreadObject}`);
|
|
521
529
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
const $propsKey = `$props_${Math.random().toString(36).substring(2)}`;
|
|
530
|
-
filteredProps.push(`${$propsKey}:${processedSpreadObject}`);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
else{
|
|
535
|
-
isWithinComponent = false;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
else {
|
|
533
|
+
isWithinComponent = false;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
538
536
|
|
|
539
537
|
// get inner content of <Component>inner content</Component>
|
|
540
538
|
let children = new RegExp(`<${name}[^>]*>(.*?)<\/${name}>`, "gs").exec(component) ? new RegExp(`<${name}[^>]*>(.*?)<\/${name}>`, "gs").exec(component)[1] : null;
|
|
541
|
-
|
|
539
|
+
|
|
542
540
|
props = filteredProps.join(',')
|
|
543
|
-
|
|
541
|
+
|
|
544
542
|
let savedname = name;
|
|
545
|
-
|
|
546
|
-
|
|
543
|
+
|
|
544
|
+
|
|
547
545
|
|
|
548
546
|
name = name + Math.random().toString(36).substring(2);
|
|
549
547
|
if (children && children.match(componentRegex)) {
|
|
550
548
|
children = parseComponents(children, true);
|
|
551
549
|
childs.push({ parent: name, children: children });
|
|
552
550
|
} else {
|
|
553
|
-
|
|
551
|
+
|
|
554
552
|
children ? childs.push({ parent: name, children: children }) : null;
|
|
555
553
|
}
|
|
556
554
|
|
|
@@ -572,24 +570,22 @@ function Compiler(func, file) {
|
|
|
572
570
|
|
|
573
571
|
|
|
574
572
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
573
|
+
|
|
574
|
+
props = props.replaceAll(`,${savedname}`, '').replaceAll(savedname, '')
|
|
575
|
+
if (props.startsWith(',')) {
|
|
576
|
+
props = props.replace(',', '')
|
|
577
|
+
}
|
|
578
|
+
props = props.replaceAll("='", ":'")
|
|
579
|
+
.replaceAll('=`', ':`')
|
|
582
580
|
.replaceAll('="', ':"')
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
.replaceAll('={', ":`")
|
|
586
|
-
|
|
581
|
+
.replaceAll('={', ':')
|
|
582
|
+
|
|
587
583
|
|
|
588
584
|
/**
|
|
589
585
|
* @memoize - memoize a component to be remembered on each render and replace the old jsx
|
|
590
586
|
*/
|
|
591
587
|
|
|
592
|
-
let replace = "";
|
|
588
|
+
let replace = "";
|
|
593
589
|
replace = `\${this.memoize(this.createComponent(${savedname}, {${props}}, [\`${myChildrens.join(" ")}\`]))}`;
|
|
594
590
|
|
|
595
591
|
body = body.replace(before, replace);
|
|
@@ -779,6 +775,12 @@ function Compiler(func, file) {
|
|
|
779
775
|
|
|
780
776
|
globalThis.isBuilding = false
|
|
781
777
|
globalThis.isWriting = null
|
|
778
|
+
const glb = await glob("**/**/**/**.{jsx,js}", {
|
|
779
|
+
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
780
|
+
cwd: process.cwd() + '/pages/',
|
|
781
|
+
absolute: true,
|
|
782
|
+
recursive: true
|
|
783
|
+
});
|
|
782
784
|
async function Build() {
|
|
783
785
|
globalThis.isBuilding = true
|
|
784
786
|
console.log('Compiling......')
|
|
@@ -804,12 +806,7 @@ async function Build() {
|
|
|
804
806
|
};
|
|
805
807
|
|
|
806
808
|
|
|
807
|
-
|
|
808
|
-
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
809
|
-
cwd: process.cwd() + '/pages/',
|
|
810
|
-
absolute: true,
|
|
811
|
-
recursive: true
|
|
812
|
-
});
|
|
809
|
+
|
|
813
810
|
|
|
814
811
|
// Process files in the 'pages' directory
|
|
815
812
|
let appjs = '';
|
|
@@ -821,10 +818,10 @@ async function Build() {
|
|
|
821
818
|
if (route.url.includes(':')) {
|
|
822
819
|
console.log('Route ' + route.url + ' is a dynamic route and will not be generated')
|
|
823
820
|
return
|
|
824
|
-
}
|
|
825
|
-
let equalparamroute = routes.map((e) => {
|
|
821
|
+
}
|
|
822
|
+
let equalparamroute = routes.map((e) => {
|
|
826
823
|
if (e.url.includes(':')) {
|
|
827
|
-
let url = e.url.split('/:')[0]
|
|
824
|
+
let url = e.url.split('/:')[0]
|
|
828
825
|
if (url && route.url === url) {
|
|
829
826
|
return e
|
|
830
827
|
} else {
|
|
@@ -908,14 +905,14 @@ async function Build() {
|
|
|
908
905
|
res.render(module, req, res, module.$metadata)
|
|
909
906
|
})
|
|
910
907
|
${equalparamroute.length > 0 ? equalparamroute.map((e) => {
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
return `router.get('${e.url}', async (req, res) => {
|
|
915
912
|
let module = await import('/${e.fileName.replace('.jsx', '.js')}')
|
|
916
913
|
res.render(module, req, res, module.$metadata)
|
|
917
914
|
})\n`
|
|
918
|
-
|
|
915
|
+
}) : ''}
|
|
919
916
|
router.listen(3000)
|
|
920
917
|
|
|
921
918
|
</script>
|
|
@@ -932,8 +929,8 @@ async function Build() {
|
|
|
932
929
|
let port = Math.floor(Math.random() * (65535 - 49152 + 1) + 49152)
|
|
933
930
|
|
|
934
931
|
const server = http.createServer((req, res) => {
|
|
935
|
-
|
|
936
|
-
if (req.url === '/') {
|
|
932
|
+
|
|
933
|
+
if (req.url === '/') {
|
|
937
934
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
938
935
|
res.end(document);
|
|
939
936
|
} else {
|
|
@@ -965,26 +962,26 @@ async function Build() {
|
|
|
965
962
|
|
|
966
963
|
globalThis.listen = true;
|
|
967
964
|
|
|
968
|
-
const browser
|
|
969
|
-
headless:
|
|
965
|
+
const browser = await puppeteer.launch({
|
|
966
|
+
headless: "new", args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
970
967
|
warning: false,
|
|
971
968
|
})
|
|
972
969
|
|
|
973
970
|
try {
|
|
974
|
-
|
|
971
|
+
|
|
975
972
|
route.url = route.url.replaceAll(/\/:[a-zA-Z0-9_-]+/gs, '')
|
|
976
973
|
let page = await browser.newPage();
|
|
977
|
-
await page.goto(`http://localhost:${port}
|
|
974
|
+
await page.goto(`http://localhost:${port}/`, { waitUntil: 'networkidle2' });
|
|
978
975
|
await page.waitForSelector('#root');
|
|
979
976
|
await page.evaluate(() => {
|
|
980
977
|
document.getElementById('meta').remove()
|
|
981
978
|
document.querySelector('#isServer').innerHTML = 'window.isServer = false'
|
|
982
|
-
if(document.head.getAttribute('prerender') === 'false'){
|
|
979
|
+
if (document.head.getAttribute('prerender') === 'false') {
|
|
983
980
|
document.querySelector('#root').innerHTML = ''
|
|
984
981
|
}
|
|
985
982
|
})
|
|
986
983
|
const html = await page.content();
|
|
987
|
-
|
|
984
|
+
|
|
988
985
|
await page.close();
|
|
989
986
|
await writer(process.cwd() + '/dist/' + (route.url === '/' ? 'index.html' : `${route.url}/` + 'index.html'), html)
|
|
990
987
|
await browser.close();
|
|
@@ -992,11 +989,11 @@ async function Build() {
|
|
|
992
989
|
console.log(error)
|
|
993
990
|
await browser.close();
|
|
994
991
|
}
|
|
995
|
-
finally{
|
|
992
|
+
finally {
|
|
996
993
|
await browser.close();
|
|
997
994
|
server.close()
|
|
998
995
|
}
|
|
999
|
-
|
|
996
|
+
|
|
1000
997
|
|
|
1001
998
|
})
|
|
1002
999
|
|
|
@@ -1004,6 +1001,7 @@ async function Build() {
|
|
|
1004
1001
|
globalThis.isBuilding = false
|
|
1005
1002
|
clearTimeout(timeout)
|
|
1006
1003
|
}, 1000)
|
|
1004
|
+
console.log(`Generated ${routes.length} html files for ${routes.length} routes`)
|
|
1007
1005
|
}
|
|
1008
1006
|
|
|
1009
1007
|
globalThis.routes = []
|
|
@@ -1041,75 +1039,72 @@ async function Build() {
|
|
|
1041
1039
|
|
|
1042
1040
|
await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), data).then(async () => {
|
|
1043
1041
|
|
|
1044
|
-
let { minify } = await import('terser')
|
|
1045
|
-
|
|
1046
|
-
try {
|
|
1047
|
-
let minified = await minify(data, {
|
|
1048
|
-
toplevel: true,
|
|
1049
|
-
ecma: 2016,
|
|
1050
|
-
enclose: false,
|
|
1051
|
-
module: true,
|
|
1052
|
-
compress: true,
|
|
1053
|
-
keep_fnames: true,
|
|
1054
1042
|
|
|
1055
|
-
})
|
|
1056
1043
|
|
|
1057
|
-
|
|
1044
|
+
await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), data)
|
|
1058
1045
|
|
|
1059
|
-
await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), minified.code)
|
|
1060
|
-
} catch (error) {
|
|
1061
|
-
console.log(error)
|
|
1062
|
-
}
|
|
1063
1046
|
})
|
|
1064
1047
|
|
|
1048
|
+
// configure routing for each page
|
|
1065
1049
|
|
|
1066
1050
|
obj.compiledPath = process.cwd() + "/dist/pages/" + fileName.replace('.jsx', '.js')
|
|
1067
|
-
let providerRedirects = {cloudflare: '_redirects', vercel: 'vercel.json', netlify:'_redirects'}
|
|
1068
|
-
switch(true){
|
|
1051
|
+
let providerRedirects = { cloudflare: '_redirects', vercel: 'vercel.json', netlify: '_redirects' }
|
|
1052
|
+
switch (true) {
|
|
1069
1053
|
case config && config.host && !config.host['_redirect']:
|
|
1070
1054
|
let host = config.host.provider
|
|
1071
|
-
|
|
1072
|
-
let provider = providerRedirects[host]
|
|
1073
|
-
if(provider){
|
|
1074
|
-
|
|
1075
|
-
let redirectFile =
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1055
|
+
|
|
1056
|
+
let provider = providerRedirects[host]
|
|
1057
|
+
if (provider) {
|
|
1058
|
+
|
|
1059
|
+
let redirectFile = null
|
|
1060
|
+
switch (true) {
|
|
1061
|
+
case provider === '_redirects':
|
|
1062
|
+
redirectFile = fs.existsSync(process.cwd() + '/dist/' + provider) ? fs.readFileSync(process.cwd() + '/dist/' + provider, 'utf8') : ''
|
|
1063
|
+
break;
|
|
1064
|
+
case provider === 'vercel.json':
|
|
1065
|
+
redirectFile = fs.existsSync(process.cwd() + '/' + provider) ? fs.readFileSync(process.cwd() + '/' + provider, 'utf8') : ''
|
|
1066
|
+
break;
|
|
1067
|
+
default:
|
|
1068
|
+
break;
|
|
1069
|
+
}
|
|
1070
|
+
let type = provider === '_redirects' ? 'text/plain' : 'application/json'
|
|
1071
|
+
|
|
1072
|
+
let root = obj.url.includes(':') ? obj.url.split('/:')[0] : obj.url
|
|
1073
|
+
switch (true) {
|
|
1080
1074
|
case root === '/':
|
|
1081
1075
|
break;
|
|
1082
1076
|
case type === 'text/plain' && !redirectFile.includes(obj.url) && obj.url.includes(':'):
|
|
1083
1077
|
let page = obj.pathname.split('/pages/')[1].replace('.jsx', '.js')
|
|
1084
1078
|
redirectFile += `\n/${page} /${page} 200\n${obj.url} ${root} 200\n`
|
|
1085
1079
|
!redirectFile.includes('/404') ? redirectFile += `\n/404 /404 404` : null
|
|
1086
|
-
fs.writeFileSync(process.cwd() + '/dist/' + provider, redirectFile)
|
|
1080
|
+
fs.writeFileSync(process.cwd() + '/dist/' + provider, redirectFile)
|
|
1087
1081
|
console.log(`Added ${obj.url} ${obj.url} 200 to ${provider}`)
|
|
1088
1082
|
break;
|
|
1089
|
-
case
|
|
1090
|
-
let json = JSON.parse(redirectFile)
|
|
1083
|
+
case type === 'application/json' && !redirectFile?.includes(`${obj.url}`):
|
|
1084
|
+
let json = redirectFile ? JSON.parse(redirectFile) : {}
|
|
1091
1085
|
let isVercel = provider === 'vercel.json' ? true : false
|
|
1092
|
-
if(isVercel){
|
|
1086
|
+
if (isVercel) {
|
|
1093
1087
|
json['rewrites'] = json['rewrites'] || []
|
|
1094
|
-
json['rewrites'].push({ "source":
|
|
1088
|
+
json['rewrites'].push({ "source": obj.url, "destination": `${root}/index.html` })
|
|
1089
|
+
fs.writeFileSync(process.cwd() + '/' + provider, JSON.stringify(json, null, 2))
|
|
1090
|
+
console.log(`Added ${obj.url} ${root}/index.html to ${provider}`)
|
|
1095
1091
|
}
|
|
1096
|
-
|
|
1097
|
-
console.log(`Added ${root}/* ${root} 200 to ${provider}`)
|
|
1092
|
+
|
|
1098
1093
|
}
|
|
1099
1094
|
}
|
|
1100
1095
|
break;
|
|
1101
1096
|
case config && config.host && config.host['_redirect']:
|
|
1102
|
-
let file =
|
|
1097
|
+
let file = config.host['_redirect']
|
|
1103
1098
|
file = file.split('./').join('')
|
|
1104
|
-
let redirectFile =
|
|
1099
|
+
let redirectFile = fs.existsSync(process.cwd() + '/' + file) ? fs.readFileSync(process.cwd() + '/' + file, 'utf8') : ''
|
|
1105
1100
|
fs.writeFileSync(process.cwd() + '/dist/' + file, redirectFile)
|
|
1106
1101
|
console.log(`Using ${file} for redirects`)
|
|
1107
1102
|
default:
|
|
1108
1103
|
break;
|
|
1109
1104
|
|
|
1110
1105
|
}
|
|
1111
|
-
|
|
1112
|
-
|
|
1106
|
+
|
|
1107
|
+
|
|
1113
1108
|
globalThis.routes.push({ fileName: fileName, url: obj.url, html: '/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html') })
|
|
1114
1109
|
|
|
1115
1110
|
|
|
@@ -1151,18 +1146,7 @@ async function Build() {
|
|
|
1151
1146
|
data = Compiler(data, process.cwd() + "/src/" + name);
|
|
1152
1147
|
|
|
1153
1148
|
await writer(process.cwd() + "/dist/src/" + name.split('.jsx').join('.js'), data).then(async () => {
|
|
1154
|
-
|
|
1155
|
-
try {
|
|
1156
|
-
let minified = await minify(data, {
|
|
1157
|
-
ecma: " 2016",
|
|
1158
|
-
module: true,
|
|
1159
|
-
compress: true,
|
|
1160
|
-
keep_fnames: true,
|
|
1161
|
-
})
|
|
1162
|
-
await writer(process.cwd() + "/dist/src/" + name.replace('.jsx', '.js'), minified.code)
|
|
1163
|
-
} catch (error) {
|
|
1164
|
-
console.log(error)
|
|
1165
|
-
}
|
|
1149
|
+
await writer(process.cwd() + "/dist/src/" + name.replace('.jsx', '.js'), data)
|
|
1166
1150
|
|
|
1167
1151
|
})
|
|
1168
1152
|
return
|
|
@@ -1221,11 +1205,13 @@ const s = () => {
|
|
|
1221
1205
|
|
|
1222
1206
|
const server = http.createServer((req, res) => {
|
|
1223
1207
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1208
|
+
const validExtensions = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg'];
|
|
1209
|
+
|
|
1210
|
+
if (!validExtensions.some(ext => req.url.endsWith(ext))) {
|
|
1211
|
+
req.url = req.url !== '/' ? req.url.split('/')[1] : req.url;
|
|
1212
|
+
req.url = path.join(process.cwd(), 'dist', req.url, 'index.html');
|
|
1227
1213
|
} else {
|
|
1228
|
-
req.url = process.cwd()
|
|
1214
|
+
req.url = path.join(process.cwd(), 'dist', req.url);
|
|
1229
1215
|
}
|
|
1230
1216
|
|
|
1231
1217
|
const filePath = req.url
|
|
@@ -1235,14 +1221,14 @@ const s = () => {
|
|
|
1235
1221
|
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
1236
1222
|
res.end(fs.existsSync(process.cwd() + '/dist/404') ? fs.readFileSync(process.cwd() + '/dist/404/index.html') : '404');
|
|
1237
1223
|
} else {
|
|
1238
|
-
const contentType = getContentType(filePath);
|
|
1224
|
+
const contentType = getContentType(filePath);
|
|
1239
1225
|
switch (true) {
|
|
1240
1226
|
case contentType === 'text/html' && globalThis.devMode:
|
|
1241
1227
|
data = data.toString() + `<script type="module">
|
|
1242
|
-
let ws = new WebSocket('ws://localhost
|
|
1228
|
+
let ws = new WebSocket('ws://localhost:${process.env.PORT || 3000}')
|
|
1243
1229
|
ws.onmessage = (e) => {
|
|
1244
1230
|
if(e.data === 'reload'){
|
|
1245
|
-
window.
|
|
1231
|
+
window.location.reload()
|
|
1246
1232
|
}
|
|
1247
1233
|
}
|
|
1248
1234
|
</script>
|
|
@@ -1257,18 +1243,44 @@ const s = () => {
|
|
|
1257
1243
|
|
|
1258
1244
|
const ws = new WebSocketServer({ server });
|
|
1259
1245
|
ws.on('connection', (socket) => {
|
|
1260
|
-
console.log('Client connected');
|
|
1261
|
-
socket.on('close', () => console.log('Client disconnected'));
|
|
1246
|
+
console.log('WebSocket Hydration Client connected');
|
|
1247
|
+
socket.on('close', () => console.log('WebSocket Hydration Client disconnected'));
|
|
1262
1248
|
});
|
|
1263
1249
|
|
|
1264
1250
|
|
|
1265
1251
|
function getContentType(filePath) {
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1252
|
+
let ext = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg'].includes(path.extname(filePath)) ? path.extname(filePath) : '.html'
|
|
1253
|
+
switch (ext) {
|
|
1254
|
+
case '.js':
|
|
1255
|
+
return 'text/javascript';
|
|
1256
|
+
case '.css':
|
|
1257
|
+
return 'text/css';
|
|
1258
|
+
case '.mjs':
|
|
1259
|
+
return 'text/javascript';
|
|
1260
|
+
case '.cjs':
|
|
1261
|
+
return 'text/javascript';
|
|
1262
|
+
case '.html':
|
|
1263
|
+
return 'text/html';
|
|
1264
|
+
case '.json':
|
|
1265
|
+
return 'application/json';
|
|
1266
|
+
case '.png':
|
|
1267
|
+
return 'image/png';
|
|
1268
|
+
case '.jpg':
|
|
1269
|
+
return 'image/jpg';
|
|
1270
|
+
case '.jpeg':
|
|
1271
|
+
return 'image/jpeg';
|
|
1272
|
+
case '.gif':
|
|
1273
|
+
return 'image/gif';
|
|
1274
|
+
case '.svg':
|
|
1275
|
+
return 'image/svg+xml';
|
|
1276
|
+
case '.mp4':
|
|
1277
|
+
return 'video/mp4';
|
|
1278
|
+
case '.webm':
|
|
1279
|
+
return 'video/webm';
|
|
1280
|
+
case '.ogg':
|
|
1281
|
+
return 'video/ogg';
|
|
1282
|
+
default:
|
|
1283
|
+
return 'application/octet-stream';
|
|
1272
1284
|
}
|
|
1273
1285
|
}
|
|
1274
1286
|
|
|
@@ -1279,21 +1291,20 @@ const s = () => {
|
|
|
1279
1291
|
let i =
|
|
1280
1292
|
setInterval(() => {
|
|
1281
1293
|
if (globalThis.isBuilding && globalThis.devMode) {
|
|
1282
|
-
|
|
1283
|
-
console.log(globalThis.isBuilding)
|
|
1284
|
-
console.log('Reloading page...')
|
|
1294
|
+
|
|
1285
1295
|
ws.clients.forEach((client) => {
|
|
1286
1296
|
client.send('reload')
|
|
1287
|
-
console.log('Reloaded page')
|
|
1288
1297
|
})
|
|
1289
|
-
}
|
|
1298
|
+
} else {
|
|
1299
|
+
clearInterval(i)
|
|
1300
|
+
}
|
|
1290
1301
|
}, 120)
|
|
1291
1302
|
|
|
1292
1303
|
}
|
|
1293
1304
|
|
|
1294
1305
|
|
|
1295
1306
|
switch (true) {
|
|
1296
|
-
case process.argv.includes('--watch'):
|
|
1307
|
+
case process.argv.includes('--watch') && !process.argv.includes('--build') && !process.argv.includes('--serve'):
|
|
1297
1308
|
|
|
1298
1309
|
globalThis.devMode = true
|
|
1299
1310
|
console.log(`
|
|
@@ -1323,7 +1334,7 @@ Vader.js v1.3.3
|
|
|
1323
1334
|
globalThis.listen = true;
|
|
1324
1335
|
|
|
1325
1336
|
break;
|
|
1326
|
-
case process.argv.includes('--build'):
|
|
1337
|
+
case process.argv.includes('--build') && !process.argv.includes('--watch') && !process.argv.includes('--serve'):
|
|
1327
1338
|
globalThis.devMode = false
|
|
1328
1339
|
console.log(`
|
|
1329
1340
|
Vader.js v1.3.3
|
|
@@ -1332,7 +1343,7 @@ Building to ./dist
|
|
|
1332
1343
|
Build()
|
|
1333
1344
|
|
|
1334
1345
|
break;
|
|
1335
|
-
case process.argv.includes('--serve'):
|
|
1346
|
+
case process.argv.includes('--serve') && !process.argv.includes('--watch') && !process.argv.includes('--build'):
|
|
1336
1347
|
let port = process.argv[process.argv.indexOf('--serve') + 1] || 3000
|
|
1337
1348
|
process.env.PORT = port
|
|
1338
1349
|
globalThis.devMode = false
|
|
@@ -1350,9 +1361,9 @@ Vader.js is a reactive framework for building interactive applications for the w
|
|
|
1350
1361
|
Usage: vader <command>
|
|
1351
1362
|
|
|
1352
1363
|
Commands:
|
|
1353
|
-
--watch Watch the pages folder for changes
|
|
1364
|
+
--watch Watch the pages folder for changes with hot reloading
|
|
1354
1365
|
|
|
1355
|
-
--build Build the project
|
|
1366
|
+
--build Build the project to ./dist
|
|
1356
1367
|
|
|
1357
1368
|
--serve Serve the project on a port (default 3000)
|
|
1358
1369
|
|