vaderjs 1.3.3-alpha-104 → 1.3.3-alpha-106
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 +0 -6
- package/package.json +1 -1
- package/runtime/router.js +1 -1
- package/runtime/vader.js +1 -1
- package/vader.js +149 -45
package/README.md
CHANGED
|
@@ -23,12 +23,6 @@
|
|
|
23
23
|
npm i vaderjs@latest
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
3. Install five server - recommended to watch the index.html file as you edit your code
|
|
27
|
-
|
|
28
|
-
[Vscode 5 Server](https://marketplace.visualstudio.com/items?itemName=yandeu.five-server)
|
|
29
|
-
|
|
30
|
-
> When running the server ensure the root is the dist folder and not the main workspace folder
|
|
31
|
-
|
|
32
26
|
4. Create Proper Folders
|
|
33
27
|
|
|
34
28
|
Create a pages folder - which allows you to have nextjs page like routing via buns file based router
|
package/package.json
CHANGED
package/runtime/router.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Component}from"./vader.js";let middlewares=[];class VaderRouter{constructor(e,t){this.routes=[],this.middlewares=[],this.errorMiddlewares=[],this.listeners=[],this.basePath=e}get(e,t){this.routes.push({path:e,handler:t,method:"get"})}use(e){this.middlewares.push(e)}listen(e,t){e||(e=Math.random().toString(36).substring(7)),this.listeners.push(e),1===this.listeners.length?this.handleRoute(window.location.hash.length>0?window.location.hash:window.location.pathname):this.listeners.pop(),t&&t(),window.
|
|
1
|
+
import{Component}from"./vader.js";let middlewares=[];class VaderRouter{constructor(e,t){this.routes=[],this.middlewares=[],this.errorMiddlewares=[],this.listeners=[],this.basePath=e,console.log(this.basePath)}get(e,t){this.routes.push({path:e,handler:t,method:"get"})}use(e){this.middlewares.push(e)}listen(e,t){e||(e=Math.random().toString(36).substring(7)),this.listeners.push(e),1===this.listeners.length?this.handleRoute(window.location.hash.length>0?window.location.hash:window.location.pathname):this.listeners.pop(),t&&t(),window.onpopstate=async e=>{let t=`/${window.location.pathname.split("/")[1]}`;routes.find((e=>e.url.includes(t)))||(t="/404");let n=(new DOMParser).parseFromString(await fetch(t,{cache:"reload"}).then((e=>e.text())),"text/html").documentElement;document.querySelector("#root").innerHTML=n.querySelector("#root").innerHTML,document.title=n.querySelector("title").innerHTML,document.querySelector('script[id="router"]').remove();let s=document.createElement("script");s.id="router",s.innerHTML=n.querySelector('script[id="router"]').innerHTML,s.setAttribute("type","module"),document.body.appendChild(s)}}extractParams(e,t){const n=e.split("/"),s=t.split("/"),o={};return n.forEach(((e,t)=>{if(e.startsWith(":")){const n=e.slice(1);o[n]=s[t]}else if(e.startsWith("*")){s.slice(t).forEach(((e,t)=>{o[t]=e}))}})),o}extractQueryParams(e){const t=e.split("?")[1];if(!t)return{};const n={};return t.split("&").forEach((e=>{const[t,s]=e.split("=");n[t]=s})),n}handleRoute(e){let t=200,n=e=e.includes("#")?e.slice(1):e,s=this.routes.find((t=>{if(t.path===e)return!0;if(""===e&&"/"===t.path)return!0;if(e.includes("?")&&(e=e.split("?")[0]),t.path.includes("*")||t.path.includes(":")){const n=t.path.split("/"),s=e.split("/");if(n.length!==s.length&&!t.path.endsWith("*"))return!1;for(let e=0;e<n.length;e++){const t=n[e],o=s[e];if(!t.startsWith(":")&&!t.startsWith("*")&&t!==o)return!1}return!0}const s=this.extractParams(t.path,n);return Object.keys(s).length>0}));s||(console.log(window.routes),s=window.routes.find((e=>{if(e.url.includes("/404"))window.history.replaceState({},"","/404");else if(!this.error&&e.url.includes("/404"))return!0})),t=s?200:404);const o=this.extractQueryParams(n),r=s&&s.path?this.extractParams(s.path,n):{};Object.keys(r).forEach((e=>{r[e]=r[e].split("?")?r[e].split("?")[0]:r[e]}));const i={headers:{},params:r,query:o,path:e,fileUrl:window.location.href.split(window.location.origin)[1],url:window.location.href,method:s?s.method:"get",pause:!1,timestamp:Date.now()};window.$CURRENT_URL=i.path,window.$FULL_URL=window.location.href.replace("#","");const a={status:t,log:e=>{void 0===e?console.log(`${i.path} ${i.method} ${a.status} ${i.timestamp}`):console.table({"Request Path":i.path,"Request Method":s.method,"Response Status":a.status,"Request Timestamp":i.timestamp})},refresh:()=>{this.handleRoute(window.location.hash)},redirect:e=>{!e.startsWith("/")&&(e=`/${e}`),window.location.hash=`#${e}`},render:async(e,t,n,s)=>{function isClass(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}try{let s=new Component;if(isClass(e.default)){let t=new e.default;s.state=t.state,s=t}else{if(e.default.toString().includes("this.key"))throw new Error('Using this.key is not supported in functional components use the attribute key="a value" instead');s.key=e.default.toString().split('key="')[1]?e.default.toString().split('key="')[1].split('"')[0]:null;let i={key:s.key,render:()=>e.default.apply(s,[t,n]),request:t,response:n,params:r,queryParams:o,reset:s.reset.bind(s),onMount:s.onMount.bind(s),useState:null,router:{use:s.router.use.bind(s)},bindMount:s.bindMount.bind(s),memoize:s.memoize.bind(s),createComponent:s.createComponent.bind(s),isChild:!1,useState:s.useState.bind(s),parseStyle:s.parseStyle.bind(s),bind:s.bind.bind(s),useRef:s.useRef.bind(s),useReducer:s.useReducer.bind(s),onMount:s.onMount.bind(s),onUnmount:s.onUnmount.bind(s),hydrate:s.hydrate.bind(s)};s.render=i.render,s=i,console.log(t)}if(!document.querySelector("#root"))throw new Error("Root element not found, please add an element with id root");s.reset(),s.components={},s.request=t,s.response=n,s.router.use&&!s.isChild?await new Promise((async o=>{if(isClass(e.default))if(isClass(e.default))switch(await s.router.use(t,n),t.pause){case!0:console.log("pausing",t.pause);let e=setInterval((()=>{t.pause?console.log("still pausing",t.pause):(clearInterval(e),o())}),1e3);break;case!1:o()}else o();else switch(await e.default.apply(s,[t,n]),await s.router.use(t,n),t.pause){case!0:let e=setInterval((()=>{t.pause?console.log("still pausing request",t.url):(clearInterval(e),o())}),1e3);break;case!1:o()}})):s.router.use&&s.isChild&&console.warn("Router.use() is not supported in child components");const i=await s.render();document.querySelector("#root").innerHTML!==i&&(console.log("rendering"),document.querySelector("#root").innerHTML=i),s.bindMount(),s.onMount()}catch(e){console.error(e)}},setQuery:e=>{let t="";Object.keys(e).forEach(((n,s)=>{t+=`${0===s?"?":"&"}${n}=${e[n]}`}));let n=window.location.hash.split("?")[0];t=t.replace("/","-").replaceAll("/","-"),window.location.hash=`${n}${t}`},send:e=>{document.querySelector("#root").innerHTML=e},json:e=>{const t=document.querySelector("#root");t.innerHTML="";const n=document.createElement("pre");n.textContent=JSON.stringify(e,null,2),t.appendChild(n)}};middlewares.forEach((e=>{e(i,a)})),s&&s.handler(i,a)}}window.VaderRouter=VaderRouter;export default VaderRouter;
|
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 n=setInterval((()=>{document.querySelector(`[key="${e}"]`)&&!hasRan.includes(e)&&(clearInterval(n),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,n){function
|
|
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 n=setInterval((()=>{document.querySelector(`[key="${e}"]`)&&!hasRan.includes(e)&&(clearInterval(n),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,n){function isClass(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}let s=isClass(e)?new e(t):null;if(!e)throw new Error("Component must be defined");let r=new Component(t);if(isClass(e))s.props=t,s.children=n,s.props.children=n.join(""),s.parentNode=this,s.request=this.request,s.response=this.response,s.key=t.key||null,r=s;else{e.toString();r.key=e.toString().split('key="')[1]?e.toString().split('key="')[1].split('"')[0]:null;let n={key:r.key,render:()=>e.apply(r,[t]),request:this.request,isChild:!0,response:this.response,params:this.request.params,queryParams:this.request.query,reset:r.reset.bind(r),onMount:r.onMount.bind(r),useState:null,router:{use:r.router.use.bind(r)},bindMount:r.bindMount.bind(r),memoize:r.memoize.bind(r),createComponent:r.createComponent.bind(r),isChild:!1,useState:r.useState.bind(r),parseStyle:r.parseStyle.bind(r),bind:r.bind.bind(r),useRef:r.useRef.bind(r),request:this.request,response:this.response,useReducer:r.useReducer.bind(r),hydrate:r.hydrate.bind(r),onUnmount:r.onUnmount.bind(r),parentNoe:this};r.render=n.render,r=n}return this.components[t.key]||(this.components[t.key]=r),!this.children.includes(r)&&this.children.push(r),this.components[t.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 n=t.render();return n&&n.split(">,").length>1&&(n=n.replaceAll(">,",">")),`<span key="${e.key}" >${n}</span>`}parseStyle(e){let t="";return Object.keys(e).forEach((n=>{let s=e[n];n=n.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,"$1-$2").toLowerCase(),t+=`${n}:${s};`})),t}bindMount(){mounts.push(this)}domDifference(e,t){let n=[];for(let s=0;s<e.length;s++){let r=e[s],o=t[s];r&&o&&!r.isEqualNode(o)&&n.push({type:"replace",old:r,new:o.cloneNode(!0)})}return n}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 n=this.domDifference(e,t);this.updateChangedElements(n)}handleObject(obj){try{obj=JSON.parse(obj)}catch(e){}return eval(obj)}bind(e,t,n,s,...r){n=n+this.key||2022;let o={},i=(s=s.replace(/,,/g,",")).replaceAll(",,",",");for(var u in r){let e=r[u];o[i.split(",")[u]]=e}s=s.replace(",,",",");let a=null;e=e.split("\n").join(";");try{a=new Function(`event, ${s}`,` \n return (async (event, ${s}) => { \n ${e.toString()}\n })(event, ${Object.keys(o).join(",")}) \n `)}catch(e){let{message:t}=e;console.error(`Error in function ${n} ${t}`)}return a=a.bind(this),this.functions.find((e=>e.ref===n))||document.addEventListener(`$dispatch_#id=${n}`,(e=>{let{name:t,event:s}=e.detail;if(t===n){let e=this.functions.find((e=>e.ref===n)).params;Object.keys(e).forEach((t=>{e[t]instanceof CustomEvent&&delete e[t],void 0===e[t]?delete e[t]:e[t]})),a(s,...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===n))&&this.functions.push({ref:n,params:o}),t?e:`((event)=>{event.target.ev = event; callFunction('${n}', event.target.ev)})(event)`}useState(e,t){this.state[e]||(this.state[e]=t);let updatedValue=()=>this.state[e],n=updatedValue();return[n,(t,s)=>{this.state[e]=t,this.hydrate(s),n=updatedValue()}]}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,n=null){this.state[e]||(this.state[e]=t);const getValue=()=>this.state[e];let s=getValue();return[getValue(),(t,r)=>{const o=n(s,t)??t;this.state[e]=o,this.hydrate(r),s=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)=>{states[e]||(states[e]=t);return[states[e],(t,n)=>{states[e]=t,this.hydrate(n)}]};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")}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 default{Component:Component,useRef:useRef,useReducer:useReducer,useState:useState,strictMount:strictMount};
|
package/vader.js
CHANGED
|
@@ -3,6 +3,9 @@ import fs from "fs";
|
|
|
3
3
|
import { glob, globSync, globStream, globStreamSync, Glob, } from 'glob'
|
|
4
4
|
import puppeteer from 'puppeteer';
|
|
5
5
|
import http from 'http'
|
|
6
|
+
import { WebSocketServer } from 'ws'
|
|
7
|
+
import { watch } from "fs";
|
|
8
|
+
let start = Date.now()
|
|
6
9
|
let bundleSize = 0;
|
|
7
10
|
let errorCodes = {
|
|
8
11
|
"SyntaxError: Unexpected token '<'": "You forgot to enclose tags in a fragment <></>",
|
|
@@ -17,7 +20,8 @@ if(!fs.existsSync(process.cwd() + '/dist')){
|
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
|
|
24
|
+
if (typeof process.env.isCloudflare !== "undefined" || !fs.existsSync(process.cwd() + '/dist/index.html')) {
|
|
21
25
|
let htmlFile = fs.readFileSync(process.cwd() + "/node_modules/vaderjs/runtime/index.html", 'utf8')
|
|
22
26
|
fs.writeFileSync(process.cwd() + "/dist/index.html", htmlFile)
|
|
23
27
|
}
|
|
@@ -88,8 +92,7 @@ function Compiler(func, file) {
|
|
|
88
92
|
/\s*([a-zA-Z0-9_-]+)(\s*=\s*("([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}|(?:\([^)]*\)|\{[^}]*\}|()=>\s*(?:\{[^}]*\})?)|\[[^\]]*\]))?/gs;
|
|
89
93
|
|
|
90
94
|
// only return elements with attribute {()=>{}} or if it also has parameters ex: onclick={(event)=>{console.log(event)}} also get muti line functions
|
|
91
|
-
const functionAttributeRegex =
|
|
92
|
-
/\s*([a-zA-Z0-9_-]+)(\s*=\s*{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*})/gs;
|
|
95
|
+
const functionAttributeRegex = /\s*([a-zA-Z0-9_-]+)(\s*=\s*{(.*?)}|\s*=\s*function\s*(.*?))(?=\s*[a-zA-Z0-9_-]+\s*=|\s*>)/gs;
|
|
93
96
|
|
|
94
97
|
let attributesList = [];
|
|
95
98
|
|
|
@@ -97,7 +100,7 @@ function Compiler(func, file) {
|
|
|
97
100
|
let functionAttributes = [];
|
|
98
101
|
let functionMatch;
|
|
99
102
|
while ((functionMatch = functionAttributeRegex.exec(code)) !== null) {
|
|
100
|
-
let [, attributeName, attributeValue] = functionMatch;
|
|
103
|
+
let [, attributeName, attributeValue] = functionMatch;
|
|
101
104
|
let attribute = {};
|
|
102
105
|
|
|
103
106
|
if (attributeValue && attributeValue.includes("=>") || attributeValue && attributeValue.includes("function")) {
|
|
@@ -134,14 +137,19 @@ function Compiler(func, file) {
|
|
|
134
137
|
isJSXComponent = elementTag.match(/^[A-Z]/) ? true : false;
|
|
135
138
|
}
|
|
136
139
|
});
|
|
140
|
+
// add ; after newlines
|
|
141
|
+
|
|
142
|
+
|
|
137
143
|
let newvalue = attributeValue.includes('=>') ? attributeValue.split("=>").slice(1).join("=>").trim() : attributeValue.split("function").slice(1).join("function").trim()
|
|
138
144
|
|
|
145
|
+
|
|
139
146
|
|
|
140
147
|
newvalue = newvalue.trim();
|
|
141
148
|
|
|
142
149
|
//remove starting {
|
|
143
|
-
newvalue = newvalue.replace("{", "")
|
|
144
|
-
|
|
150
|
+
newvalue = newvalue.replace("{", "")
|
|
151
|
+
|
|
152
|
+
|
|
145
153
|
|
|
146
154
|
let params = attributeValue
|
|
147
155
|
.split("=>")[0]
|
|
@@ -156,39 +164,38 @@ function Compiler(func, file) {
|
|
|
156
164
|
// split first {}
|
|
157
165
|
newvalue = newvalue.trim();
|
|
158
166
|
|
|
159
|
-
|
|
160
|
-
newvalue = newvalue.split("{")[1];
|
|
161
|
-
}
|
|
167
|
+
|
|
162
168
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
case newvalue.endsWith("}"):
|
|
168
|
-
newvalue = newvalue.replace("}", "");
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
// replace trailing }
|
|
169
|
+
newvalue = newvalue.replace(/}\s*$/, '');
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
172
173
|
newvalue = newvalue.trim();
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
|
|
175
|
+
// remmove trailing }
|
|
176
|
+
|
|
177
|
+
newvalue = newvalue.trim();
|
|
178
|
+
newvalue = newvalue.replace(/}\s*$/, '');
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
functionparams.length > 0 ? params = params + ',' + functionparams.map((e) => e.name).join(',') : null
|
|
183
|
+
|
|
178
184
|
newvalue = newvalue.replaceAll(',,', ',')
|
|
179
185
|
let paramnames = params ? params.split(',').map((e) => e.trim()) : null
|
|
180
186
|
paramnames = paramnames ? paramnames.filter((e) => e.length > 0) : null
|
|
181
187
|
// remove comments
|
|
182
188
|
paramnames = paramnames ? paramnames.map((e) => e.match(/\/\*.*\*\//gs) ? e.replace(e.match(/\/\*.*\*\//gs)[0], "") : e) : null
|
|
189
|
+
newvalue = newvalue.replaceAll(/\s+/g, " ")
|
|
183
190
|
|
|
184
|
-
let bind = isJSXComponent ? `${attributeName}=function(${params}){${newvalue}}.bind(this)` : `${attributeName}
|
|
191
|
+
let bind = isJSXComponent ? `${attributeName}=function(${params}){${newvalue}}.bind(this)` : `${attributeName}="\$\{this.bind("${newvalue.replace(/\s+g/, " ")}", ${isJSXComponent}, "${ref}", "${paramnames ? paramnames.map((e, index) => {
|
|
185
192
|
if (e.length < 1) return ''
|
|
186
193
|
if (e.length > 0) {
|
|
187
194
|
index == 0 ? e : ',' + e
|
|
188
195
|
}
|
|
189
196
|
return e
|
|
190
197
|
}) : ''}" ${params ? params.split(',').map((e) => e.trim()).filter(Boolean).map((e) => `,${e}`).join('') : ''})}"`
|
|
191
|
-
|
|
198
|
+
|
|
192
199
|
string = string.replace(old, bind);
|
|
193
200
|
}
|
|
194
201
|
}
|
|
@@ -710,6 +717,7 @@ async function Build() {
|
|
|
710
717
|
let appjs = '';
|
|
711
718
|
let hasWritten = []
|
|
712
719
|
function ssg(routes = []) {
|
|
720
|
+
globalThis.isBuilding = true
|
|
713
721
|
console.log(`Generating html files for ${routes.length} routes`)
|
|
714
722
|
routes.forEach(async (route) => {
|
|
715
723
|
if(route.url.includes(':')){
|
|
@@ -724,7 +732,7 @@ async function Build() {
|
|
|
724
732
|
if(url&&route.url === url){
|
|
725
733
|
return e
|
|
726
734
|
}else{
|
|
727
|
-
return
|
|
735
|
+
return null
|
|
728
736
|
|
|
729
737
|
}
|
|
730
738
|
}
|
|
@@ -734,6 +742,9 @@ async function Build() {
|
|
|
734
742
|
<!DOCTYPE html>
|
|
735
743
|
<html lang="en">
|
|
736
744
|
<head>
|
|
745
|
+
<script>
|
|
746
|
+
window.routes = JSON.parse('${JSON.stringify(routes)}')
|
|
747
|
+
</script>
|
|
737
748
|
<meta charset="UTF-8">
|
|
738
749
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
739
750
|
<script type="module" id="meta">
|
|
@@ -791,7 +802,7 @@ async function Build() {
|
|
|
791
802
|
<div id="root"></div>
|
|
792
803
|
</body>
|
|
793
804
|
|
|
794
|
-
<script type="module">
|
|
805
|
+
<script type="module" id="router">
|
|
795
806
|
import VaderRouter from '/router.js'
|
|
796
807
|
const router = new VaderRouter('${route.url}', 3000)
|
|
797
808
|
router.get('${route.url}', async (req, res) => {
|
|
@@ -799,9 +810,7 @@ async function Build() {
|
|
|
799
810
|
res.render(module, req, res, module.$metadata)
|
|
800
811
|
})
|
|
801
812
|
${equalparamroute.length > 0 ? equalparamroute.map((e) => {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
e.url = e.url.replace(folderName, '')
|
|
813
|
+
|
|
805
814
|
|
|
806
815
|
return `router.get('${e.url}', async (req, res) => {
|
|
807
816
|
let module = await import('/${e.fileName.replace('.jsx', '.js')}')
|
|
@@ -809,13 +818,14 @@ async function Build() {
|
|
|
809
818
|
})\n`
|
|
810
819
|
}): ''}
|
|
811
820
|
router.listen(3000)
|
|
821
|
+
|
|
812
822
|
</script>
|
|
813
823
|
</html>
|
|
814
824
|
`;
|
|
815
825
|
|
|
816
826
|
let port = Math.floor(Math.random() * 10000) + 1;
|
|
817
827
|
|
|
818
|
-
const server = http.createServer((req, res) => {
|
|
828
|
+
const server = http.createServer((req, res) => {
|
|
819
829
|
if (req.url === '/') {
|
|
820
830
|
// Respond with the generated HTML
|
|
821
831
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
@@ -830,7 +840,7 @@ async function Build() {
|
|
|
830
840
|
res.end('File not found');
|
|
831
841
|
} else {
|
|
832
842
|
res.writeHead(200, { 'Content-Type': filePath.includes('js') ? 'text/javascript' : 'text/html' });
|
|
833
|
-
res.end(data);
|
|
843
|
+
res.end(data);
|
|
834
844
|
}
|
|
835
845
|
});
|
|
836
846
|
}
|
|
@@ -845,7 +855,7 @@ async function Build() {
|
|
|
845
855
|
}).then(async (browser) => {
|
|
846
856
|
|
|
847
857
|
// remove /: from route
|
|
848
|
-
route.url = route.url.replaceAll(/\/:[a-zA-Z0-9_-]+/gs, '')
|
|
858
|
+
route.url = route.url.replaceAll(/\/:[a-zA-Z0-9_-]+/gs, '')
|
|
849
859
|
const page = await browser.newPage();
|
|
850
860
|
await page.goto(`http://localhost:${port}` + '#' + route.url, { waitUntil: 'networkidle2' });
|
|
851
861
|
await page.waitForSelector('#root');
|
|
@@ -858,13 +868,15 @@ async function Build() {
|
|
|
858
868
|
await writer(process.cwd() + '/dist/' + (isBasePath ? 'index.html' : `${route.url}/` + 'index.html'), html)
|
|
859
869
|
await browser.close();
|
|
860
870
|
// close http
|
|
861
|
-
server.close()
|
|
862
|
-
console.log(`Generated html file for route ${route.url}`)
|
|
871
|
+
server.close()
|
|
863
872
|
})
|
|
864
873
|
|
|
865
874
|
})
|
|
866
|
-
|
|
867
|
-
|
|
875
|
+
|
|
876
|
+
let timeout = setTimeout(() => {
|
|
877
|
+
globalThis.isBuilding = false
|
|
878
|
+
clearTimeout(timeout)
|
|
879
|
+
}, 1000)
|
|
868
880
|
}
|
|
869
881
|
|
|
870
882
|
globalThis.routes = []
|
|
@@ -927,11 +939,10 @@ async function Build() {
|
|
|
927
939
|
|
|
928
940
|
|
|
929
941
|
|
|
930
|
-
globalThis.routes.push({fileName:fileName, url:obj.url})
|
|
942
|
+
globalThis.routes.push({fileName:fileName, url:obj.url, html:'/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html')})
|
|
931
943
|
|
|
932
944
|
|
|
933
|
-
|
|
934
|
-
|
|
945
|
+
|
|
935
946
|
}
|
|
936
947
|
|
|
937
948
|
ssg(globalThis.routes)
|
|
@@ -1030,11 +1041,87 @@ async function Build() {
|
|
|
1030
1041
|
}
|
|
1031
1042
|
|
|
1032
1043
|
globalThis.isBuilding = false
|
|
1033
|
-
console.log(`Build
|
|
1044
|
+
console.log(`Build completed in ${Date.now() - start}ms with ${Math.round(bundleSize / 1000)}kb`)
|
|
1045
|
+
|
|
1034
1046
|
bundleSize = 0;
|
|
1035
1047
|
return true
|
|
1048
|
+
}
|
|
1049
|
+
const s = ()=>{
|
|
1050
|
+
|
|
1051
|
+
const server = http.createServer((req, res) => {
|
|
1052
|
+
|
|
1053
|
+
if(!req.url.endsWith('.js') && !req.url.endsWith('.css') && !req.url.endsWith('.mjs') && !req.url.endsWith('.cjs') && !req.url.endsWith('.html') && !req.url.endsWith('.json')){
|
|
1054
|
+
req.url = req.url !== '/' ? req.url.split('/')[1] : req.url
|
|
1055
|
+
req.url = process.cwd() + '/dist/' + req.url + '/index.html'
|
|
1056
|
+
}else{
|
|
1057
|
+
req.url = process.cwd() + '/dist/' + req.url
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
const filePath = req.url
|
|
1061
|
+
|
|
1062
|
+
fs.readFile(filePath, (err, data) => {
|
|
1063
|
+
if (err) {
|
|
1064
|
+
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
1065
|
+
res.end(fs.existsSync(process.cwd() + '/dist/404') ? fs.readFileSync(process.cwd() + '/dist/404/index.html') : '404');
|
|
1066
|
+
} else {
|
|
1067
|
+
const contentType = getContentType(filePath);
|
|
1068
|
+
switch(true){
|
|
1069
|
+
case contentType === 'text/html' && globalThis.devMode:
|
|
1070
|
+
data = data.toString() + `<script type="module">
|
|
1071
|
+
let ws = new WebSocket('ws://localhost:3000')
|
|
1072
|
+
ws.onmessage = (e) => {
|
|
1073
|
+
if(e.data === 'reload'){
|
|
1074
|
+
console.log('Reloading page...')
|
|
1075
|
+
window.route.hydrate()
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
</script>
|
|
1079
|
+
`
|
|
1080
|
+
}
|
|
1081
|
+
res.writeHead(200, { 'Content-Type': contentType });
|
|
1082
|
+
res.end(data);
|
|
1083
|
+
}
|
|
1084
|
+
});
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
|
|
1088
|
+
const ws = new WebSocketServer({ server });
|
|
1089
|
+
ws.on('connection', (socket) => {
|
|
1090
|
+
console.log('Client connected');
|
|
1091
|
+
socket.on('close', () => console.log('Client disconnected'));
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
function getContentType(filePath) {
|
|
1096
|
+
if (filePath.includes('js')) {
|
|
1097
|
+
return 'text/javascript';
|
|
1098
|
+
} else if (filePath.includes('.css')) {
|
|
1099
|
+
return 'text/css';
|
|
1100
|
+
} else {
|
|
1101
|
+
return 'text/html';
|
|
1102
|
+
}
|
|
1036
1103
|
}
|
|
1037
|
-
|
|
1104
|
+
|
|
1105
|
+
const PORT = process.env.PORT || 3000;
|
|
1106
|
+
server.listen(PORT, () => {
|
|
1107
|
+
console.log(`Server is running on port ${PORT}`);
|
|
1108
|
+
});
|
|
1109
|
+
let i =
|
|
1110
|
+
setInterval(() => {
|
|
1111
|
+
if (globalThis.isBuilding && globalThis.devMode) {
|
|
1112
|
+
// reload page
|
|
1113
|
+
console.log('Reloading page...')
|
|
1114
|
+
ws.clients.forEach((client) => {
|
|
1115
|
+
client.send('reload')
|
|
1116
|
+
console.log('Reloaded page')
|
|
1117
|
+
})
|
|
1118
|
+
} else{
|
|
1119
|
+
clearInterval(i)
|
|
1120
|
+
}
|
|
1121
|
+
},120)
|
|
1122
|
+
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1038
1125
|
|
|
1039
1126
|
switch (true) {
|
|
1040
1127
|
case process.argv.includes('--watch'):
|
|
@@ -1061,7 +1148,10 @@ Vader.js v1.3.3
|
|
|
1061
1148
|
}
|
|
1062
1149
|
}).on('error', (err) => console.log(err))
|
|
1063
1150
|
})
|
|
1064
|
-
|
|
1151
|
+
|
|
1152
|
+
s()
|
|
1153
|
+
|
|
1154
|
+
globalThis.listen = true;
|
|
1065
1155
|
|
|
1066
1156
|
break;
|
|
1067
1157
|
case process.argv.includes('--build'):
|
|
@@ -1069,8 +1159,20 @@ Vader.js v1.3.3
|
|
|
1069
1159
|
console.log(`
|
|
1070
1160
|
Vader.js v1.3.3
|
|
1071
1161
|
Building to ./dist
|
|
1072
|
-
`)
|
|
1162
|
+
`)
|
|
1073
1163
|
Build()
|
|
1164
|
+
|
|
1165
|
+
break;
|
|
1166
|
+
case process.argv.includes('--serve'):
|
|
1167
|
+
let port = process.argv[process.argv.indexOf('--serve') + 1] || 3000
|
|
1168
|
+
process.env.PORT = port
|
|
1169
|
+
globalThis.devMode = false
|
|
1170
|
+
console.log(`
|
|
1171
|
+
Vader.js v1.3.3
|
|
1172
|
+
Serving ./dist on port ${port}
|
|
1173
|
+
url: http://localhost:${port}
|
|
1174
|
+
`)
|
|
1175
|
+
s()
|
|
1074
1176
|
break;
|
|
1075
1177
|
default:
|
|
1076
1178
|
console.log(`
|
|
@@ -1079,9 +1181,11 @@ Vader.js is a reactive framework for building interactive applications for the w
|
|
|
1079
1181
|
Usage: vader <command>
|
|
1080
1182
|
|
|
1081
1183
|
Commands:
|
|
1082
|
-
--watch Watch the pages folder for changes
|
|
1184
|
+
--watch Watch the pages folder for changes with hot reloading
|
|
1083
1185
|
|
|
1084
1186
|
--build Build the project
|
|
1187
|
+
|
|
1188
|
+
--serve Serve the project on a given port
|
|
1085
1189
|
Learn more about vader: https://vader-js.pages.dev/
|
|
1086
1190
|
|
|
1087
1191
|
`)
|