diff --git a/client.tsx b/client.tsx deleted file mode 100644 index cdc75c1..0000000 --- a/client.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import * as HTTP from "https://deno.land/std@0.177.0/http/server.ts"; -import * as Transpile from "./xpile.tsx"; - -const dir = `file://${Deno.cwd().replaceAll("\\", "/")}`; - -const Sockets:Set = new Set(); -const SocketsBroadcast =(inData:string)=>{ console.log(inData); for (const socket of Sockets){ socket.send(inData); } } -const SocketsHandler = (_req:Request)=> -{ - if(_req.headers.get("upgrade") == "websocket") - { - try - { - const { response, socket } = Deno.upgradeWebSocket(_req); - socket.onopen = () => Sockets.add(socket); - socket.onclose = () => Sockets.delete(socket); - socket.onmessage = (e) => {}; - socket.onerror = (e) => console.log("Socket errored:", e); - return response; - } - catch(e) - { - // - return new Response(e); - } - } - return new Response(`websockets only`); -}; - -HTTP.serve(SocketsHandler, { port: 4444 }); - -const watcher =async()=> -{ - let blocking = false; - const filesChanged:Map = new Map(); - for await (const event of Deno.watchFs(Deno.cwd())) - { - event.paths.forEach( path => filesChanged.set(path, event.kind) ); - if(!blocking) - { - blocking = true; - setTimeout(async()=> - { - for await (const [path, action] of filesChanged) - { - const key = path.substring(Deno.cwd().length).replaceAll("\\", "/"); - if(action != "remove") - { - await Transpile.Fetch(dir+key, key, true); - SocketsBroadcast(key); - } - else - { - Transpile.Cache.delete(key); - } - } - filesChanged.clear(); - blocking = false; - } - , 1000); - } - } -} -watcher().then(()=>console.log("done watching")); \ No newline at end of file diff --git a/local.tsx b/local.tsx new file mode 100644 index 0000000..a6bf756 --- /dev/null +++ b/local.tsx @@ -0,0 +1,59 @@ +import * as HTTP from "https://deno.land/std@0.177.0/http/server.ts"; +import Setup, {Transpile} from "./serve.tsx"; + +const Directory = `file://${Deno.cwd().replaceAll("\\", "/")}`; +Transpile.Config.sourceMaps = "inline"; +Setup({Proxy:Directory}); + +const SocketsLive:Set = new Set(); +const SocketsSend =(inData:string)=>{ console.log(inData); for (const socket of SocketsLive){ socket.send(inData); } } +HTTP.serve((_req:Request)=> +{ + if(_req.headers.get("upgrade") == "websocket") + { + try + { + const { response, socket } = Deno.upgradeWebSocket(_req); + socket.onopen = () => SocketsLive.add(socket); + socket.onclose = () => SocketsLive.delete(socket); + socket.onmessage = (e) => {}; + socket.onerror = (e) => console.log("Socket errored:", e); + return response; + } + catch(e) + { + return new Response(e); + } + } + return new Response(`websockets only`); +}, { port: 4444 }); + +let blocking = false; +const filesChanged:Map = new Map(); +for await (const event of Deno.watchFs(Deno.cwd())) +{ + event.paths.forEach( path => filesChanged.set(path, event.kind) ); + if(!blocking) + { + blocking = true; + setTimeout(async()=> + { + for await (const [path, action] of filesChanged) + { + const key = path.substring(Deno.cwd().length).replaceAll("\\", "/"); + if(action != "remove") + { + const tsx = await Transpile.Fetch(Directory+key, key, true); + tsx && SocketsSend(key); + } + else + { + Transpile.Cache.delete(key); + } + } + filesChanged.clear(); + blocking = false; + } + , 1000); + } +} diff --git a/serve.tsx b/serve.tsx index fea1461..ab5fc68 100644 --- a/serve.tsx +++ b/serve.tsx @@ -1,20 +1,85 @@ import * as MIME from "https://deno.land/std@0.180.0/media_types/mod.ts"; import * as HTTP from "https://deno.land/std@0.177.0/http/server.ts"; -import * as Transpile from "./xpile.tsx"; +import * as SWCW from "https://esm.sh/@swc/wasm-web@1.3.62"; -type Configuration = {Proxy:string, Allow:string, Reset:string, Local:boolean}; -type ConfigurationArgs = {Proxy?:string, Allow?:string, Reset?:string, Local?:boolean}; - -let Configure:Configuration = +export type Configuration = {Proxy:string, Allow:string, Reset:string, Local:boolean}; +export type ConfigurationArgs = {Proxy?:string, Allow?:string, Reset?:string, Local?:boolean}; +export let Configure:Configuration = { Proxy: "", Allow: "*", Reset: "/clear-cache", Local: false }; + export default (config:ConfigurationArgs)=> Configure = {...Configure, ...config}; +export const Transpile = { + Config: + { + sourceMaps: false, + minify: true, + jsc: + { + target:"es2017", + minify: + { + compress: { unused: true }, + mangle: true + }, + parser: + { + syntax: "typescript", + tsx: true, + }, + transform: + { + react: { runtime: "automatic" } + } + }, + } as SWCW.Options, + Cache: new Map() as Map, + Clear() + { + const size = this.Cache.size; + this.Cache.clear(); + return size; + }, + Fetch: async function(inPath:string, inKey:string, inCheckCache=true) + { + console.log("transpile", inPath) + if(inPath.endsWith(".tsx") || inPath.endsWith(".jsx") || inPath.endsWith(".js") || inPath.endsWith(".mjs")) + { + const check = this.Cache.get(inPath); + if(check && inCheckCache) + { + return check; + } + else + { + try + { + const resp = await fetch(inPath); + const text = await resp.text(); + const {code} = await SWCW.transform(text, {...this.Config, filename:inKey}); + this.Cache.set(inKey, code); + return code; + } + catch(e) + { + console.log(`xpile.tsx error. Key:${inKey} Path:${inPath} Error:"${e}"`); + return null; + } + } + } + else + { + return false; + } + } +}; - +SWCW.default(); +console.log("starting server"); HTTP.serve(async(req: Request)=> { const url:URL = new URL(req.url); @@ -24,7 +89,7 @@ HTTP.serve(async(req: Request)=> return new Response(`cache cleared (${Transpile.Clear()} items)`); } - const lookup = await Transpile.Fetch(Configure.Proxy + url.pathname); + const lookup = await Transpile.Fetch(Configure.Proxy + url.pathname, url.pathname); if(lookup === null) { // error @@ -33,10 +98,17 @@ HTTP.serve(async(req: Request)=> else if(lookup === false) { // not a javascript file - const type = MIME.typeByExtension(url.pathname.substring(url.pathname.lastIndexOf("."))) || "text/html"; - const file = await fetch(Configure.Proxy + url.pathname); - const text = await file.text(); - return new Response(text, {headers:{"content-type":type, "Access-Control-Allow-Origin":Configure.Allow, charset:"utf-8"}}); + try + { + const type = MIME.typeByExtension(url.pathname.substring(url.pathname.lastIndexOf("."))) || "text/html"; + const file = await fetch(Configure.Proxy + url.pathname); + const text = await file.text(); + return new Response(text, {headers:{"content-type":type, "Access-Control-Allow-Origin":Configure.Allow, charset:"utf-8"}}); + } + catch(e) + { + return new Response(`404 ${Configure.Proxy + url.pathname}`, {status:404}); + } } else { diff --git a/xpile.tsx b/xpile.tsx deleted file mode 100644 index 1ec85da..0000000 --- a/xpile.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import * as SWCW from "https://esm.sh/@swc/wasm-web@1.3.62"; - -await SWCW.default(); - -export const Config:SWCW.Options = -{ - sourceMaps: false, - minify: true, - jsc: - { - minify: - { - compress: { unused: true }, - mangle: true - }, - parser: - { - syntax: "typescript", - tsx: true, - }, - transform: - { - react: { runtime: "automatic" } - } - }, -} -export const Cache:Map = new Map(); -export const Clear =()=> -{ - const size = Cache.size; - Cache.clear(); - return size; -}; -export const Fetch =async(inPath:string, inKey:string, inCheckCache=true)=> -{ - if(inPath.endsWith(".tsx") || inPath.endsWith(".jsx") || inPath.endsWith(".js") || inPath.endsWith(".mjs")) - { - const check = Cache.get(inPath); - if(check && inCheckCache) - { - return check; - } - else - { - - try - { - const resp = await fetch(inPath); - const text = await resp.text(); - const {code} = await SWCW.transform(text, Config); - Cache.set(inKey, code); - return code; - } - catch(e) - { - console.log(`xpile.tsx error. Key:${inKey} Path:${inPath} Error:"${e}"`); - return null; - } - } - } - else - { - return false; - } -}; \ No newline at end of file