From c44c1df257a6f52dc99f9da3fe3b1fec4330a9ac Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Thu, 12 Oct 2023 22:47:45 -0400 Subject: [PATCH 1/7] misc items --- checker.tsx | 1 + cli.tsx | 5 ++-- deno.jsonc | 5 ++-- hmr-signal.tsx | 0 run-browser.tsx | 2 +- run-local.tsx | 4 +++ run-serve.tsx | 79 ------------------------------------------------- 7 files changed, 12 insertions(+), 84 deletions(-) create mode 100644 hmr-signal.tsx diff --git a/checker.tsx b/checker.tsx index a5f1100..76287b0 100644 --- a/checker.tsx +++ b/checker.tsx @@ -170,6 +170,7 @@ export async function Check() importMap["react"] = `https://esm.sh/preact@10.17.1/compat`; importMap["react/"] = `https://esm.sh/preact@10.17.1/compat/`; importMap["@preact/signals"] = `https://esm.sh/@preact/signals@1.2.1`; + importMap["@twind/core"] = `https://esm.sh/@twind/core@1.1.3`; importMap[">able/"] = `${RootHost}`; if(!importMap[">able/app.tsx"]) { diff --git a/cli.tsx b/cli.tsx index 13b9f3e..931c240 100644 --- a/cli.tsx +++ b/cli.tsx @@ -123,9 +123,10 @@ if(arg._.length) `--project=${useProject}`, `--token=${useToken}`, `--import-map=${imports.path}`, - RootHost+"run.tsx", + ...scanProd, - ...Deno.args]); + ...Deno.args, + RootHost+"run.tsx"]); } case "upgrade" : { diff --git a/deno.jsonc b/deno.jsonc index 95b17a3..8e0c78d 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -2,9 +2,10 @@ "imports": { "react": "https://esm.sh/preact@10.17.1/compat", "react/": "https://esm.sh/preact@10.17.1/compat/", + "@preact/signals": "https://esm.sh/@preact/signals@1.2.1", + "@twind/core": "https://esm.sh/@twind/core@1.1.3", ">able/": "http://localhost:4507/", - ">able/app.tsx": "./app.tsx", - "@preact/signals": "https://esm.sh/@preact/signals@1.2.1" + ">able/app.tsx": "./app.tsx" }, "tasks": { "check": "deno run -A --no-lock http://localhost:4507/cli.tsx check", diff --git a/hmr-signal.tsx b/hmr-signal.tsx new file mode 100644 index 0000000..e69de29 diff --git a/run-browser.tsx b/run-browser.tsx index 018f55d..cf064c4 100644 --- a/run-browser.tsx +++ b/run-browser.tsx @@ -1,5 +1,5 @@ import React from "react"; -import * as TW from "https://esm.sh/v126/@twind/core@1.1.3/es2022/core.mjs"; +import * as TW from "@twind/core"; import TWPreTail from "https://esm.sh/v126/@twind/preset-tailwind@1.1.3/es2022/preset-tailwind.mjs"; import TWPreAuto from "https://esm.sh/v126/@twind/preset-autoprefix@1.0.7/es2022/preset-autoprefix.mjs"; diff --git a/run-local.tsx b/run-local.tsx index 94553e5..7042f27 100644 --- a/run-local.tsx +++ b/run-local.tsx @@ -27,6 +27,10 @@ Configure({ { inImports["react-original"] = inImports["react"]; inImports["react"] = `/>able/hmr-react.tsx`; + + inImports["signals-original"] = inImports["@preact/signals"]; + inImports["@preact/signals"] = `/>able/hmr-signals.tsx`; + return inImports; }, async Extra(inReq, inURL, inExt, inMap, inConfig) diff --git a/run-serve.tsx b/run-serve.tsx index 74e81a5..253f887 100644 --- a/run-serve.tsx +++ b/run-serve.tsx @@ -122,85 +122,6 @@ export const Transpile = ImportMapReload(); return size; }, - /** - * DONT USE - * Converts dynamic module imports in to static, also can resolve paths with an import map - */ - async Patch(inPath:string, inKey:string, inMap?:DenoConfig) - { - const check = this.Cache.get(inKey); - if(check) - { - return check; - } - - let file, text; - try - { - file = await fetch(inPath); - text = await file.text(); - } - catch(e) - { - return false; - } - - const remap = inMap ? (inPath:string)=> - { - const match = inMap.imports[inPath]; - if(match) - { - return match; - } - else if(inPath.includes("/")) - { - let bestKey = ""; - let bestLength = 0; - Object.keys(inMap.imports).forEach((key, i, arr)=> - { - if(key.endsWith("/") && inPath.startsWith(key) && key.length > bestLength) - { - bestKey = key; - bestLength = key.length; - } - }); - if(bestKey) - { - return inMap.imports[bestKey]+inPath.substring(bestKey.length); - } - } - return inPath; - } - : (inPath:string)=>inPath; - let match, regex; - let convertedBody = text; - - // remap static imports - regex = /from\s+(['"`])(.*?)\1/g; - while ((match = regex.exec(text))) - { - const importStatement = match[0]; - const importPath = match[2]; - convertedBody = convertedBody.replace(importStatement, `from "${remap(importPath)}"`); - } - - // convert dynamic imports into static (to work around deno deploy) - const staticImports = []; - regex = /(? Date: Sat, 14 Oct 2023 12:06:11 -0400 Subject: [PATCH 2/7] fix lib comp opts --- checker.tsx | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/checker.tsx b/checker.tsx index 76287b0..53b9d11 100644 --- a/checker.tsx +++ b/checker.tsx @@ -196,18 +196,30 @@ export async function Check() const confTasks = (config.json.tasks || {}) as Record; config.json.tasks = {...confTasks, ...tasks}; - const options = + const optionsRequired = { - "lib": ["deno.window", "dom", "dom.asynciterable"], + "lib": ["deno.window", "dom", "dom.iterable", "dom.asynciterable"], "jsx": "react-jsx", "jsxImportSource": "react" } - const compOpts = config.json.compilerOptions as Record || {}; - const compLib:string[] = compOpts.lib as string[] || []; - compOpts.jsx = options.jsx; - compOpts.jsxImportSource = options.jsxImportSource; - compOpts.lib = [...compLib, ...options.lib]; - config.json.compilerOptions = compOpts; + const optionsCurrent = config.json.compilerOptions as Record || {}; + //const compLib:string[] = compOpts.lib as string[] || []; + + if(!optionsCurrent.lib) + { + optionsCurrent.lib = []; + } + optionsRequired.lib.forEach(s=> + { + if(!optionsCurrent.lib.includes(s)) + { + (optionsCurrent.lib as string[]).push(s); + } + }); + + optionsCurrent.jsx = optionsRequired.jsx; + optionsCurrent.jsxImportSource = optionsRequired.jsxImportSource; + config.json.compilerOptions = optionsCurrent; await bake(imports); await bake(config); -- 2.34.1 From 2b83a2abe6e511c8f6086e14fd340634bda47b0d Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Sat, 14 Oct 2023 12:09:06 -0400 Subject: [PATCH 3/7] separate HMR listeners --- hmr-listen.tsx | 57 +++++--------------------------------------------- hmr-react.tsx | 53 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 53 deletions(-) diff --git a/hmr-listen.tsx b/hmr-listen.tsx index 4ec21be..9a444a8 100644 --- a/hmr-listen.tsx +++ b/hmr-listen.tsx @@ -1,4 +1,6 @@ -import { type StateCapture } from "./hmr-react.tsx"; +type Processor = (filename:string)=>void; +const Processors:Set = new Set(); +export const Process =(p:Processor)=>Processors.add(p) const FileListeners = new Map() as Mapvoid>>; export const FileListen =(inPath:string, inHandler:()=>void)=> @@ -15,56 +17,7 @@ Socket.addEventListener('message', async(event:{data:string})=> // send the updated members to any listeners for that file const reImport = await import(document.location.origin+event.data+"?reload="+Math.random()); FileListeners.get(event.data)?.forEach(reExport=>reExport(reImport)); - HMR.update(); + Processors.forEach(p=>p(event.data)) }); Socket.addEventListener("error", ()=>{clearInterval(SocketTimer); console.log("HMR socket lost")}) -const SocketTimer = setInterval(()=>{Socket.send("ping")}, 5000); - -/* - -Each custom component is secretly modified to have an extra state and id. -When there is an HMR update, this state is changed, forcing it to re-render. - -Each *user-created* React.useState is secretly modified and accompanied by an ID. -Every time its state is set, the HMR.statesNew map for this ID is set to contain the new state and updater. -When a component is removed, any of it's states in HMR.statesNew are also removed. -(HMR.statesNew is the "running total" of all states currently at play). - ---- - -When a state is interacted with: -- statesNew for this id is set -- the internal state is also set in the traditional way - -When there is an HMR update: -- All custom components are re-rendered... - for each useState(value) call that then happens in the re-render: - - if there is a "statesOld" value for this state, use that and ignore the passed value, otherwise use the passed value - - if this state has not been interacted with since the last reload (statesNew is empty at this id), set statesNew with whatever is in statesOld -- statesNew is moved into *statesOld* -- statesNew is cleared. - -*/ - -const HMR = -{ - reloads:1, - RegisteredComponents: new Map() as Mapvoid>, - statesNew: new Map() as Map, - statesOld: new Map() as Map, - wireframe: false, - RegisterComponent(reactID:string, value:()=>void):void - { - this.RegisteredComponents.set(reactID, value); - }, - update() - { - this.reloads++; - this.RegisteredComponents.forEach(handler=>handler()); - this.RegisteredComponents.clear(); - this.statesOld = this.statesNew; - this.statesNew = new Map(); - } -}; - -export {HMR}; \ No newline at end of file +const SocketTimer = setInterval(()=>{Socket.send("ping")}, 5000); \ No newline at end of file diff --git a/hmr-react.tsx b/hmr-react.tsx index b47bb8a..444bc11 100644 --- a/hmr-react.tsx +++ b/hmr-react.tsx @@ -1,5 +1,56 @@ import * as ReactParts from "react-original"; -import { HMR } from "./hmr-listen.tsx"; +import { Process } from "./hmr-listen.tsx"; + + +/* + +Each custom component is secretly modified to have an extra state and id. +When there is an HMR update, this state is changed, forcing it to re-render. + +Each *user-created* React.useState is secretly modified and accompanied by an ID. +Every time its state is set, the HMR.statesNew map for this ID is set to contain the new state and updater. +When a component is removed, any of it's states in HMR.statesNew are also removed. +(HMR.statesNew is the "running total" of all states currently at play). + +--- + +When a state is interacted with: +- statesNew for this id is set +- the internal state is also set in the traditional way + +When there is an HMR update: +- All custom components are re-rendered... + for each useState(value) call that then happens in the re-render: + - if there is a "statesOld" value for this state, use that and ignore the passed value, otherwise use the passed value + - if this state has not been interacted with since the last reload (statesNew is empty at this id), set statesNew with whatever is in statesOld +- statesNew is moved into *statesOld* +- statesNew is cleared. + +*/ +const HMR = +{ + reloads:1, + RegisteredComponents: new Map() as Mapvoid>, + statesNew: new Map() as Map, + statesOld: new Map() as Map, + wireframe: false, + RegisterComponent(reactID:string, value:()=>void):void + { + this.RegisteredComponents.set(reactID, value); + }, + update() + { + this.reloads++; + this.RegisteredComponents.forEach(handler=>handler()); + this.RegisteredComponents.clear(); + this.statesOld = this.statesNew; + this.statesNew = new Map(); + } +}; +Process(()=>HMR.update()) + + + export type StateType = boolean|number|string|Record export type StateCapture = {state:StateType, set:ReactParts.StateUpdater, reload:number}; -- 2.34.1 From 9e7fe002b038b9404e2a474e7b2d5c8f66f1059c Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Sat, 14 Oct 2023 23:47:20 -0400 Subject: [PATCH 4/7] signal started --- checker.tsx | 4 ++-- deno.jsonc | 2 ++ hmr-signal.tsx | 16 ++++++++++++++++ run-local.tsx | 2 +- run-serve.tsx | 2 +- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/checker.tsx b/checker.tsx index 53b9d11..c44c7bd 100644 --- a/checker.tsx +++ b/checker.tsx @@ -167,8 +167,8 @@ export async function Check() const importMap = imports.json.imports as Record; const bake =async(obj:ConfigCheck)=> await Deno.writeTextFile(Deno.cwd()+"/"+obj.path, JSON.stringify(obj.json, null, "\t")); - importMap["react"] = `https://esm.sh/preact@10.17.1/compat`; - importMap["react/"] = `https://esm.sh/preact@10.17.1/compat/`; + importMap["react"] = `https://esm.sh/preact@10.18.1/compat`; + importMap["react/"] = `https://esm.sh/preact@10.18.1/compat/`; importMap["@preact/signals"] = `https://esm.sh/@preact/signals@1.2.1`; importMap["@twind/core"] = `https://esm.sh/@twind/core@1.1.3`; importMap[">able/"] = `${RootHost}`; diff --git a/deno.jsonc b/deno.jsonc index 8e0c78d..8c5bac3 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,8 +1,10 @@ { "imports": { "react": "https://esm.sh/preact@10.17.1/compat", + "react-original": "https://esm.sh/preact@10.17.1/compat", "react/": "https://esm.sh/preact@10.17.1/compat/", "@preact/signals": "https://esm.sh/@preact/signals@1.2.1", + "signals-original": "https://esm.sh/@preact/signals@1.2.1", "@twind/core": "https://esm.sh/@twind/core@1.1.3", ">able/": "http://localhost:4507/", ">able/app.tsx": "./app.tsx" diff --git a/hmr-signal.tsx b/hmr-signal.tsx index e69de29..5febad0 100644 --- a/hmr-signal.tsx +++ b/hmr-signal.tsx @@ -0,0 +1,16 @@ +import * as SignalsParts from "signals-original"; +import { Process } from "./hmr-listen.tsx"; + + +const s1 = SignalsParts.signal(true); + +const proxySignal =(arg)=> +{ + console.log("---hmr---", arg); + return SignalsParts.signal(arg); +} + +export * from "signals-original"; +export { proxySignal as signal }; +// ? export {ProxyCreate as createElement, ProxyState as useState, ProxyReducer as useReducer }; +// ? export default {...ReactParts, createElement:ProxyCreate, useState:ProxyState, useReducer:ProxyReducer}; \ No newline at end of file diff --git a/run-local.tsx b/run-local.tsx index 7042f27..a845712 100644 --- a/run-local.tsx +++ b/run-local.tsx @@ -29,7 +29,7 @@ Configure({ inImports["react"] = `/>able/hmr-react.tsx`; inImports["signals-original"] = inImports["@preact/signals"]; - inImports["@preact/signals"] = `/>able/hmr-signals.tsx`; + inImports["@preact/signals"] = `/>able/hmr-signal.tsx`; return inImports; }, diff --git a/run-serve.tsx b/run-serve.tsx index 253f887..cb61263 100644 --- a/run-serve.tsx +++ b/run-serve.tsx @@ -74,7 +74,7 @@ let Configuration:Configuration =
- +