Compare commits
	
		
			5 Commits
		
	
	
		
			master
			...
			deprecate-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f36278453b | |||
| 35592bb183 | |||
| f5d7ca2e95 | |||
| 70a0c2e96f | |||
| b18df9ff89 | 
							
								
								
									
										3
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							| @ -10,9 +10,10 @@ | ||||
|             "type": "node", | ||||
|             "program": "${workspaceFolder}/server.tsx", | ||||
|             "cwd": "${workspaceFolder}", | ||||
|             "runtimeExecutable": "deno.exe", | ||||
|             "runtimeExecutable": "C:\\Users\\Seth\\.deno\\bin\\deno.EXE", | ||||
|             "runtimeArgs": [ | ||||
|                 "run", | ||||
|                 "--no-lock", | ||||
|                 "--unstable", | ||||
|                 "--inspect-wait", | ||||
|                 "--allow-all" | ||||
|  | ||||
| @ -4,9 +4,8 @@ | ||||
|     ]}, | ||||
|     "imports": { | ||||
|         "react": "https://esm.sh/preact@10.13.2/compat", | ||||
|          | ||||
|         "preact": "https://esm.sh/preact@10.13.2/compat", | ||||
|         "react-original": "https://esm.sh/preact@10.13.2/compat", | ||||
|         "@eno/app": "./example/app.tsx", | ||||
|         "@eno/iso": "./lib/iso.tsx" | ||||
|     }, | ||||
|     "tasks": | ||||
							
								
								
									
										52
									
								
								deno.lock
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								deno.lock
									
									
									
									
									
								
							| @ -1,52 +0,0 @@ | ||||
