From 083e37a1736ab4c87aa87132fc0d72cabf6e9a00 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Tue, 6 Jun 2023 22:48:45 -0400 Subject: [PATCH] example started --- example/deno.json | 6 ++++ hmr/hmr.tsx | 76 ++++++++++++++++++++++++++++++++++++++++++++++ hmr/react.tsx | 77 +++++++++++++++++++++++++++++++++++++++++++++++ serve.tsx | 4 +++ 4 files changed, 163 insertions(+) create mode 100644 example/deno.json create mode 100644 hmr/hmr.tsx create mode 100644 hmr/react.tsx diff --git a/example/deno.json b/example/deno.json new file mode 100644 index 0000000..16d929c --- /dev/null +++ b/example/deno.json @@ -0,0 +1,6 @@ +{ + "imports": + { + "react":"https://esm.sh/preact/compat" + } +} \ No newline at end of file diff --git a/hmr/hmr.tsx b/hmr/hmr.tsx new file mode 100644 index 0000000..198981e --- /dev/null +++ b/hmr/hmr.tsx @@ -0,0 +1,76 @@ + +let reloads = 0; +const listeners = new Map() as Mapvoid>>; +const socket:WebSocket = new WebSocket("ws://"+document.location.host); +socket.addEventListener('message', (event) => +{ + let handlers = listeners.get(event.data)??[]; + reloads++; + Promise.all( + handlers.map(handler=> + { + return import(event.data+"?reload="+reloads) + .then(updatedModule=>handler(updatedModule)); + }) + ).then(()=>HMR.update()); +}); +const socketTimer = setInterval(()=>{socket.send("ping")}, 1000); + +export const FileListen =(inPath:string, inHandler:()=>void)=> +{ + const members = listeners.get(inPath)??[]; + members.push(inHandler); + listeners.set(inPath, members); +}; + +const HMR = { + reloads:0, + registered: new Map() as Mapvoid>, + states: new Map(), + statesOld: new Map(), + wireframe: false, + onChange(key:string, value:()=>void):void + { + this.registered.set(key, value); + }, + update() + { + this.reloads++; + this.registered.forEach(handler=>handler()); + this.registered.clear(); + this.statesOld = this.states; + this.states = new Map(); + this.echoState(); + }, + echoState() + { + let output = []; + for(const[key, val] of HMR.statesOld) + { + output[key] = val.state+"--"+val.reload; + } + console.log(output); + output = []; + for(const[key, val] of HMR.states) + { + output[key] = val.state+"--"+val.reload; + } + console.log(output); + } +}; + +export {HMR}; + +export const MapAt =(inMap, inIndex)=> +{ + let index = 0; + for(const kvp of inMap) + { + if(index == inIndex) + { + return kvp; + } + index++; + } + return false; +}; \ No newline at end of file diff --git a/hmr/react.tsx b/hmr/react.tsx new file mode 100644 index 0000000..3b013cd --- /dev/null +++ b/hmr/react.tsx @@ -0,0 +1,77 @@ +import * as ReactParts from "react-original"; +import { HMR, MapAt } from "./hmr.tsx"; + +const H = ReactParts.createElement; + +const ProxyElement = (props)=> +{ + const id = ReactParts.useId(); + const [stateGet, stateSet] = ReactParts.useState(0); + ReactParts.useEffect(()=>HMR.onChange(id, ()=>stateSet(stateGet+1))); + + const child = H(...props.__args); + + if(HMR.wireframe) + { + return H("div", {style:{padding:"10px", border:"2px solid red"}}, + H("p", null, stateGet), + child + ); + } + else + { + return child; + } +}; + +const ProxyCreate =(...args)=> +{ + return typeof args[0] != "string" ? H(ProxyElement, {__args:args, ...args[1]}) : H(...args); +}; + +const ProxyState =(arg)=> +{ + const id = ReactParts.useId(); + const trueArg = arg; + + // does statesOld have an entry for this state? use that instead of the passed arg + const check = MapAt(HMR.statesOld, HMR.states.size); + if(check) + { + arg = check[1].state; + console.info(`BOOTING with ${arg}`); + } + + const lastKnowReloads = HMR.reloads; + const [stateGet, stateSet] = ReactParts.useState(arg); + ReactParts.useEffect(()=>{ + return ()=>{ + if(HMR.reloads == lastKnowReloads) + { + // this is a switch/ui change, not a HMR reload change + const oldState = MapAt(HMR.statesOld, HMR.states.size-1); + HMR.statesOld.set(oldState[0], {...oldState[1], state:trueArg}); + } + HMR.states.delete(id); + } + }, []); + + if(!HMR.states.has(id)) + { + HMR.states.set(id, {state:arg, set:stateSet, reload:HMR.reloads}); + } + + function proxySetter (arg) + { + //console.log("state spy update", id, arg); + HMR.states.set(id, {state:arg, set:stateSet, reload:HMR.reloads}); + return stateSet(arg); + } + return [stateGet, proxySetter]; + +}; + +export * from "react-original"; +export { ProxyCreate as createElement, ProxyState as useState }; +export const isProxy = true; +export default {...ReactParts.default, createElement:ProxyCreate, useState:ProxyState, isProxy:true}; \ No newline at end of file diff --git a/serve.tsx b/serve.tsx index ab5fc68..860e4c3 100644 --- a/serve.tsx +++ b/serve.tsx @@ -84,6 +84,10 @@ HTTP.serve(async(req: Request)=> { const url:URL = new URL(req.url); + if(url.pathname.endsWith("/")) + { + + } if(url.pathname === Configure.Reset) { return new Response(`cache cleared (${Transpile.Clear()} items)`);