This commit is contained in:
Seth Trowbridge 2023-06-20 21:40:49 -04:00
parent e64ce9a144
commit 47ef75c55b
7 changed files with 117 additions and 71 deletions

15
_lib_/boot.tsx Normal file
View File

@ -0,0 +1,15 @@
import "../serve.tsx";
Deno.args.forEach(arg=>
{
if(arg.startsWith("--"))
{
const kvp = arg.substring(2).split("=");
Deno.env.set(kvp[0], kvp[1] || "true");
}
});
if(Deno.env.get("dev"))
{
await import("../local.tsx");
}

View File

@ -24,6 +24,42 @@ export const Shadow =(inElement:HTMLElement, inConfig?:TW.TwindUserConfig)=>
return ShadowDiv;
};
let booted = false;
export const Boot =async(inSettings:{App:()=>React.JSX.Element, CSS?:TW.TwindUserConfig, DOM?:string})=>
{
if(booted){return;}
booted = true;
const settings = {CSS:{...Configure, ...inSettings.CSS||{} }, DOM:inSettings.DOM||"#app", App:inSettings.App};
console.log("Clinet boot called")
let dom = document.querySelector(settings.DOM);
if(!dom)
{
console.log(`element "${settings.DOM}" not found.`);
return false;
}
dom = Shadow(dom as HTMLElement, settings.CSS)
const app = React.createElement(()=> React.createElement(settings.App, null), null);
if(React.render)
{
React.render(app, dom);
return ()=>dom && React.unmountComponentAtNode(dom);
}
else
{
const reactDom = await import(`https://esm.sh/react-dom@${React.version}/client`);
const root = reactDom.createRoot(dom);
root.render(app);
return root.unmount;
}
};
export default async(inSelector:string, inModulePath:string, inMemberApp="default", inMemberCSS="CSS"):Promise<(()=>void)|false>=>
{
let dom = document.querySelector(inSelector);
@ -50,4 +86,4 @@ export default async(inSelector:string, inModulePath:string, inMemberApp="defaul
return root.unmount;
}
};
};

View File

@ -1,23 +0,0 @@
{
"version": "2",
"remote": {
"https://esm.sh/preact@10.15.1": "2b79349676a4942fbcf835c4efa909791c2f0aeca195225bf22bac9866e94b4e",
"https://esm.sh/preact@10.15.1/compat": "07273e22b1c335b8acc9f33c5e78165319c59bd8e2d0f3e5a2b4e028329424d9",
"https://esm.sh/react@18.2.0": "742d8246041966ba1137ec8c60888c35882a9d2478bce63583875f86c1e3687c",
"https://esm.sh/stable/preact@10.15.1/denonext/compat.js": "bad6b5b4d4fdfa5975b7a8d30410bd6877247f058e4952799fab39f66a94b8cf",
"https://esm.sh/stable/preact@10.15.1/denonext/hooks.js": "5c989ad368cf4f2cb3a5d7d1801843d9348c599fe3e7731d04728f7b845d724e",
"https://esm.sh/stable/preact@10.15.1/denonext/preact.mjs": "30710ac1d5ff3711ae0c04eddbeb706f34f82d97489f61aaf09897bc75d2a628",
"https://esm.sh/stable/react@18.2.0/deno/react.mjs": "a5a73ee24acca4744ee22c51d9357f31968d1f684ce253bde222b4e26d09f49f",
"https://esm.sh/v118/@types/prop-types@15.7.5/index.d.ts": "6a386ff939f180ae8ef064699d8b7b6e62bc2731a62d7fbf5e02589383838dea",
"https://esm.sh/v118/@types/react@18.2.0/global.d.ts": "549df62b64a71004aee17685b445a8289013daf96246ce4d9b087d13d7a27a61",
"https://esm.sh/v118/@types/react@18.2.0/index.d.ts": "b091747b1f503f434d3cac4217a13858baba87b421a7054ffdfd797da7737678",
"https://esm.sh/v118/@types/scheduler@0.16.3/tracing.d.ts": "f5a8b384f182b3851cec3596ccc96cb7464f8d3469f48c74bf2befb782a19de5",
"https://esm.sh/v118/csstype@3.1.2/index.d.ts": "4c68749a564a6facdf675416d75789ee5a557afda8960e0803cf6711fa569288",
"https://esm.sh/v118/preact@10.15.1/compat/src/index.d.ts": "9ec63be9612a10ff72fd4183179cde7d551ce43b3a0c2f549d8f788910d8263d",
"https://esm.sh/v118/preact@10.15.1/compat/src/suspense-list.d.ts": "b8e274324392157ce476ef3a48ae215c9f7003b08525d140645f19eab20d1948",
"https://esm.sh/v118/preact@10.15.1/compat/src/suspense.d.ts": "81f5266e0977a94347505d11b8103024211f2b4f3b2eb2aa276a10d8fd169e65",
"https://esm.sh/v118/preact@10.15.1/hooks/src/index.d.ts": "933eab6436614f8cd8e9b7c9b8bd54c6f3f14c3f065ba42c8c87a42d93de6595",
"https://esm.sh/v118/preact@10.15.1/src/index.d.ts": "fa83186a4b6caca36d52ca2d49b481c3ca5460988d4a8388d44dadc28987fb27",
"https://esm.sh/v118/preact@10.15.1/src/jsx.d.ts": "a6e4b7e4af3b959f8cfd41a0f475c547807ebcec8524d9605ab5c6de79f302fa"
}
}

