From ea5be77bc9b1cfc1f5210322cc7160ee5bf67b20 Mon Sep 17 00:00:00 2001 From: Daniel Ledda Date: Thu, 31 Oct 2024 17:14:30 +0100 Subject: [PATCH] better --- deno.json | 2 +- deno.lock | 94 +++-------------------------------------------- deps.ts | 2 - main.ts | 6 +-- public/index.html | 2 +- transpile.ts | 57 ++++++++++++++++++++++++++++ transpileTs.ts | 80 ---------------------------------------- 7 files changed, 67 insertions(+), 176 deletions(-) create mode 100644 transpile.ts delete mode 100644 transpileTs.ts diff --git a/deno.json b/deno.json index cd54a7a..65b1e0d 100644 --- a/deno.json +++ b/deno.json @@ -2,13 +2,13 @@ "tasks": { "start": "deno --allow-read --allow-net --allow-env --allow-write --allow-run main.ts", "watch": "deno --watch --allow-read --allow-net --allow-env --allow-write --allow-run main.ts" + "install": "deno install --entrypoint deps.ts" }, "fmt": { "lineWidth": 120, "indentWidth": 4 }, "imports": { - "@stock3/koala": "npm:@stock3/koala@^15.3.8-esm.0", "vue": "npm:vue@^3.5.12", "vue/jsx-runtime": "npm:vue/jsx-runtime", "@/": "./app/" diff --git a/deno.lock b/deno.lock index c671d10..64aa545 100644 --- a/deno.lock +++ b/deno.lock @@ -4,29 +4,21 @@ "jsr:@deno/cache-dir@0.13.2": "0.13.2", "jsr:@deno/emit@*": "0.46.0", "jsr:@deno/graph@~0.73.1": "0.73.1", - "jsr:@luca/esbuild-deno-loader@0.11": "0.11.0", "jsr:@std/assert@0.223": "0.223.0", "jsr:@std/bytes@0.223": "0.223.0", - "jsr:@std/bytes@^1.0.2": "1.0.2", "jsr:@std/cli@^1.0.6": "1.0.6", "jsr:@std/encoding@^1.0.5": "1.0.5", "jsr:@std/fmt@0.223": "0.223.0", "jsr:@std/fmt@^1.0.3": "1.0.3", - "jsr:@std/fs@*": "1.0.5", "jsr:@std/fs@0.223": "0.223.0", "jsr:@std/http@*": "1.0.9", "jsr:@std/io@0.223": "0.223.0", - "jsr:@std/media-types@*": "1.0.3", "jsr:@std/media-types@^1.0.3": "1.0.3", "jsr:@std/net@^1.0.4": "1.0.4", "jsr:@std/path@0.223": "0.223.0", - "jsr:@std/path@^1.0.6": "1.0.7", "jsr:@std/path@^1.0.7": "1.0.7", "jsr:@std/streams@^1.0.7": "1.0.7", - "npm:@stock3/koala@^15.3.8-esm.0": "15.3.8-esm.0_@stock3+auth-js@4.2.3_bg-auth-legacy@2.5.0_bg-status-js@2.4.3_flora-client-js@0.5.3_m-gate@2.12.8_vue@3.5.12_vue-router@4.4.5__vue@3.5.12", - "npm:@types/node@*": "22.5.4", "npm:vue@*": "3.5.12", - "npm:vue@3.5.12": "3.5.12", "npm:vue@^3.5.12": "3.5.12" }, "jsr": { @@ -35,7 +27,7 @@ "dependencies": [ "jsr:@deno/graph", "jsr:@std/fmt@0.223", - "jsr:@std/fs@0.223", + "jsr:@std/fs", "jsr:@std/io", "jsr:@std/path@0.223" ] @@ -50,23 +42,12 @@ "@deno/graph@0.73.1": { "integrity": "cd69639d2709d479037d5ce191a422eabe8d71bb68b0098344f6b07411c84d41" }, - "@luca/esbuild-deno-loader@0.11.0": { - "integrity": "c05a989aa7c4ee6992a27be5f15cfc5be12834cab7ff84cabb47313737c51a2c", - "dependencies": [ - "jsr:@std/bytes@^1.0.2", - "jsr:@std/encoding", - "jsr:@std/path@^1.0.6" - ] - }, "@std/assert@0.223.0": { "integrity": "eb8d6d879d76e1cc431205bd346ed4d88dc051c6366365b1af47034b0670be24" }, "@std/bytes@0.223.0": { "integrity": "84b75052cd8680942c397c2631318772b295019098f40aac5c36cead4cba51a8" }, - "@std/bytes@1.0.2": { - "integrity": "fbdee322bbd8c599a6af186a1603b3355e59a5fb1baa139f8f4c3c9a1b3e3d57" - }, "@std/cli@1.0.6": { "integrity": "d22d8b38c66c666d7ad1f2a66c5b122da1704f985d3c47f01129f05abb6c5d3d" }, @@ -82,19 +63,13 @@ "@std/fs@0.223.0": { "integrity": "3b4b0550b2c524cbaaa5a9170c90e96cbb7354e837ad1bdaf15fc9df1ae9c31c" }, - "@std/fs@1.0.5": { - "integrity": "41806ad6823d0b5f275f9849a2640d87e4ef67c51ee1b8fb02426f55e02fd44e", - "dependencies": [ - "jsr:@std/path@^1.0.7" - ] - }, "@std/http@1.0.9": { "integrity": "d409fc319a5e8d4a154e576c758752e9700282d74f31357a12fec6420f9ecb6c", "dependencies": [ "jsr:@std/cli", "jsr:@std/encoding", "jsr:@std/fmt@^1.0.3", - "jsr:@std/media-types@^1.0.3", + "jsr:@std/media-types", "jsr:@std/net", "jsr:@std/path@^1.0.7", "jsr:@std/streams" @@ -104,7 +79,7 @@ "integrity": "2d8c3c2ab3a515619b90da2c6ff5ea7b75a94383259ef4d02116b228393f84f1", "dependencies": [ "jsr:@std/assert", - "jsr:@std/bytes@0.223" + "jsr:@std/bytes" ] }, "@std/media-types@1.0.3": { @@ -133,8 +108,8 @@ "@babel/helper-validator-identifier@7.25.9": { "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==" }, - "@babel/parser@7.26.1": { - "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", + "@babel/parser@7.26.2": { + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "dependencies": [ "@babel/types" ] @@ -149,30 +124,6 @@ "@jridgewell/sourcemap-codec@1.5.0": { "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, - "@stock3/auth-js@4.2.3": { - "integrity": "sha512-zGtenGSxx/PVfbd9oIPPyPA9K2kOWYZ382lSNFZ2JzdB8SBVZinMP5c5s406cnxgMujTpim9lpaY/o7nUUCF1w==", - "dependencies": [ - "bg-api-authorization" - ] - }, - "@stock3/koala@15.3.8-esm.0_@stock3+auth-js@4.2.3_bg-auth-legacy@2.5.0_bg-status-js@2.4.3_flora-client-js@0.5.3_m-gate@2.12.8_vue@3.5.12_vue-router@4.4.5__vue@3.5.12": { - "integrity": "sha512-7VUztN6HIRYVgUjhouR3uBlZmLcQrvt7Z2ZVidb5DvSPRFtpYxGq65fqpovR+8O8k3d8BWs338Vc9sdPBYEV4A==", - "dependencies": [ - "@stock3/auth-js", - "bg-auth-legacy", - "bg-status-js", - "flora-client-js", - "m-gate", - "vue", - "vue-router" - ] - }, - "@types/node@22.5.4": { - "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", - "dependencies": [ - "undici-types" - ] - }, "@vue/compiler-core@3.5.12": { "integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", "dependencies": [ @@ -211,9 +162,6 @@ "@vue/shared" ] }, - "@vue/devtools-api@6.6.4": { - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" - }, "@vue/reactivity@3.5.12": { "integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==", "dependencies": [ @@ -247,15 +195,6 @@ "@vue/shared@3.5.12": { "integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==" }, - "bg-api-authorization@2.0.0": { - "integrity": "sha512-eo4lPdyktT3S2i6Ef+1drJuHku3NyvhLzM3JNkRsS70v+0J7C2jrsGQAXTVLnaJ5V+tC51g8C6BoanwQxi//8Q==" - }, - "bg-auth-legacy@2.5.0": { - "integrity": "sha512-+V1vVpUDrMJB1s8CcOak4yXBXbz3oejQ16GqKyuRrqy9e43VLozaHl/Xmsj1TCm2TrB7Ha2rExnk7VLbcjFU6w==" - }, - "bg-status-js@2.4.3": { - "integrity": "sha512-Ys0rGJGDZuPAfnYhTqwndRtZYxhmGopDZ2t42OGgJXnYxaZT1dDaKV56tXf75tMO9+y0PIOewP6kEgkkSccN1g==" - }, "csstype@3.1.3": { "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, @@ -265,18 +204,6 @@ "estree-walker@2.0.2": { "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" }, - "flora-client-js@0.5.3": { - "integrity": "sha512-00CHCjfIDxo+/ROQkHGqS+9mzhGVmdEMErmwBg7roYD4gIKNjDgFJgYoDB8V1VmTeK4LFaPm2B1du1iMxgY8sQ==", - "dependencies": [ - "has" - ] - }, - "has@1.0.4": { - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==" - }, - "m-gate@2.12.8": { - "integrity": "sha512-QAyDRBBYFx6k+WoVMpGwWFf2Z554LMNfF6yVmqW92FgP5hx9qUQypWZPl9P2XEw3Htlv/rBVQ9q9n+uBcx6yEg==" - }, "magic-string@0.30.12": { "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", "dependencies": [ @@ -300,16 +227,6 @@ "source-map-js@1.2.1": { "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" }, - "undici-types@6.19.8": { - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" - }, - "vue-router@4.4.5_vue@3.5.12": { - "integrity": "sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==", - "dependencies": [ - "@vue/devtools-api", - "vue" - ] - }, "vue@3.5.12": { "integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==", "dependencies": [ @@ -323,7 +240,6 @@ }, "workspace": { "dependencies": [ - "npm:@stock3/koala@^15.3.8-esm.0", "npm:vue@*", "npm:vue@^3.5.12" ] diff --git a/deps.ts b/deps.ts index fca492a..7943a10 100644 --- a/deps.ts +++ b/deps.ts @@ -1,5 +1,3 @@ import "jsr:@deno/emit"; -import "jsr:@std/media-types"; import "jsr:@std/http"; import "vue"; -import "@stock3/koala"; diff --git a/main.ts b/main.ts index 9e9b28f..d70a729 100644 --- a/main.ts +++ b/main.ts @@ -2,7 +2,7 @@ import { serveFile } from "jsr:@std/http/file-server"; import { createSSRApp } from "vue"; import { renderToString } from "vue/server-renderer"; import App from "@/App.tsx"; -import transpileResponse from './transpileTs.ts'; +import transpileResponse from './transpile.ts'; const utf8Decoder = new TextDecoder("utf-8"); @@ -17,7 +17,7 @@ Deno.serve({ const pathname = URL.parse(req.url)?.pathname ?? "/"; if (pathname === "/") { const rendered = await renderToString(createSSRApp(App)); - const content = utf8Decoder.decode(await Deno.readFile("./playground/index.html")) + const content = utf8Decoder.decode(await Deno.readFile("./public/index.html")) .replace(``, rendered) .replace(``, ''); return new Response(content, { headers: { "Content-Type": "text/html" } }); @@ -29,7 +29,7 @@ Deno.serve({ } else if (pathname.startsWith('/deps')) { return serveFile(req, `node_modules/${pathname.split('/deps')[1]}`); } else { - return serveFile(req, `playground${pathname}`); + return serveFile(req, `public${ pathname }`); } } else { return new Response("Only GET allowed.", { status: 500 }); diff --git a/public/index.html b/public/index.html index e97930e..ecf8f61 100644 --- a/public/index.html +++ b/public/index.html @@ -19,7 +19,7 @@

G'day, mate!

-

Willkommen auf Daniels Spielwiese

+

YOUR SITE GOES HERE

KANGAROO
diff --git a/transpile.ts b/transpile.ts new file mode 100644 index 0000000..c2ee9bc --- /dev/null +++ b/transpile.ts @@ -0,0 +1,57 @@ +import { CompilerOptions, transpile, TranspileOptions } from "jsr:@deno/emit"; +import denoJson from "./deno.json" with { type: "json" }; + +const contentTypes = { + 'js': "application/javascript; charset=utf-8", + + // https://github.com/denoland/deno_ast/blob/ea1ccec37e1aa8e5e1e70f983a7ed1472d0e132a/src/media_type.rs#L117 + 'ts': "text/typescript; charset=utf-8", + 'jsx': "text/jsx; charset=utf-8", + 'tsx': "text/tsx; charset=utf-8", +} as const; + +const transpileOptions = (extension: keyof typeof contentTypes, tsCode: string, targetUrlStr: string): TranspileOptions => ({ + importMap: { + imports: denoJson.imports, + }, + compilerOptions: denoJson.compilerOptions as CompilerOptions, + load(specifier) { + const correctContent = specifier === targetUrlStr; + return Promise.resolve({ + kind: "module", + specifier, + content: correctContent ? tsCode : "", + headers: { "content-type": contentTypes[correctContent ? extension : 'js'] }, + }); + }, +}); + +export default async function transpileResponse(response: Response, requestUrl: string, filepath?: string): Promise { + const url = new URL(`ts-serve:///${ requestUrl }`); + const pathname = filepath !== undefined ? filepath : url.pathname; + const extension = pathname.split('.').at(-1) ?? ''; + if (response.status === 200 && (extension === 'ts' || extension === 'tsx' || extension === 'jsx')) { + const tsCode = await response.text(); + const targetUrlStr = url.toString(); + try { + const result = await transpile(url, transpileOptions(extension, tsCode, targetUrlStr)); + const jsCode = result.get(targetUrlStr); + response.headers.delete("content-length"); + response.headers.set("content-type", contentTypes.js); + return new Response(jsCode, { + status: response.status, + statusText: response.statusText, + headers: response.headers, + }); + } catch (e) { + console.error('[transpileResponse]: Error transpiling!\n', e); + if (typeof e === 'string') { + return new Response('Internal Server Error', { + status: 500, + headers: response.headers, + }); + } + } + } + return response; +} diff --git a/transpileTs.ts b/transpileTs.ts deleted file mode 100644 index b758fa7..0000000 --- a/transpileTs.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { contentType } from "jsr:@std/media-types"; -import { transpile } from "jsr:@deno/emit"; -import config from "./deno.json" with { type: "json" }; - -const jsContentType = contentType(".js"); - -export enum MediaType { - TypeScript, - JSX, - TSX, -}; - -// https://github.com/denoland/deno_ast/blob/ea1ccec37e1aa8e5e1e70f983a7ed1472d0e132a/src/media_type.rs#L117 -const customContentType = { - [MediaType.TypeScript]: "text/typescript; charset=utf-8", - [MediaType.JSX]: "text/jsx; charset=utf-8", - [MediaType.TSX]: "text/tsx; charset=utf-8", -}; - -async function rewriteTsResponse(response: Response, url: URL, mediaType: MediaType) { - const tsCode = await response.text(); - const targetUrlStr = url.toString(); - try { - const result = await transpile(url, { - importMap: config, - compilerOptions: config.compilerOptions, - load(specifier) { - if (specifier !== targetUrlStr) { - return Promise.resolve({ - kind: "module", - specifier, - content: "", - headers: { "content-type": "application/javascript; charset=utf-8" }, - }); - } else { - return Promise.resolve({ - kind: "module", - specifier, - content: tsCode, - headers: { - "content-type": customContentType[mediaType], - }, - }); - } - }, - }); - const jsCode = result.get(targetUrlStr); - const { headers } = response; - headers.set("content-type", jsContentType); - headers.delete("content-length"); - - return new Response(jsCode, { - status: response.status, - statusText: response.statusText, - headers, - }); - } catch (e) { - console.error(e); - return new Response(`${e}`, { - status: 500, - statusText: `${e}`, - headers: response.headers, - }); - } -} - -export default async function transpileResponse(response: Response, requestUrl: string, filepath?: string): Promise { - const url = new URL(`ts-serve:///${ requestUrl }`); - if (response.status !== 200) { - return response; - } - const pathname = filepath !== undefined ? filepath : url.pathname; - const extension = pathname.split('.').at(-1) ?? null; - switch (extension) { - case 'ts': return await rewriteTsResponse(response, url, MediaType.TypeScript); - case 'tsx': return await rewriteTsResponse(response, url, MediaType.TSX); - case 'jsx': return await rewriteTsResponse(response, url, MediaType.JSX); - default: return response; - } -}