Files
djledda-web/main.ts
Daniel Ledda bcb820f35e nice
2024-10-31 23:46:23 +01:00

84 lines
3.7 KiB
TypeScript

import { serveFile } from "jsr:@std/http/file-server";
import { createSSRApp } from "vue";
import { renderToString } from "vue/server-renderer";
import { createRouter, createMemoryHistory } from 'vue-router';
import Home from "@/home/App.tsx";
import GERoot, { routes as geRoutes } from "@/generative-energy/GERoot.tsx";
import transpileResponse from "./transpile.ts";
import { DOMParser } from 'jsr:@b-fuze/deno-dom'
const utf8Decoder = new TextDecoder("utf-8");
const parser = new DOMParser();
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.startsWith('/static/') ||
pathname.startsWith('/generative-energy/static/')) {
if (pathname.startsWith('/static/')) {
return serveFile(req, `public/home/${ pathname }`);
} else {
return serveFile(req, `public${pathname}`);
}
} else if (pathname === "/") {
const rendered = await renderToString(createSSRApp(Home));
const content = utf8Decoder.decode(await Deno.readFile("./public/home/index.html"))
.replace(`<!-- SSR OUTLET -->`, rendered)
.replace(`<!-- SSR HEAD OUTLET -->`, "");
return new Response(content, { headers: { "Content-Type": "text/html" } });
} else if (pathname.startsWith('/generative-energy')) {
const app = createSSRApp(GERoot);
const router = createRouter({
routes: geRoutes,
history: createMemoryHistory('/generative-energy'),
});
app.use(router);
app.provide('dom-parse', (innerHTML: string) => {
return parser.parseFromString(innerHTML, 'text/html').documentElement;
});
const ssrContext = { registry: {}};
await router.replace(pathname.split('/generative-energy')[1]);
await router.isReady();
const rendered = await renderToString(app, ssrContext);
const content = utf8Decoder.decode(await Deno.readFile("./public/generative-energy/index.html"))
.replace('%TITLE%', 'Generative Energy')
.replace('<!-- SSR HEAD OUTLET -->', `
<script type="importmap">
{
"imports": {
"vue": "/deps/vue/dist/vue.esm-browser.prod.js",
"vue-router": "/deps/vue-router/dist/vue-router.esm-browser.js",
"vue/jsx-runtime": "/deps/vue/jsx-runtime/index.mjs",
"@vue/devtools-api": "/deps/@vue/devtools-api/lib/esm/index.js",
"@/": "/app/"
}
}
</script>
<script> window.appstate = ${ JSON.stringify(ssrContext.registry) }; </script>
`)
.replace(`<!-- SSR OUTLET -->`, rendered);
return new Response(content, { headers: { "Content-Type": "text/html" } });
} 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]}`);
}
return new Response("Not found.", { status: 404 });
} else {
return new Response("Only GET allowed.", { status: 500 });
}
});
Deno.addSignalListener("SIGINT", () => {
console.info("Shutting down (received SIGINT)");
Deno.exit();
});