From f35e5b83bc731e0650aa115e7eb8264fbbb30e26 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Wed, 8 Oct 2025 12:50:23 -0400 Subject: [PATCH] so much --- app.tsx | 4 +- bundle-file.ts | 5 +++ deno.json | 15 +++++-- deno.lock | 36 +++++++++++++++- hmr/hmr-react.tsx | 11 +++-- hmr/hmr-static.tsx | 2 +- index.html | 6 ++- jsx-runtime.tsx | 4 ++ server.ts | 104 ++++++++++++++++++++++++++++++++------------- 9 files changed, 147 insertions(+), 40 deletions(-) create mode 100644 bundle-file.ts create mode 100644 jsx-runtime.tsx diff --git a/app.tsx b/app.tsx index 7ed9a1e..18f6a99 100644 --- a/app.tsx +++ b/app.tsx @@ -1,4 +1,4 @@ -import * as React from ">/npm:react"; +import ReactDOM from "react-dom/client"; export function App(){ return <> @@ -6,4 +6,4 @@ export function App(){ } -export default "lol" \ No newline at end of file +ReactDOM.createRoot(document.body).render(); \ No newline at end of file diff --git a/bundle-file.ts b/bundle-file.ts new file mode 100644 index 0000000..9dd66c3 --- /dev/null +++ b/bundle-file.ts @@ -0,0 +1,5 @@ +const resp = await Deno.bundle({ + entrypoints:["file:///C:/Local%20Web%20Projects/gale/hmr/hmr-react.tsx"] +}); + +console.log(resp); \ No newline at end of file diff --git a/deno.json b/deno.json index e508a14..b6f22c2 100644 --- a/deno.json +++ b/deno.json @@ -4,10 +4,19 @@ }, "compilerOptions": { "jsx": "react-jsx", - "jsxImportSource": "react" + "jsxImportSource": "react", + "types": ["npm:@types/react", "npm:@types/react-dom"], + "lib": [ + "deno.window", "dom", "dom.asynciterable" + ] }, "imports": { - "@std/assert": "jsr:@std/assert@1", - "react":"npm:react" + "react":"npm:react", + "react-dom/client":"npm:react-dom/client", + "@preact/signals":"npm:@preact/signals", + + "signals-original": "npm:@preact/signals", + "react-original": "npm:react" } } + diff --git a/deno.lock b/deno.lock index e6de917..82e9b97 100644 --- a/deno.lock +++ b/deno.lock @@ -1,11 +1,42 @@ { "version": "5", "specifiers": { + "jsr:@std/media-types@*": "1.1.0", + "npm:@preact/signals@*": "2.3.2_preact@10.27.2", + "npm:react-dom@*": "19.2.0_react@19.2.0", "npm:react@*": "19.2.0" }, + "jsr": { + "@std/media-types@1.1.0": { + "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4" + } + }, "npm": { + "@preact/signals-core@1.12.1": { + "integrity": "sha512-BwbTXpj+9QutoZLQvbttRg5x3l5468qaV2kufh+51yha1c53ep5dY4kTuZR35+3pAZxpfQerGJiQqg34ZNZ6uA==" + }, + "@preact/signals@2.3.2_preact@10.27.2": { + "integrity": "sha512-Q22avIn4z0BQnmFeo6Y5HCnJTo8VufN84zN51OtqeNgZOVCYgdwEOcJKVX1x/IrjRVxUnOy6Ubn7H5aVFujXaQ==", + "dependencies": [ + "@preact/signals-core", + "preact" + ] + }, + "preact@10.27.2": { + "integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==" + }, + "react-dom@19.2.0_react@19.2.0": { + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "dependencies": [ + "react", + "scheduler" + ] + }, "react@19.2.0": { "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==" + }, + "scheduler@0.27.0": { + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" } }, "redirects": { @@ -19,7 +50,10 @@ }, "workspace": { "dependencies": [ - "jsr:@std/assert@1", + "npm:@preact/signals@*", + "npm:@types/react-dom@*", + "npm:@types/react@*", + "npm:react-dom@*", "npm:react@*" ] } diff --git a/hmr/hmr-react.tsx b/hmr/hmr-react.tsx index 9f1f6a9..ff59ef5 100644 --- a/hmr/hmr-react.tsx +++ b/hmr/hmr-react.tsx @@ -1,4 +1,8 @@ -import * as ReactParts from "react-original"; +import * as ReactOriginal from "react-original"; + +const ReactParts = ReactOriginal.default ? ReactOriginal.default : ReactOriginal; + +console.log(ReactParts); /* @@ -172,5 +176,6 @@ const ProxyReducer =(inReducer:(inState:Storelike, inAction:string)=>Storelike, }; export * from "react-original"; -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 +const Fragment = ReactParts.Fragment +export {ProxyCreate as createElement, ProxyCreate as jsx, Fragment, ProxyState as useState, ProxyReducer as useReducer }; +export default {...ReactParts, createElement:ProxyCreate, jsx:ProxyCreate, Fragment, useState:ProxyState, useReducer:ProxyReducer}; \ No newline at end of file diff --git a/hmr/hmr-static.tsx b/hmr/hmr-static.tsx index bc4882c..f4e73e5 100644 --- a/hmr/hmr-static.tsx +++ b/hmr/hmr-static.tsx @@ -119,7 +119,7 @@ export const ModuleProxy =(inText:string, inPath:string)=> const [local, foreign] = ModuleShape(inText); console.log("shape local", local); return ` -import {FileListen} from ">/hmr/hmr-listen.tsx"; +import {FileListen} from "/^/hmr/hmr-listen.tsx"; import * as Import from "${inPath}?reload=${new Date().getTime()}"; ${ local.map(m=>`let proxy_${m} = Import.${m}; export { proxy_${m} as ${m} };`).join("\n") } FileListen("${inPath}", (updatedModule)=> diff --git a/index.html b/index.html index a82cdde..6898cc0 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,11 @@ \ No newline at end of file diff --git a/jsx-runtime.tsx b/jsx-runtime.tsx new file mode 100644 index 0000000..d93021c --- /dev/null +++ b/jsx-runtime.tsx @@ -0,0 +1,4 @@ +import Default from "react-jsx-runtime-original"; +const jsx = Default.jsx; +const Fragment = Default.Fragment; +export { jsx, Fragment }; \ No newline at end of file diff --git a/server.ts b/server.ts index b08b57f..07673be 100644 --- a/server.ts +++ b/server.ts @@ -1,13 +1,14 @@ +import { contentType } from "jsr:@std/media-types"; import { ModuleProxy } from "./hmr/hmr-static.tsx"; -const keyProxy = encodeURI(">"); -const keyAdjacent = "^"; +const keyBundle = encodeURI(">"); +const keyAdjacent = encodeURI("^"); const keyReload = "reload"; -const keysRemote = ["npm:", "jsr:", "http"]; const keysExtension = ["ts", "tsx"]; -const extractExtension =(path)=> +const extractExtension =(path:string)=> { - return path.substring(path.lastIndexOf(".")+1); + const ind = path.lastIndexOf("."); + return ind === -1 ? "" : path.substring(ind+1); } const RootRunning = new URL(`file://${Deno.cwd()}`).toString(); @@ -20,15 +21,16 @@ const bakeConfigPackage:Deno.bundle.Options = { entrypoints:[""], platform: "browser", + format:"esm", write: false, minify: true, } const bakeConfigLocal:Deno.bundle.Options = {...bakeConfigPackage, minify:false, sourcemap:"inline", inlineImports:false }; async function BakeForce(path:string, type?:"package") { - console.log("baking", path); const config = type ? bakeConfigPackage : bakeConfigLocal; config.entrypoints[0] = type ? path : RootRunning+path; + console.log("baking", config.entrypoints); const result = await Deno.bundle(config); if(result.outputFiles) @@ -52,34 +54,44 @@ async function BakeCheck(path:string, type?:"package") type CachedTranspile = [file:string, profile:string] const BakeCache:Record = {} +const denoBody = await fetch(RootRunning+"/deno.json").then(resp=>resp.json()); -const JSResponse =(body:string)=>new Response(body, {headers:{"content-type":"application/javascript"}}); +for(const key in denoBody.imports) +{ + const value = denoBody.imports[key]; + if(value.startsWith("npm:")) + { + denoBody.imports[key] = "/>/"+value; + } +} + +denoBody.imports["react-jsx-runtime-original"] = "/>/npm:react/jsx-runtime"; +denoBody.imports["react/jsx-runtime"] = "/^/jsx-runtime.tsx"; + +// denoBody.imports["react-original"] = denoBody.imports["react"]; +// denoBody.imports["react-jsx-runtime-original"] = denoBody.imports[denoBody.compilerOptions.jsxImportSource]+"/jsx-runtime"; +// denoBody.imports["signals-original"] = denoBody.imports["@preact/signals"]; +// denoBody.imports["@preact/signals"] = "/^/hmr/hmr-signal.tsx"; +// denoBody.imports["react"] = "/^/hmr/hmr-react.tsx"; +// denoBody.imports["react/jsx-runtime"] = "/^/hmr/hmr-react.tsx"; + +console.log(denoBody.imports); + +const importMap = ``; + +let htmlPageBody = await fetch(RootRunning+"/index.html").then(resp=>resp.text()); +htmlPageBody = htmlPageBody.replace("", ""+importMap); +const htmlPageHead = {headers:{"content-type":"text/html"}} +const IndexResponse =()=> new Response(htmlPageBody, htmlPageHead); + +const JSHead = {headers:{"content-type":"application/javascript"}}; +const JSResponse =(body:string)=>new Response(body, JSHead); Deno.serve(async(req:Request)=> { - const url = new URL(req.url); - const parts = url.pathname.split("/").filter(part=>part); - - const lastPart = parts.at(-1); - const extension = extractExtension(lastPart); - - console.log("REQUEST:", parts, extension); - - if(parts[0] == keyProxy) - { - const proxiedPath = parts.slice(1).join("/"); - console.log("PROXIED:", proxiedPath); - const transpiled = await BakeCheck(proxiedPath, "package"); - return JSResponse(transpiled[0]); - } - if(keysExtension.includes(extension)) - { - const transpiled = await BakeCheck(url.pathname); - return JSResponse(transpiled[url.searchParams.has(keyReload) ? 0 : 1]); - } - if(req.headers.get("upgrade") == "websocket") { + console.log(" --serve socket", req.url) try { const { response, socket } = Deno.upgradeWebSocket(req); @@ -90,7 +102,41 @@ Deno.serve(async(req:Request)=> return response; } catch(e){ console.log("Socket errored:", e); } - } + } + + const url = new URL(req.url); + const parts = url.pathname.split("/").filter(part=>part); + + const lastPart = parts.at(-1); + const extension = extractExtension(lastPart); + console.log("REQUEST:", parts); + + if(parts[0] == keyBundle) + { + const proxiedPath = parts.slice(1).join("/"); + const transpiled = await BakeCheck(proxiedPath, "package"); + console.log(" --serve bundle", proxiedPath); + return JSResponse(transpiled[0]); + } + if(parts[0] == keyAdjacent) + { + const proxiedPath = "/"+parts.slice(1).join("/"); + const transpiled = await BakeCheck(proxiedPath); + console.log(" --serve adjacent", proxiedPath); + return JSResponse(transpiled[0]); + } + if(keysExtension.includes(extension)) + { + console.log(" --serve local file", parts) + const transpiled = await BakeCheck(url.pathname); + return JSResponse(transpiled[url.searchParams.has(keyReload) ? 0 : 1]); + } + + if(!extension) + { + console.log(" --serving html page", parts); + return IndexResponse(); + } return new Response(); });