| { | ||||
|   "version": "2", | ||||
|   "remote": { | ||||
|     "https://deno.land/std@0.151.0/async/debounce.ts": "564273ef242bcfcda19a439132f940db8694173abffc159ea34f07d18fc42620", | ||||
|     "https://deno.land/std@0.180.0/media_types/_db.ts": "7606d83e31f23ce1a7968cbaee852810c2cf477903a095696cdc62eaab7ce570", | ||||
|     "https://deno.land/std@0.180.0/media_types/_util.ts": "916efbd30b6148a716f110e67a4db29d6949bf4048997b754415dd7e42c52378", | ||||
|     "https://deno.land/std@0.180.0/media_types/content_type.ts": "c682589a0aeb016bfed355cc1ed6fbb3ead2ea48fc0000ac5de6a5730613ad1c", | ||||
|     "https://deno.land/std@0.180.0/media_types/extension.ts": "7a4ef2813d7182f724a941f38161525996e4a67abc3cf6a0f9bc2168d73a0f0e", | ||||
|     "https://deno.land/std@0.180.0/media_types/extensions_by_type.ts": "4358023feac696e6e9d49c0f1e76a859f03ca254df57812f31f8536890c3a443", | ||||
|     "https://deno.land/std@0.180.0/media_types/format_media_type.ts": "1e35e16562e5c417401ffc388a9f8f421f97f0ee06259cbe990c51bae4e6c7a8", | ||||
|     "https://deno.land/std@0.180.0/media_types/get_charset.ts": "8be15a1fd31a545736b91ace56d0e4c66ea0d7b3fdc5c90760e8202e7b4b1fad", | ||||
|     "https://deno.land/std@0.180.0/media_types/mod.ts": "d3f0b99f85053bc0b98ecc24eaa3546dfa09b856dc0bbaf60d8956d2cdd710c8", | ||||
|     "https://deno.land/std@0.180.0/media_types/parse_media_type.ts": "bed260d868ea271445ae41d748e7afed9b5a7f407d2777ead08cecf73e9278de", | ||||
|     "https://deno.land/std@0.180.0/media_types/type_by_extension.ts": "6076a7fc63181d70f92ec582fdea2c927eb2cfc7f9c9bee9d6add2aca86f2355", | ||||
|     "https://deno.land/std@0.180.0/media_types/vendor/mime-db.v1.52.0.ts": "6925bbcae81ca37241e3f55908d0505724358cda3384eaea707773b2c7e99586", | ||||
|     "https://deno.land/std@0.185.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", | ||||
|     "https://deno.land/std@0.185.0/json/common.ts": "ecd5e87d45b5f0df33238ed8b1746e1444da7f5c86ae53d0f0b04280f41a25bb", | ||||
|     "https://deno.land/std@0.185.0/jsonc/mod.ts": "b88dce28eb3645667caa856538ae2fe87af51410822544a0b45a4177ef3bd7dd", | ||||
|     "https://deno.land/std@0.185.0/jsonc/parse.ts": "2910e33bc7c3b243e3b6f3a39ce4d6ca84337b277a8df6f2ad2d9e4adbcddc08", | ||||
|     "https://deno.land/x/denoflate@1.2.1/mod.ts": "f5628e44b80b3d80ed525afa2ba0f12408e3849db817d47a883b801f9ce69dd6", | ||||
|     "https://deno.land/x/denoflate@1.2.1/pkg/denoflate.js": "b9f9ad9457d3f12f28b1fb35c555f57443427f74decb403113d67364e4f2caf4", | ||||
|     "https://deno.land/x/denoflate@1.2.1/pkg/denoflate_bg.wasm.js": "d581956245407a2115a3d7e8d85a9641c032940a8e810acbd59ca86afd34d44d", | ||||
|     "https://deno.land/x/esbuild@v0.17.4/mod.d.ts": "dc279a3a46f084484453e617c0cabcd5b8bd1920c0e562e4ea02dfc828c8f968", | ||||
|     "https://deno.land/x/esbuild@v0.17.4/mod.js": "28f92694d79c8ef313e7ead7bb0e915551a805c3ad14dd2af24bbb0872e38c0d", | ||||
|     "https://esm.sh/@twind/core@1.1.3": "022193fe0f683445f35b232bf4a105d2c2aa48cc035332b4939d4f795c7ed48f", | ||||
|     "https://esm.sh/preact-ssr-prepass@1.2.0": "2ad461cd2ebd0ccb3b0345102e51f94923084f089b85805da5ca97d0b8db77d2", | ||||
|     "https://esm.sh/preact@10.13.2/compat": "1cf68e0c8c6c84b60d42f30665403b67229c16ff5206824709b19df60ba9cdc3", | ||||
|     "https://esm.sh/stable/preact@10.13.2/deno/compat.js": "3151a948abd84aa75dfc9e57733da7e1a45fff7a25de58c7b6025b923874b508", | ||||
|     "https://esm.sh/stable/preact@10.13.2/deno/hooks.js": "c7a8e703bcbc6a05949f329b618c33d5d1ea5fee113ddcea44ff0f527af8556f", | ||||
|     "https://esm.sh/stable/preact@10.13.2/deno/preact.mjs": "365fab897381f4f403f859c5d12939084560545567108cc90dae901bbe892578", | ||||
|     "https://esm.sh/v113/preact-render-to-string@6.0.2": "9e27e8724b3e53ba3d006146efa7ac0d6764672e4cd7a2fb5738412526c2b16d", | ||||
|     "https://esm.sh/v113/preact-render-to-string@6.0.2/deno/preact-render-to-string.mjs": "09ead691b3745189a4171a6ee0948592c7a862b1bf1a97fe651fb34f88eabe3b", | ||||
|     "https://esm.sh/v113/preact-render-to-string@6.0.2/src/index.d.ts": "3df00ff7e5f6dc9d2d6b944a88c2e541b098c0e559bd3a918732f3aa35acf1af", | ||||
|     "https://esm.sh/v113/preact@10.13.2/src/index.d.ts": "65398710de6aa0a07412da79784e05e6e96763f51c7c91b77344d2d0af06385c", | ||||
|     "https://esm.sh/v113/preact@10.13.2/src/jsx.d.ts": "9ac9b82c199fa7b04748807d750eba1a106c0be52041b8617416f88d6fc0a257", | ||||
|     "https://esm.sh/v115/@twind/core@1.1.3/es2022/core.mjs": "937e906c390266871215f71372af7fadf98274fb47670a7e1e8cf98e775357a8", | ||||
|     "https://esm.sh/v115/@twind/preset-autoprefix@1.0.7/es2022/preset-autoprefix.mjs": "082486172119c516f5daf83cd178175302455fab8ed550a3cb58630864f0c4e3", | ||||
|     "https://esm.sh/v115/@twind/preset-tailwind@1.1.4/es2022/preset-tailwind.mjs": "7c561cfa2c639b259c390d4412f88b2f0675431b995261f1a5ef0916f1b9b48b", | ||||
|     "https://esm.sh/v115/style-vendorizer@2.2.3/es2022/style-vendorizer.mjs": "b0f813226f7c4a30e1742087311243bbb021ef9b201e064932fce1122625b29e", | ||||
|     "https://esm.sh/v118/preact-ssr-prepass@1.2.0/deno/preact-ssr-prepass.mjs": "302a0da48c6fb2232c6f713f17957e409ec909ccb8f5a4074065eb0ca7553ee3", | ||||
|     "https://esm.sh/v118/preact-ssr-prepass@1.2.0/typings/index.d.ts": "68d54a22a76ef21fd95266ba4d8c71b3228d5e7769baf899998d5348018671c4", | ||||
|     "https://esm.sh/v118/preact@10.13.2/compat/src/index.d.ts": "d02f015638a40e32649151e011cfda7b520d66f7fbd3c12a28fa03de2a5e1421", | ||||
|     "https://esm.sh/v118/preact@10.13.2/compat/src/suspense-list.d.ts": "b8e274324392157ce476ef3a48ae215c9f7003b08525d140645f19eab20d1948", | ||||
|     "https://esm.sh/v118/preact@10.13.2/compat/src/suspense.d.ts": "81f5266e0977a94347505d11b8103024211f2b4f3b2eb2aa276a10d8fd169e65", | ||||
|     "https://esm.sh/v118/preact@10.13.2/hooks/src/index.d.ts": "5c29febb624fc25d71cb0e125848c9b711e233337a08f7eacfade38fd4c14cc3", | ||||
|     "https://esm.sh/v118/preact@10.13.2/src/index.d.ts": "65398710de6aa0a07412da79784e05e6e96763f51c7c91b77344d2d0af06385c", | ||||
|     "https://esm.sh/v118/preact@10.13.2/src/jsx.d.ts": "9ac9b82c199fa7b04748807d750eba1a106c0be52041b8617416f88d6fc0a257", | ||||
|     "https://esm.sh/v119/@twind/core@1.1.3/core.d.ts": "87836d90ff43c5bd5cbb53df7adbcad9d9515fae21f8a31d34203027b7d75d29", | ||||
|     "https://esm.sh/v119/@twind/core@1.1.3/deno/core.mjs": "9a65476bdc46aeb10894c4496fbfbc863e45ffebf43e58d6320017f847aca7b2", | ||||
|     "https://esm.sh/v119/csstype@3.1.2/index.d.ts": "4c68749a564a6facdf675416d75789ee5a557afda8960e0803cf6711fa569288" | ||||
|   } | ||||
| } | ||||
| @ -1,53 +1,29 @@ | ||||
| import React from "react"; | ||||
| import * as Iso from "@eno/iso"; | ||||
| 
 | ||||
