commit e6f20af28d4a455f66b4d051cb21f4160dd758d0 Author: Daniel Ledda Date: Wed Oct 30 20:42:01 2024 +0100 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a56a7ef --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules + diff --git a/app/App.tsx b/app/App.tsx new file mode 100644 index 0000000..ca3ca22 --- /dev/null +++ b/app/App.tsx @@ -0,0 +1,19 @@ +import { defineComponent, computed, ref } from "vue"; +import Test from '@/test.tsx'; + +export default defineComponent({ + name: "app-root", + setup() { + const count = ref(0); + const countDouble = computed(() => count.value * 2); + count.value++; + return () => ( +
+ +
Count: {count.value}
+
Count Double: {countDouble.value}
+ +
+ ); + }, +}); diff --git a/app/test.tsx b/app/test.tsx new file mode 100644 index 0000000..f8d8729 --- /dev/null +++ b/app/test.tsx @@ -0,0 +1 @@ +export default () =>
Test
; diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..cd54a7a --- /dev/null +++ b/deno.json @@ -0,0 +1,23 @@ +{ + "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" + }, + "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/" + }, + "nodeModulesDir": "auto", + "compilerOptions": { + "jsx": "react-jsx", + "jsxFactory": "h", + "jsxFragmentFactory": "Fragment", + "jsxImportSource": "vue" + } +} diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..c671d10 --- /dev/null +++ b/deno.lock @@ -0,0 +1,331 @@ +{ + "version": "4", + "specifiers": { + "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": { + "@deno/cache-dir@0.13.2": { + "integrity": "c22419dfe27ab85f345bee487aaaadba498b005cce3644e9d2528db035c5454d", + "dependencies": [ + "jsr:@deno/graph", + "jsr:@std/fmt@0.223", + "jsr:@std/fs@0.223", + "jsr:@std/io", + "jsr:@std/path@0.223" + ] + }, + "@deno/emit@0.46.0": { + "integrity": "e276be2c77bac1b93caf775762e2a49a54cb00da2d48ca2b01ed8d7cba9d082c", + "dependencies": [ + "jsr:@deno/cache-dir", + "jsr:@std/path@0.223" + ] + }, + "@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" + }, + "@std/encoding@1.0.5": { + "integrity": "ecf363d4fc25bd85bd915ff6733a7e79b67e0e7806334af15f4645c569fefc04" + }, + "@std/fmt@0.223.0": { + "integrity": "6deb37794127dfc7d7bded2586b9fc6f5d50e62a8134846608baf71ffc1a5208" + }, + "@std/fmt@1.0.3": { + "integrity": "97765c16aa32245ff4e2204ecf7d8562496a3cb8592340a80e7e554e0bb9149f" + }, + "@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/net", + "jsr:@std/path@^1.0.7", + "jsr:@std/streams" + ] + }, + "@std/io@0.223.0": { + "integrity": "2d8c3c2ab3a515619b90da2c6ff5ea7b75a94383259ef4d02116b228393f84f1", + "dependencies": [ + "jsr:@std/assert", + "jsr:@std/bytes@0.223" + ] + }, + "@std/media-types@1.0.3": { + "integrity": "b12d30a7852f7578f4d210622df713bbfd1cbdd9b4ec2eaf5c1845ab70bab159" + }, + "@std/net@1.0.4": { + "integrity": "2f403b455ebbccf83d8a027d29c5a9e3a2452fea39bb2da7f2c04af09c8bc852" + }, + "@std/path@0.223.0": { + "integrity": "593963402d7e6597f5a6e620931661053572c982fc014000459edc1f93cc3989", + "dependencies": [ + "jsr:@std/assert" + ] + }, + "@std/path@1.0.7": { + "integrity": "76a689e07f0e15dcc6002ec39d0866797e7156629212b28f27179b8a5c3b33a1" + }, + "@std/streams@1.0.7": { + "integrity": "1a93917ca0c58c01b2bfb93647189229b1702677f169b6fb61ad6241cd2e499b" + } + }, + "npm": { + "@babel/helper-string-parser@7.25.9": { + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==" + }, + "@babel/helper-validator-identifier@7.25.9": { + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==" + }, + "@babel/parser@7.26.1": { + "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", + "dependencies": [ + "@babel/types" + ] + }, + "@babel/types@7.26.0": { + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "dependencies": [ + "@babel/helper-string-parser", + "@babel/helper-validator-identifier" + ] + }, + "@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": [ + "@babel/parser", + "@vue/shared", + "entities", + "estree-walker", + "source-map-js" + ] + }, + "@vue/compiler-dom@3.5.12": { + "integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", + "dependencies": [ + "@vue/compiler-core", + "@vue/shared" + ] + }, + "@vue/compiler-sfc@3.5.12": { + "integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", + "dependencies": [ + "@babel/parser", + "@vue/compiler-core", + "@vue/compiler-dom", + "@vue/compiler-ssr", + "@vue/shared", + "estree-walker", + "magic-string", + "postcss", + "source-map-js" + ] + }, + "@vue/compiler-ssr@3.5.12": { + "integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", + "dependencies": [ + "@vue/compiler-dom", + "@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": [ + "@vue/shared" + ] + }, + "@vue/runtime-core@3.5.12": { + "integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==", + "dependencies": [ + "@vue/reactivity", + "@vue/shared" + ] + }, + "@vue/runtime-dom@3.5.12": { + "integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==", + "dependencies": [ + "@vue/reactivity", + "@vue/runtime-core", + "@vue/shared", + "csstype" + ] + }, + "@vue/server-renderer@3.5.12_vue@3.5.12": { + "integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==", + "dependencies": [ + "@vue/compiler-ssr", + "@vue/shared", + "vue" + ] + }, + "@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==" + }, + "entities@4.5.0": { + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "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": [ + "@jridgewell/sourcemap-codec" + ] + }, + "nanoid@3.3.7": { + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" + }, + "picocolors@1.1.1": { + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "postcss@8.4.47": { + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "dependencies": [ + "nanoid", + "picocolors", + "source-map-js" + ] + }, + "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": [ + "@vue/compiler-dom", + "@vue/compiler-sfc", + "@vue/runtime-dom", + "@vue/server-renderer", + "@vue/shared" + ] + } + }, + "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 new file mode 100644 index 0000000..fca492a --- /dev/null +++ b/deps.ts @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..9e9b28f --- /dev/null +++ b/main.ts @@ -0,0 +1,42 @@ +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'; + +const utf8Decoder = new TextDecoder("utf-8"); + +Deno.serve({ + port: 8080, + hostname: "0.0.0.0", + onListen({ port, hostname }) { + console.log(`Listening on port http://${hostname}:${port}/`); + }, +}, async (req, _conn) => { + if (req.method === "GET") { + 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")) + .replace(``, rendered) + .replace(``, ''); + return new Response(content, { headers: { "Content-Type": "text/html" } }); + } else if (pathname === "/health") { + return new Response("OK"); + } else if (pathname.startsWith('/app') && (pathname.endsWith('.ts') || pathname.endsWith('.tsx'))) { + const response = await serveFile(req, './' + pathname); + return await transpileResponse(response, req.url, pathname); + } else if (pathname.startsWith('/deps')) { + return serveFile(req, `node_modules/${pathname.split('/deps')[1]}`); + } else { + return serveFile(req, `playground${pathname}`); + } + } else { + return new Response("Only GET allowed.", { status: 500 }); + } +}); + +Deno.addSignalListener("SIGINT", () => { + console.info("Shutting down (received SIGINT)"); + Deno.exit(); +}); diff --git a/public/app.js b/public/app.js new file mode 100644 index 0000000..9833426 --- /dev/null +++ b/public/app.js @@ -0,0 +1,4 @@ +import { createSSRApp } from "vue"; +import App from "@/App.tsx"; + +createSSRApp(App).mount('#app-root'); diff --git a/public/icon.webp b/public/icon.webp new file mode 100644 index 0000000..9658d7e Binary files /dev/null and b/public/icon.webp differ diff --git a/public/image.jpeg b/public/image.jpeg new file mode 100644 index 0000000..50e1ebb Binary files /dev/null and b/public/image.jpeg differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..e97930e --- /dev/null +++ b/public/index.html @@ -0,0 +1,27 @@ + + + + G'day + + + + + + + +
+

G'day, mate!

+

Willkommen auf Daniels Spielwiese

+ KANGAROO +
+
+ + diff --git a/public/styles.css b/public/styles.css new file mode 100644 index 0000000..ef76dde --- /dev/null +++ b/public/styles.css @@ -0,0 +1,22 @@ +.container { + margin: auto; + text-align: center; + width: 100%; + background-color: #fffafa; + box-shadow: #000000; + padding-top: 10px; + min-height: calc(100vh - 10px); + box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.2); + + @media (min-width: 992px) { + width: 900px; + } + + h1 { + margin: 0; + } +} + +body { + margin: 0; +} diff --git a/transpileTs.ts b/transpileTs.ts new file mode 100644 index 0000000..b758fa7 --- /dev/null +++ b/transpileTs.ts @@ -0,0 +1,80 @@ +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; + } +}