View File

@ -1,3 +1,4 @@
import "../_lib_/boot.tsx";
import React from "react";
const CTXString = React.createContext("lol");
@ -30,13 +31,13 @@ const builder =(inState:Store):Store=>
return inState;
}
export default ()=>
{
const [Store, Dispatch] = React.useReducer(reducer, {name:"seth", age:24} as Store, builder)
return <CTXString.Provider value="intradestink">
<div class="my-4 font-sans">
<h1 class="font-black text-xl">Title!!!!</h1>
<h1 class="font-black text-xl text-red-500">Title?</h1>
<h2>subtitle!</h2>
<p>
<button onClick={e=>Dispatch(1)}>{Store.name}|{Store.age}?</button>
@ -48,5 +49,5 @@ export default ()=>
<Outer>
<Inner/>
</Outer>
</CTXString.Provider>
}
</CTXString.Provider>;
}

View File

@ -2,12 +2,11 @@
"compilerOptions": { "lib": ["deno.window", "dom"] },
"imports":
{
"react":"https://esm.sh/preact@10.15.1/compat",
"@app": "./app.tsx"
"react":"https://esm.sh/preact@10.15.1/compat"
},
"tasks":
{
"local": "deno run -A --no-lock ../local.tsx",
"serve": "deno run -A --no-lock ../serve.tsx"
"local": "deno run -A --no-lock app.tsx --dev",
"serve": "deno run -A --no-lock app.tsx"
}
}

View File