| /* | ||||
| const delay =(inMS:number)=> | ||||
| { | ||||
|     return new Promise((accept)=> | ||||
|     { | ||||
|         setTimeout(()=> | ||||
|         { | ||||
|             accept({default:()=> | ||||
|             { | ||||
|                 return <h1>loooooool</h1>; | ||||
|             }}); | ||||
|         }, inMS); | ||||
|     }); | ||||
| } | ||||
| const LOL = React.lazy(()=>delay(3000)); | ||||
| */ | ||||
| 
 | ||||
| const Comp = React.lazy(()=>import("./deep/component.tsx")); | ||||
| 
 | ||||
| 
 | ||||
| export default ()=> | ||||
| { | ||||
| 
 | ||||
|     const [stack] = React.useContext(Iso.Meta.Context); | ||||
| 
 | ||||
| Iso.Boot( | ||||
|     ()=> | ||||
|     { | ||||
|         return <div class="p-4 font-sans"> | ||||
|         <Iso.Meta.Metas title="Main Page!" description="its great"/> | ||||
|             <Iso.Meta.Metas title="Main Page!"/> | ||||
|             <nav class="p-4"> | ||||
|                 <a class="text-red-500" href="/">Home</a> | ||||
|                 <a href="/about">About</a> | ||||
|             </nav> | ||||
|      | ||||
|         <h1 class="my-2 font(bold serif) text(3xl)">Title!!</h1> | ||||
|             <h1 class="my-2 font(bold serif) text(3xl)">Title!!!!!!</h1> | ||||
|             <h2>suspended:</h2> | ||||
|             <React.Suspense fallback={<div>Loading!</div>}> | ||||
|                 <Comp/> | ||||
|             </React.Suspense> | ||||
|             <Iso.Switch> | ||||
|             <Iso.Case value="/"> | ||||
|                 <p>thing1</p> | ||||
|                 <p>thing2</p> | ||||
|             </Iso.Case> | ||||
|                 <Iso.Case value="page"> | ||||
|                     <Iso.Switch> | ||||
|                         <Iso.Case value="about-us"> | ||||
|                             <> | ||||
|                             <Iso.Meta.Metas title="About US" concatListed=" | "/> | ||||
|                                 <Iso.Meta.Metas title="About US"/> | ||||
|                                 About us! | ||||
|                             </> | ||||
|                         </Iso.Case> | ||||
| @ -55,12 +31,8 @@ export default ()=> | ||||
|                     </Iso.Switch> | ||||
|                 </Iso.Case> | ||||
|                 <Iso.Case value="lol/idk">lol/idk</Iso.Case> | ||||
|             <Iso.Case default> | ||||
|                 <> | ||||
|                     <Iso.Meta.Metas description="a 404 has occurred"/> | ||||
|                     <p>404!</p> | ||||
|                 </> | ||||
|             </Iso.Case> | ||||
|                 <Iso.Case default><p>404!</p></Iso.Case> | ||||
|             </Iso.Switch> | ||||
|         </div>; | ||||
| }; | ||||
|     } | ||||
| ); | ||||
| @ -13,7 +13,7 @@ export default ()=> | ||||
|     console.log("component.tsx render!!") | ||||
| 
 | ||||
