diff --git a/deno.json b/deno.json
index 14eb980..1cd8ff9 100644
--- a/deno.json
+++ b/deno.json
@@ -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":
diff --git a/deno.lock b/deno.lock
deleted file mode 100644
index b8e174d..0000000
--- a/deno.lock
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "version": "2",
- "remote": {
- "http://localhost:4507/lib/iso.tsx": "edf1cf4c539900040c75824eac8472e0ec43098b13af4049bd79ddbd76a5346d",
- "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/v116/preact@10.13.2/compat/src/index.d.ts": "d02f015638a40e32649151e011cfda7b520d66f7fbd3c12a28fa03de2a5e1421",
- "https://esm.sh/v116/preact@10.13.2/compat/src/suspense-list.d.ts": "b8e274324392157ce476ef3a48ae215c9f7003b08525d140645f19eab20d1948",
- "https://esm.sh/v116/preact@10.13.2/compat/src/suspense.d.ts": "81f5266e0977a94347505d11b8103024211f2b4f3b2eb2aa276a10d8fd169e65",
- "https://esm.sh/v116/preact@10.13.2/hooks/src/index.d.ts": "5c29febb624fc25d71cb0e125848c9b711e233337a08f7eacfade38fd4c14cc3",
- "https://esm.sh/v116/preact@10.13.2/src/index.d.ts": "65398710de6aa0a07412da79784e05e6e96763f51c7c91b77344d2d0af06385c",
- "https://esm.sh/v116/preact@10.13.2/src/jsx.d.ts": "9ac9b82c199fa7b04748807d750eba1a106c0be52041b8617416f88d6fc0a257"
- }
-}
diff --git a/example/app.tsx b/example/app.tsx
index 8a7cd9e..da58b1d 100644
--- a/example/app.tsx
+++ b/example/app.tsx
@@ -3,34 +3,36 @@ import * as Iso from "@eno/iso";
const Comp = React.lazy(()=>import("./deep/component.tsx"));
-export default ()=>
-{
- return
-
-
-
-
Title!!
-
suspended:
-
Loading! }>
-
-
-
-
-
-
- <>
-
- About us!
- >
-
- sorry no page
-
-
- lol/idk
- 404!
-
- ;
-};
\ No newline at end of file
+Iso.Boot(
+ ()=>
+ {
+ return
+
+
+
+
Title!!!!!!
+
suspended:
+
Loading! }>
+
+
+
+
+
+
+ <>
+
+ About us!
+ >
+
+ sorry no page
+
+
+ lol/idk
+ 404!
+
+ ;
+ }
+);
\ No newline at end of file
diff --git a/example/deno.jsonc b/example/deno.jsonc
index 2c2f6e0..521187d 100644
--- a/example/deno.jsonc
+++ b/example/deno.jsonc
@@ -5,10 +5,9 @@
"react": "https://esm.sh/stable/preact@10.13.2/compat",
"preact": "https://esm.sh/stable/preact@10.13.2/",
"@deep/": "./deep/",
- "@eno/app": "./app.tsx",
"@eno/iso": "http://localhost:4507/lib/iso.tsx"
},
"tasks": {
- "dev": "deno run -A --unstable --reload=http://localhost:4507/ --no-lock app.tsx --dev"
+ "dev": "deno run -A --unstable --reload=http://localhost:4507/ --no-lock app.tsx"
}
}
\ No newline at end of file
diff --git a/fetch.test.tsx b/fetch.test.tsx
deleted file mode 100644
index 1a16c21..0000000
--- a/fetch.test.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import {Fetch} from "./lib/iso.tsx";
-
-
-const delay =async(inHandler:()=>void, inDelay:number):Promise=>
-{
- return new Promise((accept)=>{
- setTimeout(()=>{
- accept(inHandler());
- }, inDelay);
- });
-};
-
-const queue = [1, 2, 3];
-while(queue.length)
-{
- await(delay(()=>{console.log(queue.pop())}, 1000))
-}
-
-console.log("all done!");
-
-/*
-let r1, r2, r3;
-
-delay(()=>{r1 = Fetch.Request(`https://catfact.ninja/fact`, undefined, 0.2); console.log(r1); }, 10);
-delay(()=>{r2 = Fetch.Request(`https://catfact.ninja/fact`, undefined, 0.2); console.log(r2); }, 20);
-delay(()=>{r3 = Fetch.Request(`https://catfact.ninja/fact`, undefined, 0.2); console.log(r3); }, 2000);
-
-
-await delay(()=>{}, 3000);
-
-console.log(r1);
-console.log(r2);
-console.log(r3);
-
-*/
\ No newline at end of file
diff --git a/lib/boot-client.tsx b/lib/boot-client.tsx
new file mode 100644
index 0000000..6eb1f15
--- /dev/null
+++ b/lib/boot-client.tsx
@@ -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(
+
+
+
+
+ ,
+ root
+ );
+ }
+ else
+ {
+ console.log(`no "#app" element is present!`)
+ }
+
+};
\ No newline at end of file
diff --git a/lib/iso.tsx b/lib/iso.tsx
index 42b621b..4747787 100644
--- a/lib/iso.tsx
+++ b/lib/iso.tsx
@@ -1,17 +1,20 @@
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 from "react";
+import { Boot as _Boot } from "../server.tsx";
export const CSS = {
presets: [TWPreTail(), TWPreAuto()],
hash:false
};
-if(!window.innerWidth)
+
+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?:boolean; dropUnlisted?:boolean};
type MetasStackItem = MetasModeArgs&MetasInputs&{id:string, depth:number}
diff --git a/lib/mid.tsx b/lib/mid.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/server.tsx b/server.tsx
index f912b27..0928e4d 100644
--- a/server.tsx
+++ b/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
@@ -134,6 +133,7 @@ function Transpiler(inDevMode:boolean)
}
+type ImportMap = {imports?:Record, importMap?:string};
/**
* Extract all configuration info form a project's deno.jsonc file
* @param inDevMode When true, proxies react to an HMR-enabled version
@@ -142,8 +142,7 @@ function Transpiler(inDevMode:boolean)
*/
async function Configure(inDevMode:boolean, inLibPath:string)
{
- type ImportMap = {imports?:Record, importMap?:string};
- const output:{Imports?:ImportMap, App?:React.FunctionComponent, TwindInst?:Twind.Twind, Error?:string} = {};
+ const output:{Imports?:ImportMap, Error?:string} = {};
let ImportObject:ImportMap = {};
try
{
@@ -204,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)
@@ -272,158 +225,180 @@ async function Configure(inDevMode:boolean, inLibPath:string)
return output;
}
-const Flags:Record = {};
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);
-const {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)
{
- const url:URL = new URL(_req.url);
- const pathParts = url.pathname.substring(1, url.pathname.endsWith("/") ? url.pathname.length-1 : url.pathname.length).split("/");
- const pathLast = pathParts.at(-1);
- const pathExt:string|undefined = pathLast?.split(".")[1];
-
- const resp = SocketsHandler(_req);
- if(resp){ return resp; }
-
- try
+ console.log(Error);
+ }
+ else if(App && TwindInst)
+ {
+ Deno.serve({ port: Deno.env.get("port")||3000 }, async(_req:Request) =>
{
- // serve index by default
- let type = `text/html`;
- let body:BodyInit = ``;
-
- const isLib = url.pathname.startsWith(`/${Path.LibDir}/`);
-
- if(Transpileable(url.pathname))
+ const url:URL = new URL(_req.url);
+ const pathParts = url.pathname.substring(1, url.pathname.endsWith("/") ? url.pathname.length-1 : url.pathname.length).split("/");
+ const pathLast = pathParts.at(-1);
+ const pathExt:string|undefined = pathLast?.split(".")[1];
+
+ const resp = SocketsHandler(_req);
+ if(resp){ return resp; }
+
+ console.log(url.pathname);
+
+ try
{
- type = `application/javascript`;
- if(isLib)
+ // serve index by default
+ let type = `text/html`;
+ let body:BodyInit = ``;
+
+ const isLib = url.pathname.startsWith(`/${Path.LibDir}/`);
+
+ if(Transpileable(url.pathname))
{
- body = await TranspileURL(Path.Hosted+url.pathname, url.pathname, true);
+ type = `application/javascript`;
+ if(isLib)
+ {
+ 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);
+ const members = [];
+ for( const key in imp ) { members.push(key); }
+ body =
+ `
+ import {FileListen} from "/${Path.LibDir}/hmr.tsx";
+ import * as Import from "${url.pathname}?reload=0";
+ ${ members.map(m=>`let proxy_${m} = Import.${m};
+ export { proxy_${m} as ${m} };
+ `).join(" ") }
+ const reloadHandler = (updatedModule)=>
+ {
+ ${ members.map(m=>`proxy_${m} = updatedModule.${m};`).join("\n") }
+ };
+ FileListen("${url.pathname}", reloadHandler);`;
+
+ }
+ else
+ {
+ body = await TranspileURL(Path.Active+url.pathname, url.pathname, true);
+ }
}
- else if(DevMode && !url.searchParams.get("reload"))
+ // serve static media
+ else if( pathExt )
{
- const imp = await import(Path.Active+url.pathname);
- const members = [];
- for( const key in imp ) { members.push(key); }
- body =
- `
- import {FileListen} from "/${Path.LibDir}/hmr.tsx";
- import * as Import from "${url.pathname}?reload=0";
- ${ members.map(m=>`let proxy_${m} = Import.${m};
- export { proxy_${m} as ${m} };
- `).join(" ") }
- const reloadHandler = (updatedModule)=>
- {
- ${ members.map(m=>`proxy_${m} = updatedModule.${m};`).join("\n") }
- };
- FileListen("${url.pathname}", reloadHandler);`;
-
+ type = MIME.typeByExtension(pathExt) || "text/html";
+ const _fetch = await fetch((Path.Active)+url.pathname);
+ body = await _fetch.text();
}
else
{
- body = await TranspileURL(Path.Active+url.pathname, url.pathname, true);
- }
- }
- // serve static media
- else if( pathExt )
- {
- type = MIME.typeByExtension(pathExt) || "text/html";
- const _fetch = await fetch((Path.Active)+url.pathname);
- body = await _fetch.text();
- }
- else
- {
- Iso.Fetch.ServerBlocking = [];
- Iso.Fetch.ServerTouched = new Set();
- Iso.Fetch.ServerRemove = new Set();
- let app = ;
- await Prepass(app)
- let bake = SSR(app);
- while(Iso.Fetch.ServerBlocking.length)
- {
- await Promise.all(Iso.Fetch.ServerBlocking);
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.Fetch.ServerTouched = new Set();
+ Iso.Fetch.ServerRemove = new Set();
+ let app = ;
await Prepass(app)
- bake = SSR(app);
+ let bake = SSR(app);
+ while(Iso.Fetch.ServerBlocking.length)
+ {
+ await Promise.all(Iso.Fetch.ServerBlocking);
+ 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 = ;
+ await Prepass(app)
+ bake = SSR(app);
+ }
+
+ const seed:Iso.FetchRecord[] = [];
+ Iso.Fetch.ServerTouched.forEach((record)=>{
+ const r:Iso.FetchRecord = {...record};
+ delete r.Promise;
+ seed.push(r);
+ });
+ Iso.Fetch.ServerTouched = false;
+
+ const results = Twind.extract(bake, TwindInst);
+
+ type = `text/html`;
+ body =
+ `
+
+
+ ${Iso.Meta.Meta.title}
+
+
+
+
+
+
+ ${results.html}
+
+
+ `;
}
-
- const seed:Iso.FetchRecord[] = [];
- Iso.Fetch.ServerTouched.forEach((record)=>{
- const r:Iso.FetchRecord = {...record};
- delete r.Promise;
- seed.push(r);
- });
- Iso.Fetch.ServerTouched = false;
-
- const results = Twind.extract(bake, TwindInst);
-
- type = `text/html`;
- body =
- `
-
-
- ${Iso.Meta.Meta.title}
-
-
-
-
-
-
- ${results.html}
-
-
- `;
+
+ return new Response(body, {headers:{"content-type":type as string, "Access-Control-Allow-Origin":"*", charset:"utf-8"}});
}
-
- return new Response(body, {headers:{"content-type":type as string, "Access-Control-Allow-Origin":"*", charset:"utf-8"}});
- }
- catch(error)
- {
- console.log(error);
- return new Response(error, {status:404});
- }
- });
-}
\ No newline at end of file
+ catch(error)
+ {
+ console.log(error);
+ return new Response(error, {status:404});
+ }
+ });
+ }
+}