@ -2,10 +2,8 @@ import {Configure, Transpile, Extension} from "./serve.tsx";
const SocketsLive:Set<WebSocket> = new Set();
const SocketsSend =(inData:string)=>{ console.log(inData); for (const socket of SocketsLive){ socket.send(inData); } }
const Directory = `file://${Deno.cwd().replaceAll("\\", "/")}`;
Configure({
Proxy:Directory,
SWCOp:
{
sourceMaps: "inline",
@ -36,11 +34,11 @@ Configure({
console.log(inImports);
return inImports;
},
async Serve(inReq, inURL, inExt, inMap)
async Serve(inReq, inURL, inExt, inMap, inProxy)
{
if(Transpile.Check(inExt) && !inURL.searchParams.get("reload") && !inURL.pathname.startsWith("/_lib_/"))
{
const imp = await import(Directory+inURL.pathname);
const imp = await import(inProxy+inURL.pathname);
const members = [];
for( const key in imp ) { members.push(key); }
@ -73,35 +71,40 @@ FileListen("${inURL.pathname}", (updatedModule)=>
}
});
let blocking = false;
const filesChanged:Map<string, string> = new Map();
for await (const event of Deno.watchFs(Deno.cwd()))
const Watcher =async()=>
{
event.paths.forEach( path => filesChanged.set(path, event.kind) );
if(!blocking)
let blocking = false;
const filesChanged:Map<string, string> = new Map();
for await (const event of Deno.watchFs(Deno.cwd()))
{
blocking = true;
setTimeout(async()=>
event.paths.forEach( path => filesChanged.set(path, event.kind) );
if(!blocking)
{
for await (const [path, action] of filesChanged)
blocking = true;
setTimeout(async()=>
{
if(Transpile.Check(Extension(path)))
for await (const [path, action] of filesChanged)
{
const key = path.substring(Deno.cwd().length).replaceAll("\\", "/");
if(action != "remove")
{
const tsx = await Transpile.Fetch(Directory+key, key, true);
tsx && SocketsSend(key);
}
else
if(Transpile.Check(Extension(path)))
{
Transpile.Cache.delete(key);
const key = path.substring(Deno.cwd().length).replaceAll("\\", "/");
if(action != "remove")
{
const tsx = await Transpile.Fetch(`file://${Deno.cwd().replaceAll("\\", "/")}`+key, key, true);
tsx && SocketsSend(key);
}
else
{
Transpile.Cache.delete(key);
}
}
}
filesChanged.clear();
blocking = false;
}
filesChanged.clear();
blocking = false;
, 1000);
}
, 1000);
}
}
}
Watcher().then(()=>console.log("done watching"));

View File

@ -23,16 +23,16 @@ const ImportMapReload =async()=>
ImportMap.imports = Configuration.Remap(json.imports);
};
type CustomHTTPHandler = (inReq:Request, inURL:URL, inExt:string|false, inMap:{imports:Record<string, string>})=>void|false|Response|Promise<Response|void|false>;
type CustomHTTPHandler = (inReq:Request, inURL:URL, inExt:string|false, inMap:{imports:Record<string, string>}, inProxy:string)=>void|false|Response|Promise<Response|void|false>;
type CustomRemapper = (inImports:Record<string, string>)=>Record<string, string>;
type Configuration = {Proxy:string, Allow:string, Reset:string, SWCOp:SWCW.Options, Serve:CustomHTTPHandler, Shell:CustomHTTPHandler, Remap:CustomRemapper};
type ConfigurationArgs = {Proxy?:string, Allow?:string, Reset?:string, SWCOp?:SWCW.Options, Serve?:CustomHTTPHandler, Shell?:CustomHTTPHandler, Remap?:CustomRemapper};
let Configuration:Configuration =
{
Proxy: `file://${Deno.cwd().replaceAll("\\", "/")}`,
Proxy: new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(),
Allow: "*",
Reset: "/clear-cache",
Serve(inReq, inURL, inExt, inMap){},
Serve(inReq, inURL, inExt, inMap, inProxy){},
Remap: (inImports)=>
{
Object.entries(inImports).forEach(([key, value])=>
@ -51,8 +51,13 @@ let Configuration:Configuration =
console.log(inImports);
return inImports;
},
Shell(inReq, inURL, inExt, inMap)
Shell(inReq, inURL, inExt, inMap, inProxy)
{
console.log("Start app:", Deno.mainModule, "start dir", inProxy);
console.log("Split:", Deno.mainModule.split(inProxy) );
const parts = Deno.mainModule.split(inProxy);
return new Response(
`<!doctype html>
<html>
@ -62,8 +67,8 @@ let Configuration:Configuration =
<div id="app"></div>
<script type="importmap">${JSON.stringify(inMap)}</script>
<script type="module">
import Mount from "/_lib_/mount.tsx";
Mount("#app", "@app");
import Mount from "/_lib_/mount.tsx";
Mount("#app", "${parts[1]??"/app.tsx"}");
</script>
</body>
</html>`, {status:200, headers:{"content-type":"text/html"}});
@ -162,7 +167,7 @@ HTTP.serve(async(req: Request)=>
}
// allow for custom handler
const custom = await Configuration.Serve(req, url, ext, ImportMap);
const custom = await Configuration.Serve(req, url, ext, ImportMap, Configuration.Proxy);
if(custom)
{
return custom;
@ -171,26 +176,36 @@ HTTP.serve(async(req: Request)=>
// transpileable files
if(Transpile.Check(ext))
{
let code;
let path;
if(url.pathname.startsWith("/_lib_/"))
{
const path = import.meta.url+"/.."+url.pathname;
const code = await Transpile.Fetch(path, url.pathname, true);
if(code)
if(url.pathname.endsWith("boot.tsx"))
{
return new Response(code, {headers:{"content-type":"application/javascript"}});
path = import.meta.url+"/../_lib_/mount.tsx";
}
else
{
path = import.meta.url+"/.."+url.pathname;
}
code = await Transpile.Fetch(path, url.pathname, true);
}
else
{
const lookup = await Transpile.Fetch(Configuration.Proxy + url.pathname, url.pathname);
return new Response(lookup, {status:lookup?200:404, headers:{...headers, "content-type":"application/javascript"}} );
path = Configuration.Proxy + url.pathname;
code = await Transpile.Fetch(path, url.pathname);
}
if(code)
{
return new Response(code, {headers:{...headers, "content-type":"application/javascript"}} );
}
}
// custom page html
if(!ext)
{
const shell = await Configuration.Shell(req, url, ext, ImportMap);
const shell = await Configuration.Shell(req, url, ext, ImportMap, Configuration.Proxy);
if(shell)
{
return shell;