vaderjs 1.3.7-alpha-3 → 1.4.0-169o234

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/runtime/router.js CHANGED
@@ -1,261 +1 @@
1
- import { Component } from "./vader.js";
2
-
3
-
4
-
5
-
6
-
7
- /**
8
- * @class VaderRouter
9
- * @description - creates an instance of Vader Express Router
10
- *
11
- * @param {String} path
12
- * @param {Function} handler
13
- * @param {object} req request object
14
- * @param {object} res response object
15
- * @returns {Object} Express
16
- *
17
- */
18
- class VaderRouter{
19
- /**
20
- * @constructor
21
- * @param {*} basePath
22
- *
23
- */
24
- constructor(/**@type {string}**/basePath, /**@type {number}**/port) {
25
- this.routes = [];
26
- this.middlewares = [];
27
- this.errorMiddlewares = [];
28
- this.listeners = [];
29
-
30
- this.basePath = basePath;
31
-
32
- }
33
-
34
- /**
35
- * @method get
36
- * @param {String} path
37
- * @param {Function} handler
38
- * @param {{a:b}} req request object
39
- * @description This method is used to register a get route
40
- * @returns {void}
41
- * @memberof Express
42
- */
43
- get(path, handler) {
44
-
45
- this.routes.push({
46
- path,
47
- handler,
48
- method: 'get',
49
- });
50
- }
51
- /**
52
- * @method use
53
- * @description This method allows you to use middlewares
54
- * @param {Function} middleware
55
- */
56
-
57
- use(/* path, */ middleware) {
58
- this.middlewares.push(middleware);
59
- }
60
-
61
- /**
62
- * @method listen
63
- * @param {String} port - unique id for the listener
64
- * @param {Function} callback - callback function
65
- * @description This method is used to start listening to the routes
66
- * @returns {void}
67
- *
68
- */
69
-
70
- listen(port, callback) {
71
- if(!port){
72
- port = Math.random().toString(36).substring(7);
73
- }
74
- this.listeners.push(port);
75
- if (this.listeners.length === 1) {
76
- this.handleRoute(window.location.hash);
77
- }else{
78
- this.listeners.pop();
79
- }
80
- if (callback) {
81
- callback();
82
- }
83
- window.onhashchange = () => {
84
- this.handleRoute(window.location.hash);
85
- }
86
- }
87
- /**
88
- * @method extractParams
89
- * @description This method is used to extract parameters from the route path
90
- * @param {*} routePath
91
- * @param {*} hash
92
- * @returns {Object} params
93
- * @memberof Express
94
- */
95
-
96
- extractParams(routePath, hash) {
97
- const routeParts = routePath.split('/');
98
- const hashParts = hash.split('/');
99
- const params = {};
100
- routeParts.forEach((part, index) => {
101
- if (part.startsWith(':')) {
102
- const paramName = part.slice(1);
103
- params[paramName] = hashParts[index];
104
- }else if(part.startsWith('*')){
105
- // remove queries from this par
106
- params[0] = hashParts.slice(index).join('/').split('?')[0];
107
- }
108
- });
109
- return params;
110
- }
111
- extractQueryParams(hash){
112
-
113
- const queryParams = hash.split('?')[1];
114
- if(!queryParams){
115
- return {};
116
- }
117
- const params = {};
118
- queryParams.split('&').forEach((param)=>{
119
- const [key, value] = param.split('=');
120
- params[key] = value;
121
- })
122
- return params;
123
- }
124
-
125
- /**
126
- * @method handleRoute
127
- * @param {String} hash
128
- * @description This method is used to handle the route
129
- */
130
-
131
- handleRoute(hash) {
132
- hash = hash.slice(1);
133
- let status = 200;
134
- let route = this.routes.find((route) => {
135
-
136
- if (route.path === hash) {
137
- return true;
138
- }
139
- const routePathParts = route.path.split('/');
140
- const hashParts = hash.split('/');
141
- if (routePathParts.length !== hashParts.length) {
142
- return false;
143
- }else if(routePathParts[routePathParts.length-1].startsWith('*')){
144
- return true;
145
- }
146
- const params = this.extractParams( route.path, hash);
147
- return Object.keys(params).length > 0;
148
- });
149
-
150
- if (!route) {
151
- route = this.routes.find((route) => {
152
-
153
- if(route.path === '/404'){
154
- return true;
155
- }else{
156
- window.location.hash = this.basePath
157
- }
158
- });
159
-
160
- route ? status = 200 :
161
-
162
- status = 404;
163
- }
164
-
165
-
166
- const queryParams = this.extractQueryParams(hash);
167
- const params = route && route.path ? this.extractParams(route.path, hash) : {};
168
- const req = {
169
- headers: {},
170
- params: params,
171
- query: queryParams,
172
- path: hash,
173
- method: route ? route.method : 'get',
174
- };
175
-
176
- // @ts-ignore
177
- window.$CURRENT_URL = req.path
178
-
179
- // @ts-ignore
180
- window.$FULL_URL = window.location.href.replace('#', '')
181
-
182
- const res = {
183
- status: status,
184
- /**
185
- * @method log
186
- * @param {String} type
187
- * @description This method is used to log the request and response
188
- */
189
- log: (type) => {
190
- if(type === undefined){
191
- console.log(`${req.path} ${req.method} ${res.status} ${req.timestamp}`);
192
- }else{
193
- console.table({
194
- 'Request Path': req.path,
195
- 'Request Method': route.method,
196
- 'Response Status': res.status,
197
- 'Request Timestamp': req.timestamp,
198
- });
199
- }
200
- },
201
- render: async (/**@type {Component} */ Component, req, res) => {
202
-
203
- if(!Component.default || !Component.constructor){
204
- let message = !Component.default ? 'default' : 'constructor';
205
- switch(message){
206
- case 'default':
207
- throw new Error(`Component must have a default export ex: return {default: Component}`);
208
-
209
- case 'constructor':
210
- throw new Error(`Component is invalid, please check the constructor`);
211
-
212
- }
213
-
214
- }
215
-
216
- Component = Component.default ? new Component.default() : Component.constructor ? new Component() : Component;
217
-
218
-
219
- Component.mounted = true;
220
-
221
- if(!document.querySelector('#root')){
222
- throw new Error('Root element not found, please add an element with id root');
223
- }
224
- Component.request = req;
225
- Component.response = res;
226
- document.querySelector('#root').innerHTML = Component.render()
227
- Component.bindMount();
228
- Component.onMount()
229
-
230
- },
231
- send: (data) => {
232
- document.querySelector('#root').innerHTML = data;
233
- },
234
- json: (selector, data) => {
235
-
236
- if(typeof selector === 'string'){
237
- // @ts-ignore
238
- let obj = document.createElement('object');
239
- // data url
240
- obj.data = URL.createObjectURL(new Blob([JSON.stringify(data)], {type: 'application/json'}));
241
- // @ts-ignore
242
- document.querySelector(selector).appendChild(obj);
243
- }else{
244
- throw new Error('Selector must be a string');
245
- }
246
- },
247
- };
248
- this.middlewares.forEach((middleware) => {
249
- middleware(req, res);
250
- });
251
-
252
- route ? route.handler(req, res) : null;
253
-
254
- }
255
-
256
- }
257
-
258
- window.VaderRouter = VaderRouter;
259
-
260
- export default VaderRouter;
261
-
1
+ import Vader from"./vader.js";let middlewares=[];class Router{constructor(t,e){this.routes=[],this.middlewares=[],this.errorMiddlewares=[],this.listeners=[],this.basePath=t}get(t,e){this.routes.push({method:"get",path:t,handler:e})}use(t){this.middlewares.push(t)}matchingRoute(){return routes.find((t=>t.url===window.location.pathname||window.location.pathname.split("/")[1]===t.url.split("/")[1]||void 0))}listen(t,e){t||(t=Math.random().toString(36).substring(7)),this.listeners.push(t),window.onpopstate=async t=>{let e=window.location.pathname;if(e.includes("#noNavigation"))return;let r=`/${e.split("/")[1]}`,n=(new DOMParser).parseFromString(await fetch(r,{cache:"reload"}).then((t=>t.text())),"text/html").documentElement,s=(n.querySelector("head"),n.querySelector("body"));document.querySelector("#app").innerHTML=s.querySelector("#app").innerHTML;let o=document.createElement("script");o.id="router",o.innerHTML=s.querySelector('script[id="router"]').innerHTML,o.setAttribute("type","module"),document.body.appendChild(o)},window.location.pathname.includes("#noNavigation")||(console.log("no navigation"),this.handleRoute(window.location.pathname)),e&&e()}render(t){document.querySelector("#app").innerHTML="",Vader.render(t,document.querySelector("#app"))}extractParams(t,e){const r=t.split("/").filter((t=>""!==t)),n=e.split("/").filter((t=>""!==t)),s={};return r.forEach(((t,e)=>{if(t.startsWith(":")){const r=t.slice(1);s[r]=n[e]}else if(t.startsWith("*")){n.slice(e).forEach(((t,e)=>{s[e]=t}))}})),s}extractQueryParams(t){const e=t.split("?")[1];if(!e)return{};const r={};return e.split("&").forEach((t=>{const[e,n]=t.split("=");r[e]=n})),r}checkroute(t){return(t=t.endsWith("/")?t.slice(0,-1):t).includes("?")&&(t=t.split("?")[0]),this.routes.find((e=>{if(e.path===t)return!0;if(""===t&&"/"===e.path)return!0;if(e.path.includes("*")||e.path.includes(":")){const r=e.path.split("/").filter((t=>""!==t)),n=t.split("/").filter((t=>""!==t));if(this.basePath&&n.shift(),console.log(r,n),r.length!==n.length&&!e.path.endsWith("*"))return!1;for(let t=0;t<r.length;t++){const e=r[t],s=n[t];if(!e.startsWith(":")&&!e.startsWith("*")&&e!==s)return!1}return!0}const r=this.extractParams(e.path,t);return Object.keys(r).length>0}))}handleRoute(t){let e=200,r={},n=t,s=this.checkroute(t);console.log(s),s||(e=404,s=this.routes.find((t=>"*"===t.path)),s&&(r=this.extractParams(s.path,t)));const o=this.extractQueryParams(n),a=s&&s.path?this.extractParams(s.path,n):r;Object.keys(a).forEach((t=>{a[t]=a[t].split("?")?a[t].split("?")[0]:a[t]}));const i={headers:{},params:a,query:o,path:t,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 l={status:e,log:t=>{void 0===t?console.log(`${i.path} ${i.method} ${l.status} ${i.timestamp}`):console.table({"Request Path":i.path,"Request Method":s.method,"Response Status":l.status,"Request Timestamp":i.timestamp})},refresh:()=>{this.handleRoute(window.location.pathname)},redirect:t=>{!t.startsWith("/")&&(t=`/${t}`),window.history.pushState({},"",t),window.dispatchEvent(new Event("popstate"))},render:async t=>{document.querySelector("#app").innerHTML="",Vader.render(t,document.querySelector("#app"),{passProps:{router:{req:i,res:l}}})},setQuery:t=>{let e="";Object.keys(t).forEach(((r,n)=>{e+=`${0===n?"?":"&"}${r}=${t[r]}`}));let r=window.location.hash.split("?")[0];e=e.replace("/","-").replaceAll("/","-"),window.location.hash=`${r}${e}`},send:t=>{document.querySelector("#app").innerHTML=t},json:t=>{const e=document.querySelector("#app");e.innerHTML="";const r=document.createElement("pre");r.textContent=JSON.stringify(t,null,2),e.appendChild(r)}};middlewares.forEach((t=>{t(i,l)})),s?l.render(s.handler):l.status(404).send("Not Found")}}export default Router;
@@ -0,0 +1 @@
1
+ let hasMounted=[],hasRendered=[];export const Mounted=(e,t,r=!1)=>{let s=setInterval((()=>{switch(!0){case r&&hasMounted.includes(t.key):return clearInterval(s);case r&&!hasMounted.includes(t.key):hasMounted.push(t.key),e();break;case!document.querySelector(`[key="${t.key}"]`):return;default:e(),clearInterval(s)}}),100)};export class Component{constructor(e){this.state={},this.__internalInstance=null,this.key=e?.key||Math.random(),this.checkMount(),this.mounted=!1}setState(e){this.state=Object.assign({},this.state,e),this.updateInstance(this.__internalInstance)}useState(e,t){this.state[e]||(this.state[e]=t);let r=this.state[e];return r=(()=>this.state[e]||t)(),[r,t=>{r=t,this.state[e]=t,this.updateInstance(this.__internalInstance)}]}useReducer(e,t,r){this.state[e]||(this.state[e]=r);let s=this.state[e];return s=(()=>this.state[e]||r)(),[s,r=>{const n=t(s,r);s=n,this.state[e]=n,this.updateInstance(this.__internalInstance)}]}useRef(e,t){return this.state[e]||(this.state[e]=t),{current:this.state[e]}}onMount(){}domDifference(e,t){let r=[];for(let s=0;s<e.length;s++){let n=e[s],a=t[s];if(n&&a&&n.childNodes.length>0&&a.childNodes.length>0){switch(!0){case n.attributes&&a.attributes&&n.attributes.length!==a.attributes.length:r.push({type:"attributeSwap",old:n,new:a});break;case!n.isEqualNode(a)&&n.nodeName===a.nodeName:r.push({type:"replace",old:n,new:a})}let e=this.domDifference(Array.from(n.childNodes),Array.from(a.childNodes));return r.push(...e),r}!n&&a&&r.push({type:"add",old:n,new:a})}return r}checkMount(){if(this.mounted)return;setInterval((()=>{document.querySelector(`[key="${this.key}"]`)&&!this.mounted&&(this.mounted=!0,this.onMount())}))}updateChangedElements(e){e.forEach((e=>{if(e)switch(e.type){case"replace":if(e.old.panrntNode&&"BODY"===e.old.parentNode.nodeName)return;e.old.replaceWith(e.new.cloneNode(!0));break;case"remove":e.old.remove();break;case"attributeSwap":let t=Array.from(e.old.attributes),r=Array.from(e.new.attributes);t.forEach((t=>{e.old.removeAttribute(t.name)})),r.forEach((t=>{e.old.setAttribute(t.name,t.value)}));break;case"add":e.old.appendChild(e.new.cloneNode(!0))}}))}async updateInstance(e){console.log(e);let t=document.querySelector(`[key="${this.key}"]`)||document.querySelector("#app").firstChild,r=await vjsxx.render(e,t,{return:!0});console.log(r);let s=this.domDifference(Array.from(t.childNodes),Array.from(r.childNodes));this.updateChangedElements(s)}parseStyle(e){let t="";return Object.keys(e).forEach((r=>{let s=e[r];r=r.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,"$1-$2").toLowerCase(),t+=`${r}:${s};`})),t}}class vjsx{constructor(){this._vjsx=!0}isClass(e){return/^\s*class\s+/.test(e.toString())}instanizeClass(e,t={}){if("string"==typeof e||"object"==typeof e)return e;switch(this.isClass(e)){case!0:let r=new e(t);return r.$$typeof="vjsx",r.type=e.name,r.key=t?.key||r.name,r.props=t,r.__internalInstance=()=>r.render(),r.render();case!1:let s=new Component;s.key=e.name+Math.random(),s.__internalInstance=()=>e.bind(s)(t),e.$$typeof="vjsx",e.useState=s.useState.bind(s),e.setState=s.setState.bind(s),e.state=s.state;let n={},a={};return t?.router&&(n=t.router.req,a=t.router.res),e.apply?e.apply(s,[n,a,t]):e}}createElement(e,t,r,...s){let n="function"==typeof e,a=s.find((e=>"vjsx"===e?.$$typeof));if(n)return t.key=r||Math.random(),t.parent=a,this.instanizeClass(e,t);let o={type:e,RootParent:a,props:{...t,key:t?.key||Math.random(),children:Array.isArray(t.children)?t.children:[t.children]}};return"TEXT_ELEMENT"===("string"==typeof o?"TEXT_ELEMENT":o.type)?createTextElement(o):o}async render(e,t,r){let s=this.instanizeClass(e,r?.passProps);if(r&&r?.passProps&&r?.passProps?.router){let e=r.passProps.router.req,s=r.passProps.router.res;e.pause&&await new Promise((n=>{let a=setInterval((()=>{e.pause?s.render&&"function"==typeof s.render&&!hasRendered.includes(s.render.toString())&&(Vader.render(s.render(e,s,r.passProps),t),hasRendered.push(s.render.toString())):(clearInterval(a),n())}),0)}))}if(!s.type)return;let n="TEXT_ELEMENT"===s.type?document.createTextNode(""):document.createElement(s.type),isListener=e=>e.startsWith("on");if(s.props&&(s.props.key&&(s.key=s.props.key),Object.keys(s.props).filter(isListener).forEach((e=>{let t=e.toLowerCase().substring(2);n.addEventListener(t,s.props[e].bind(s))})),Object.keys(s.props).filter((e=>!isListener(e))).forEach((e=>{switch(e){case"classname":n.setAttribute("class",s.props[e]),delete s.props[e];break;case"ref":if(Array.isArray(s.props[e].current))return void s.props[e].current.push(n);s.props[e].current=n;break;case"htmlFor":n.setAttribute("for",s.props[e]);break;case"style":n.setAttribute("style",Component.prototype.parseStyle(s.props[e]));case"children":break;default:n.setAttribute(e,s.props[e])}"TEXT_ELEMENT"!==s.type||(n.nodeValue=s.props[e])}))),s.props&&s.props.children&&Array.isArray(s.props.children)&&s.props?.children&&s.props.children.forEach((e=>{if(Array.isArray(e))return void e.forEach((e=>{null!==e&&this.render(e,n,!0)}));if(!e)return;let t="function"==typeof e?this.instanizeClass(e):e;"TEXT_ELEMENT"!==(t?.type?t.type:"TEXT_ELEMENT")?this.render(t,n):n.appendChild(document.createTextNode(t))})),r?.return)return n;s.key&&n.setAttribute("key",s.key),!r?.return&&document.body.contains(t)&&(s?.RootParent?.onMount(),t.innerHTML=""),r?.return||t.appendChild(n)}}function createTextElement(e){return{type:"TEXT_ELEMENT",props:{nodeValue:e,children:[]}}}export const useState=e=>{this.state[key]||(this.state[key]=e);let t=this.state[key];return t=(()=>this.state[key]||e)(),[t,e=>{t=e,this.state[key]=e,this.updateInstance(this.__internalInstance)}]};export const useReducer=(e,t)=>{const[r,s]=useState(t);return[r,t=>{const n=e(r,t);s(n)}]};export const useRef=e=>{this.state[key]||(this.state[key]=e);let t=this.state[key];return t=(()=>this.state[key]||e)(),[t,e=>{t=e,this.state[key]=e,this.updateInstance(this.__internalInstance)}]};export class Html extends Component{constructor(e){super(e),this.key=e?.key||"DOCUMENT_ROOT",this.props=e,this.checkMount()}render(){return $SERVER?(this.props.lang&&document.documentElement.setAttribute("lang",this.props.lang),vjsxx.createElement("html",{children:this.props.children})):vjsxx.createElement("div",{children:this.props.children,key:this.key})}onMount(){this.props?.parent&&this.props?.parent&&this.props.parent.onMount()}}export class Head extends Component{constructor(e){super(e),this.head=document.createElement("head")}render(){if($SERVER||this.props.updateOnReload){Array.isArray(this.props.children)&&this.props.children.forEach((e=>{this.head.appendChild(vjsxx.render(e,this.head,{return:!0}))})),Object.keys(this.props).includes("children")&&!Array.isArray(this.props.children)&&this.head.appendChild(vjsxx.render(this.props.children,this.head,{return:!0}));let e=document.head;this.head.querySelectorAll("*").forEach((t=>{switch(t.tagName){case"TITLE":e.querySelector("title")&&e.querySelector("title").remove(),e.appendChild(t);break;case"META":if(this.props.updateOnReload)return;return void(e.querySelector(`meta[name="${t.name}"]`)&&e.querySelector(`meta[name="${t.name}"]`).remove());case"LINK":if($SERVER)return void(e.querySelector(`link[href="${t.href}"]`)||e.appendChild(t));case"SCRIPT":if(!t.hasAttribute("eager"))return void(document.querySelector(`script[src="${t.src}"]`)||e.appendChild(t));if(document.querySelector(`script[srcid="${t.src}"]`))return;fetch(t.src).then((e=>e.text())).then((r=>{let s=document.createElement("script");s.innerHTML=r,s.setAttribute("srcid",t.src),s.setAttribute("type",t.type),s.setAttribute("async",t.async||!1),s.setAttribute("defer",t.defer||!1),e.querySelector(`script[srcid="${t.src}"]`)||e.prepend(s)})).catch((e=>{console.warn("Error fetching script",e)}));break;default:console.warn("Unknown tag",t.tagName)}}))}return""}}export class Link extends Component{constructor(e){super(e),this.key=e?.key||Math.random(),this.props=e,this.checkMount()}render(){return vjsxx.createElement("a",{class:this.props.class||this.props.className,style:this.props.style,onClick:e=>{switch(e.preventDefault(),!0){case"outside"===this.props.action:e.preventDefault(),window.open(this.props.href,"_blank");break;case"function"==typeof this.props.action:this.props.action(e);break;default:e.preventDefault(),window.history.pushState({},"",this.props.href),window.dispatchEvent(new Event("popstate"))}},children:this.props.children},this.props?.key,null)}}let vjsxx=new vjsx,Vader={createElement:vjsxx.createElement,useState:useState,instanizeClass:vjsxx.instanizeClass,render:vjsxx.render,useRef:useRef,isClass:vjsxx.isClass,Head:Head,Html:Html,Mounted:Mounted,Component:Component,Link:Link};export default Vader;
package/vader.js ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'fs';
3
+ let vaderisInstalled = process.cwd() + '/node_modules/vaderjs/binaries/main.js'
4
+ if(!fs.existsSync(process.cwd() +'/_dev')){
5
+ fs.mkdirSync(process.cwd() +'/_dev');
6
+ }
7
+
8
+ if(!fs.existsSync(process.cwd() +'/_dev/vader.js')){
9
+ console.log('Copying vader to dev folder....')
10
+ fs.copyFileSync(vaderisInstalled, process.cwd() +'/_dev/vader.js');
11
+ }
12
+
13
+ let args = process.argv.slice(2);
14
+
15
+ function run(arg){
16
+ if(!fs.existsSync(process.cwd() + '/package.json')){
17
+ fs.writeFileSync(process.cwd() + '/package.json', JSON.stringify({name: 'my_app', version: '1.0.0'}, null, 2));
18
+ return;
19
+ }
20
+ let packageJson = JSON.parse(fs.readFileSync(process.cwd() + '/package.json').toString());
21
+ if(!packageJson.scripts){
22
+ packageJson.scripts = {};
23
+ }
24
+ packageJson.scripts['dev'] = 'bun run ./_dev/vader.js dev';
25
+ packageJson.scripts['build'] = 'bun run ./_dev/vader.js build';
26
+ packageJson.scripts['start'] = 'bun run ./_dev/vader.js start';
27
+ if(!packageJson.dependencies){
28
+ packageJson.dependencies = {};
29
+ }
30
+ fs.writeFileSync(process.cwd() + '/package.json', JSON.stringify(packageJson, null, 2));
31
+ console.log(`
32
+ Vader.js is a reactive framework for building interactive applications for the web built ontop of bun.js!
33
+
34
+ Usage: vader <command>
35
+
36
+ Commands:
37
+
38
+ bun run dev -p <number> Start the development server
39
+
40
+ bun run build Build the project to ./dist
41
+
42
+ bun run start -p <number> Production Mode (default 3000 or process.env.PORT)
43
+
44
+ Learn more about vader: https://vader-js.pages.dev/
45
+
46
+ `)
47
+ }
48
+
49
+
50
+ run()
@@ -1,21 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Vaderjs v1.3.3</title>
7
- <meta name="description" content="Vader.js is a modern web framework for building web applications.">
8
- <link rel="shortcut icon" href="https://raw.githubusercontent.com/Postr-Inc/Vader.js/vader1.3.3-beta/logo.png" type="image/x-icon">
9
- </head>
10
- <body>
11
- <div id="root"></div>
12
- <script type="module">
13
- import VaderRouter from './public/vader/router.js'
14
-
15
- const router = new VaderRouter('/', 3000)
16
- window.router = router
17
- await import('./app.js')
18
- router.listen(3000)
19
- </script>
20
- </body>
21
- </html>
package/vader DELETED
Binary file