|     return <div class="p-4 text-red-500"> | ||||
|         <Iso.Meta.Metas title="Component!" description="components can set metas"/> | ||||
|         <Iso.Meta.Metas title="Component!"/> | ||||
|         Component Route is: {routeGet.Path.toString()} | ||||
|         <button className="p-4 bg-green-500 text-white" onClick={e=>{countSet(countGet+1); routeSet(["lol", "idk"], {count:countGet+1});}}>{countGet}</button> | ||||
|         <a href="/page/about-us" className="p-2 text(lg blue-500) font-bold">a link</a> | ||||
|  | ||||
| @ -3,11 +3,11 @@ | ||||
|     "imports": | ||||
|     { | ||||
|         "react": "https://esm.sh/stable/preact@10.13.2/compat", | ||||
|         "@eno/app": "./app.tsx", | ||||
|         "preact": "https://esm.sh/stable/preact@10.13.2/", | ||||
|         "@deep/": "./deep/", | ||||
|         "@eno/iso": "http://localhost:4507/lib/iso.tsx" | ||||
|     }, | ||||
|     "tasks": { | ||||
|         "dev": "deno run -A --unstable --reload=http://localhost:4507/ --no-lock app.tsx --dev", | ||||
|         "run": "deno run -A --unstable --reload=http://localhost:4507/ --no-lock app.tsx" | ||||
|         "dev": "deno run -A --unstable --reload=http://localhost:4507/ --no-lock app.tsx" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										30
									
								
								lib/boot-client.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/boot-client.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| import React, {hydrate} from "react"; | ||||
| import * as Twind from "https://esm.sh/v115/@twind/core@1.1.3/es2022/core.mjs"; | ||||
| import {Router, CSS, Meta} from "@eno/iso"; | ||||
| 
 | ||||
| export function Boot(inApp:()=>React.JSX.Element, inCSS?:object) | ||||
| { | ||||
|     console.log(inApp, inCSS); | ||||
|     Twind.install(inCSS ? {...CSS, ...inCSS} : CSS); | ||||
| 
 | ||||
|     const HMRWrap =()=> React.createElement(inApp, null, null); | ||||
| 
 | ||||
|     const root = document.querySelector("#app"); | ||||
| 
 | ||||
|     if(root) | ||||
|     { | ||||
|         hydrate( | ||||
|             <Router.Provider url={new URL(window.location.href)}> | ||||
|                 <Meta.Provider> | ||||
|                     <HMRWrap/> | ||||
|                 </Meta.Provider> | ||||
|             </Router.Provider>, | ||||
|             root | ||||
|         ); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         console.log(`no "#app" element is present!`) | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| @ -1,8 +1,7 @@ | ||||
| 
 | ||||
| let reloads = 0; | ||||
| const listeners = new Map() as Map<string, Array<(module:unknown)=>void>>; | ||||
| const socket:WebSocket = new WebSocket("ws://"+document.location.host); | ||||
| socket.addEventListener('message', (event) => | ||||
| new WebSocket("ws://"+document.location.host).addEventListener('message', (event) => | ||||
| { | ||||
|     let handlers = listeners.get(event.data)??[]; | ||||
|     reloads++; | ||||
| @ -14,7 +13,6 @@ socket.addEventListener('message', (event) => | ||||
|         }) | ||||
|     ).then(()=>HMR.update()); | ||||
| }); | ||||
| const socketTimer = setInterval(()=>{socket.send("ping")}, 1000); | ||||
| 
 | ||||
| export const FileListen =(inPath:string, inHandler:()=>void)=> | ||||
| { | ||||
|  | ||||
							
								
								
									
										98
									
								
								lib/iso.tsx
									
									
									
									
									
								
							
							
						
						
									
										98
									
								
								lib/iso.tsx
									
									
									
									
									
								
							| @ -1,26 +1,29 @@ | ||||
| import TWPreTail from "https://esm.sh/v115/@twind/preset-tailwind@1.1.4/es2022/preset-tailwind.mjs"; | ||||
| import TWPreAuto from "https://esm.sh/v115/@twind/preset-autoprefix@1.0.7/es2022/preset-autoprefix.mjs"; | ||||
| import React, { JSX } from "react"; | ||||
| import React from "react"; | ||||
| import { Boot as _Boot } from "../server.tsx"; | ||||
| 
 | ||||
| export const CSS = { | ||||
|     presets: [TWPreTail(), TWPreAuto()], | ||||
|     hash:false | ||||
| }; | ||||
| 
 | ||||
| if(!window.innerWidth && !Deno.mainModule.endsWith("server.tsx")) | ||||
| 
 | ||||
| export function Boot(inApp:React.FunctionComponent, inCSS?:object) | ||||
| { | ||||
|     import(import.meta.resolve("../../server.tsx")).then(()=>{console.log("...imported!");}); | ||||
|     _Boot(inApp, inCSS); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| type MetasInputs = { [Property in MetaKeys]?: string }; | ||||
| type MetasModeArgs = {concatListed?:string; dropUnlisted?:boolean}; | ||||
| type MetasModeArgs = {concatListed?:boolean; dropUnlisted?:boolean}; | ||||
| type MetasStackItem = MetasModeArgs&MetasInputs&{id:string, depth:number} | ||||
| type Meta = {title:string, description:string, keywords:string, image:string, canonical:string } | ||||
| type MetaKeys = keyof Meta; | ||||
| 
 | ||||
| export const Meta = | ||||
| { | ||||
|     Stack:[] as MetasStackItem[], | ||||
|     Stack:[] as Array<MetasStackItem>, | ||||
|     Meta: { | ||||
|         title:"", | ||||
|         description:"", | ||||
| @ -28,83 +31,20 @@ export const Meta = | ||||
|         image:"", | ||||
|         canonical:"" | ||||
|     } as Meta, | ||||
|     ComputeFinal(inStack:MetasStackItem[], inStart=0) | ||||
|     { | ||||
|         const seed = { | ||||
|             title:"", | ||||
|             description:"", | ||||
|             keywords:"", | ||||
|             image:"", | ||||
|             canonical:"" | ||||
|         }; | ||||
|         if(inStack.length>0) | ||||
|         { | ||||
|             let final = {...seed, ...inStack[0]}; | ||||
|             for(let i=inStart+1; i<inStack.length; i++) | ||||
|             { | ||||
|                 const curr = inStack[i]; | ||||
|                 Object.keys(seed).forEach(key=> | ||||
|                 { | ||||
|                     const lookup = key as MetaKeys | ||||
|                     const valPrev = final[lookup]; | ||||
|                     const valCurr = curr[lookup]; | ||||
| 
 | ||||
|                     if(valPrev && !valCurr) | ||||
|                     { | ||||
|                         final[lookup] = curr.dropUnlisted ? "" : valPrev; | ||||
|                     } | ||||
|                     else if(valPrev && valCurr) | ||||
|                     { | ||||
|                         final[lookup] = curr.concatListed ? valPrev + curr.concatListed + valCurr : valCurr | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         final[lookup] = valCurr||""; | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|             return final; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return seed; | ||||
|         } | ||||
|     }, | ||||
|     Context: React.createContext([[], ()=>{}] as [Get:MetasStackItem[], Set:React.StateUpdater<MetasStackItem[]>]), | ||||
|     Provider({children}:{children:Children}) | ||||
|     { | ||||
|         const binding = React.useState([] as MetasStackItem[]); | ||||
|          | ||||
|         type MetaDOM = {description:NodeListOf<Element>, title:NodeListOf<Element>, image:NodeListOf<Element>, url:NodeListOf<Element>}; | ||||
| 
 | ||||
|         const refElements = React.useRef(null as null | MetaDOM); | ||||
| 
 | ||||
|         React.useEffect(()=> | ||||
|         { | ||||
|             refElements.current = { | ||||
|                 description:document.querySelectorAll(`head > meta[name$='description']`), | ||||
|                 title:document.querySelectorAll(`head > meta[name$='title']`), | ||||
|                 image:document.querySelectorAll(`head > meta[name$='image']`), | ||||
|                 url:document.querySelectorAll(`head > link[rel='canonical']`) | ||||
|             }; | ||||
|         }, []); | ||||
| 
 | ||||
|         React.useEffect(()=> | ||||
|         { | ||||
|             if(refElements.current) | ||||
|             { | ||||
|                 const final = Meta.ComputeFinal(binding[0]); | ||||
| 
 | ||||
|                 refElements.current.url.forEach(e=>e.setAttribute("content", final.canonical||"")); | ||||
|                 document.title = final.title; | ||||
|                 refElements.current.title.forEach(e=>e.setAttribute("content", final.title||"")); | ||||
|                 refElements.current.image.forEach(e=>e.setAttribute("content", final.image||"")); | ||||
|                 refElements.current.description.forEach(e=>e.setAttribute("content", final.description||"")); | ||||
|             } | ||||
|         }); | ||||
|         React.useEffect(()=>{ | ||||
|             const stack = binding[0]; | ||||
|             const last = stack[stack.length-1]; | ||||
|             console.log("updating page title", stack); | ||||
|             document.title = last?.title||""; | ||||
|         }) | ||||
|         return <Meta.Context.Provider value={binding}>{children}</Meta.Context.Provider>; | ||||
|     }, | ||||
|     Metas({concatListed=undefined, dropUnlisted=false, ...props}:MetasModeArgs&MetasInputs):null | ||||
|     Metas({concatListed=false, dropUnlisted=false, ...props}:MetasModeArgs&MetasInputs):null | ||||
|     { | ||||
|         const id = React.useId(); | ||||
|         const [, metasSet] = React.useContext(Meta.Context); | ||||
| @ -119,6 +59,7 @@ export const Meta = | ||||
|                 { | ||||
|                     if(clone[i].depth <= depth) | ||||
|                     { | ||||
|                          | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
| @ -154,11 +95,6 @@ export const Meta = | ||||
|             }); | ||||
|         }, Object.keys(props).map( (key) => props[key as MetaKeys] )); | ||||
| 
 | ||||
|         if(!window.innerWidth && props.title) | ||||
|         { | ||||
|             Meta.Stack.push({id, depth, concatListed, dropUnlisted, ...props}); | ||||
|         } | ||||
| 
 | ||||
|         return null; | ||||
|     } | ||||
| }; | ||||
| @ -280,7 +216,7 @@ export const Switch =({children}:{children:Children})=> | ||||
|         for(let i=0; i<children.length; i++) | ||||
|         { | ||||
|             const childCase =  children[i]; | ||||
|             const childCaseChildren = childCase.props?.__args?.slice(2) || childCase.props.children; | ||||
|             const childCaseChildren = childCase.props?.__args?.[2] || childCase.props.children; | ||||
|             const newContextValue = checkChild(childCase); | ||||
|             if(newContextValue) | ||||
|             { | ||||
|  | ||||
							
								
								
									
										0
									
								
								lib/mid.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								lib/mid.tsx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										148
									
								
								server.tsx
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								server.tsx
									
									
									
									
									
								
							| @ -2,14 +2,13 @@ import * as ESBuild from 'https://deno.land/x/esbuild@v0.17.4/mod.js'; | ||||
| import * as MIME from "https://deno.land/std@0.180.0/media_types/mod.ts"; | ||||
| import { debounce } from "https://deno.land/std@0.151.0/async/debounce.ts"; | ||||
| import { parse as JSONC} from "https://deno.land/std@0.185.0/jsonc/mod.ts"; | ||||
| import { toFileUrl } from "https://deno.land/std@0.185.0/path/mod.ts"; | ||||
| import SSR from "https://esm.sh/v113/preact-render-to-string@6.0.2"; | ||||
| import Prepass from "https://esm.sh/preact-ssr-prepass@1.2.0"; | ||||
| import * as Twind from "https://esm.sh/@twind/core@1.1.3"; | ||||
| import React from "react"; | ||||
| import * as Iso from "@eno/iso"; | ||||
| 
 | ||||
| Deno.env.set("initialized", "true"); | ||||
| 
 | ||||
| /** | ||||
|  * Setup a transpiler. | ||||
|  * @param inDevMode When true, starts a file-watcher | ||||
| @ -89,7 +88,6 @@ function Transpiler(inDevMode:boolean) | ||||
|     : | ||||
|     ()=>false; | ||||
| 
 | ||||
|     let reloads = 0; | ||||
|     const watcher =async()=> | ||||
|     { | ||||
|         const FilesChanged:Map<string, string> = new Map(); | ||||
| @ -100,13 +98,6 @@ function Transpiler(inDevMode:boolean) | ||||
|                 const key = path.substring(Deno.cwd().length).replaceAll("\\", "/"); | ||||
|                 if(action != "remove") | ||||
|                 { | ||||
|                     if(Imports?.imports) | ||||
|                     { | ||||
|                         reloads++; | ||||
|                         const importApp = Imports.imports["@eno/app"]; | ||||
|                         const imp = await import(Path.Active+importApp+"?reloads="+reloads); | ||||
|                         App = imp.default; | ||||
|                     } | ||||
|                     await TranspileURL(Path.Active+key, key, false); | ||||
|                     SocketsBroadcast(key); | ||||
|                 } | ||||
| @ -142,6 +133,7 @@ function Transpiler(inDevMode:boolean) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| type ImportMap = {imports?:Record<string, string>, importMap?:string}; | ||||
| /** | ||||
|  * Extract all configuration info form a project's deno.jsonc file | ||||
|  * @param inDevMode When true, proxies react to an HMR-enabled version | ||||
| @ -150,8 +142,7 @@ function Transpiler(inDevMode:boolean) | ||||
|  */ | ||||
| async function Configure(inDevMode:boolean, inLibPath:string) | ||||
| { | ||||
|     type ImportMap = {imports?:Record<string, string>, importMap?:string}; | ||||
|     const output:{Imports?:ImportMap, App?:React.FunctionComponent, TwindInst?:Twind.Twind, Error?:string} = {}; | ||||
|     const output:{Imports?:ImportMap, Error?:string} = {}; | ||||
|     let ImportObject:ImportMap = {}; | ||||
|     try | ||||
|     { | ||||
| @ -212,52 +203,6 @@ async function Configure(inDevMode:boolean, inLibPath:string) | ||||
|                 return output; | ||||
|             } | ||||
|      | ||||
|             const importApp = output.Imports.imports["@eno/app"]; | ||||
|             if(importApp) | ||||
|             { | ||||
|                 let appImport  | ||||
|                 try | ||||
|                 { | ||||
|                     appImport = await import(Path.Active+importApp); | ||||
|                 } | ||||
|                 catch(e) | ||||
|                 { | ||||
|                     output.Error = `"@eno/app" entry-point (${importApp}) file not found`; | ||||
|                     return output; | ||||
|                 } | ||||
|                  | ||||
|                 if(typeof appImport.default == "function" ) | ||||
|                 { | ||||
|                     output.App = appImport.default; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     output.Error = `"@eno/app" entry-point (${importApp}) needs to export a default function to use as the app root.`; | ||||
|                     return output; | ||||
|                 } | ||||
|      | ||||
|                 let twindConfig = Iso.CSS; | ||||
|                 if(typeof appImport.CSS == "object") | ||||
|                 { | ||||
|                     twindConfig = {...twindConfig, ...appImport.CSS}; | ||||
|                 } | ||||
|                 try | ||||
|                 { | ||||
|                     // @ts-ignore
 | ||||
|                     output.TwindInst = Twind.install(twindConfig); | ||||
|                 } | ||||
|                 catch(e) | ||||
|                 { | ||||
|                     output.Error = `CSS configuration is malformed`; | ||||
|                     return output; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 output.Error = `"imports" configuration does not alias an entry-point file as "@eno/app"`; | ||||
|                 return output; | ||||
|             } | ||||
|              | ||||
|      | ||||
|             Object.entries(output.Imports.imports).forEach(([key, value])=>{ | ||||
|                 if(value.startsWith("./") && output.Imports?.imports) | ||||
| @ -280,37 +225,60 @@ async function Configure(inDevMode:boolean, inLibPath:string) | ||||
|     return output; | ||||
| } | ||||
| 
 | ||||
| const Flags:Record<string, string|boolean> = {}; | ||||
| Deno.args.forEach(arg=> | ||||
| { | ||||
|     if(arg.startsWith("--")) | ||||
|     { | ||||
|         const kvp = arg.substring(2).split("="); | ||||
|         Flags[kvp[0]] = kvp[1] ? kvp[1] : true;  | ||||
|         Deno.env.set(kvp[0], kvp[1] ? kvp[1] : "true"); | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| let DevMode = Flags.dev ? true : false; | ||||
| let DevMode = Deno.env.get("dev") ? true : false; | ||||
| let hosted = import.meta.resolve("./"); | ||||
| const Path = { | ||||
|     Hosted: hosted.substring(0, hosted.length-1), | ||||
|     Active: `file://${Deno.cwd().replaceAll("\\", "/")}`, | ||||
|     LibDir: "lib" | ||||
|     LibDir: "lib", | ||||
|     AppDir: "" | ||||
| }; | ||||
| console.log(Path); | ||||
| console.log(`Dev Mode: ${DevMode}`); | ||||
| console.log(`Args seen: `, Flags); | ||||
| console.log(`Dev Mode:`, DevMode); | ||||
| console.log(`import.meta.url:`, import.meta.url); | ||||
| console.log(`Deno.cwd():`, Deno.cwd()); | ||||
| console.log(`Deno.mainModule:`, Deno.mainModule); | ||||
| 
 | ||||
| const {Transpileable, TranspileURL, SocketsHandler} = Transpiler(DevMode); | ||||
| let {Imports, App, TwindInst, Error} = await Configure(DevMode, Path.LibDir); | ||||
| 
 | ||||
| if(Error) | ||||
| let Booted = false; | ||||
| let TwindInst:Twind.Twind; | ||||
| export function Boot(inApp:React.FunctionComponent, inCSS?:object) | ||||
| { | ||||
|     console.log(Error); | ||||
|     if(Booted){return;} | ||||
|     Booted = true; | ||||
| 
 | ||||
|     const pathInit = Deno.mainModule; | ||||
|     const pathProj = toFileUrl(Deno.cwd()); | ||||
|      | ||||
|     //@ts-ignore
 | ||||
|     TwindInst = Twind.install({...Iso.CSS, ...inCSS||{}}); | ||||
| 
 | ||||
|     const App = inApp; | ||||
|     Path.AppDir = pathInit.split(pathProj.toString())[1]; | ||||
| 
 | ||||
|     Server(App, Path.AppDir, TwindInst); | ||||
| } | ||||
| else if(App && TwindInst) | ||||
| 
 | ||||
| async function Server(App:React.FunctionComponent, AppPath:string, TwindInst:Twind.Twind) | ||||
| { | ||||
|     Deno.serve({ port: Flags?.port||3000 }, async(_req:Request) => | ||||
|     const {Transpileable, TranspileURL, SocketsHandler} = Transpiler(DevMode); | ||||
|     const {Imports, Error} = await Configure(DevMode, Path.LibDir); | ||||
|     if(Error) | ||||
|     { | ||||
|         console.log(Error); | ||||
|     } | ||||
|     else if(App && TwindInst) | ||||
|     { | ||||
|         Deno.serve({ port: Deno.env.get("port")||3000 }, async(_req:Request) => | ||||
|         { | ||||
|             const url:URL = new URL(_req.url); | ||||
|             const pathParts = url.pathname.substring(1, url.pathname.endsWith("/") ? url.pathname.length-1 : url.pathname.length).split("/"); | ||||
| @ -320,6 +288,8 @@ else if(App && TwindInst) | ||||
|             const resp = SocketsHandler(_req); | ||||
|             if(resp){ return resp; } | ||||
|          | ||||
|             console.log(url.pathname); | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 // serve index by default
 | ||||
| @ -335,6 +305,10 @@ else if(App && TwindInst) | ||||
|                     { | ||||
|                         body = await TranspileURL(Path.Hosted+url.pathname, url.pathname, true); | ||||
|                     } | ||||
|                     else if(url.pathname == "/server.tsx") | ||||
|                     { | ||||
|                         body = await TranspileURL(`${Path.Hosted}/${Path.LibDir}/boot-client.tsx`, url.pathname, true); | ||||
|                     } | ||||
|                     else if(DevMode && !url.searchParams.get("reload")) | ||||
|                     { | ||||
|                         const imp = await import(Path.Active+url.pathname); | ||||
| @ -371,9 +345,8 @@ else if(App && TwindInst) | ||||
|                     Iso.Fetch.ServerBlocking = []; | ||||
|                     Iso.Fetch.ServerTouched = new Set(); | ||||
|                     Iso.Fetch.ServerRemove = new Set(); | ||||
|                 let app = <Iso.Router.Provider url={url}><App/></Iso.Router.Provider>; | ||||
|                 await Prepass(app); | ||||
|                 Iso.Meta.Stack = []; | ||||
|                     let app = <Iso.Router.Provider url={url}><Iso.Meta.Provider><App/></Iso.Meta.Provider></Iso.Router.Provider>; | ||||
|                     await Prepass(app) | ||||
|                     let bake = SSR(app); | ||||
|                     while(Iso.Fetch.ServerBlocking.length) | ||||
|                     { | ||||
| @ -381,9 +354,8 @@ else if(App && TwindInst) | ||||
|                         Iso.Fetch.ServerBlocking = []; | ||||
|                         // at this point, anything that was requested that was not cached, has now been loaded and cached
 | ||||
|                         // this next render will use cached resources. using a cached resource (if its "Seed" is true) adds it to the "touched" set.
 | ||||
|                     app = <Iso.Router.Provider url={url}><App/></Iso.Router.Provider>; | ||||
|                     await Prepass(app); | ||||
|                     Iso.Meta.Stack = []; | ||||
|                         app = <Iso.Router.Provider url={url}><Iso.Meta.Provider><App/></Iso.Meta.Provider></Iso.Router.Provider>; | ||||
|                         await Prepass(app) | ||||
|                         bake = SSR(app); | ||||
|                     } | ||||
|          | ||||
| @ -395,7 +367,6 @@ else if(App && TwindInst) | ||||
|                     }); | ||||
|                     Iso.Fetch.ServerTouched = false; | ||||
|          | ||||
|                 Iso.Meta.Meta = Iso.Meta.ComputeFinal(Iso.Meta.Stack); | ||||
|                     const results = Twind.extract(bake, TwindInst); | ||||
|          | ||||
|                     type = `text/html`; | ||||
| @ -404,13 +375,6 @@ else if(App && TwindInst) | ||||
|         <html lang="en"> | ||||
|             <head> | ||||
|                 <title>${Iso.Meta.Meta.title}</title> | ||||
|             <meta property="og:title" content="${Iso.Meta.Meta.title}"> | ||||
|             <meta name="description" content="${Iso.Meta.Meta.description}"> | ||||
|             <meta property="og:description" content="${Iso.Meta.Meta.description}"> | ||||
|             <meta property="og:image" content="${Iso.Meta.Meta.image}"> | ||||
|             <meta property="og:url" content="${Iso.Meta.Meta.canonical}"> | ||||
|             <link rel="canonical" href="${Iso.Meta.Meta.canonical}" /> | ||||
| 
 | ||||
|                 <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|                 <meta charset="utf-8"/> | ||||
|                 <style data-twind>${results.css}</style> | ||||
| @ -419,19 +383,10 @@ else if(App && TwindInst) | ||||
|             <body> | ||||
|                 <div id="app">${results.html}</div> | ||||
|                 <script type="module"> | ||||
|                 import {hydrate, createElement as H} from "react"; | ||||
|                 import * as Twind from "https://esm.sh/v115/@twind/core@1.1.3/es2022/core.mjs"; | ||||
|                 import * as App from "@eno/app"; | ||||
|                 import {Router, Fetch, CSS, Meta} from "@eno/iso"; | ||||
|                 Twind.install(App.CSS ? {...CSS, ...App.CSS} : CSS); | ||||
|                     import {Fetch} from "@eno/iso"; | ||||
|                     Fetch.Seed(${JSON.stringify(seed)}); | ||||
|                 const hmrWrap = H( ()=>H(App.default) ); | ||||
|                 hydrate( | ||||
|                     H(Router.Provider, null, | ||||
|                         H(Meta.Provider, null, hmrWrap) | ||||
|                     ), | ||||
|                     document.querySelector("#app") | ||||
|                 ); | ||||
| 
 | ||||
|                     import "${AppPath}"; | ||||
|                 </script> | ||||
|             </body> | ||||
|         </html>`;
 | ||||
| @ -445,4 +400,5 @@ else if(App && TwindInst) | ||||
|                 return new Response(error, {status:404}); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user