djledda.de main
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

84 lines
3.7 KiB

  1. import { serveFile } from "jsr:@std/http/file-server";
  2. import { createSSRApp } from "vue";
  3. import { renderToString } from "vue/server-renderer";
  4. import { createRouter, createMemoryHistory } from 'vue-router';
  5. import Home from "@/home/App.tsx";
  6. import GERoot, { routes as geRoutes } from "@/generative-energy/GERoot.tsx";
  7. import transpileResponse from "./transpile.ts";
  8. import { DOMParser } from 'jsr:@b-fuze/deno-dom'
  9. const utf8Decoder = new TextDecoder("utf-8");
  10. const parser = new DOMParser();
  11. Deno.serve({
  12. port: 8080,
  13. hostname: "0.0.0.0",
  14. onListen({ port, hostname }) {
  15. console.log(`Listening on port http://${hostname}:${port}/`);
  16. },
  17. }, async (req, _conn) => {
  18. if (req.method === "GET") {
  19. const pathname = URL.parse(req.url)?.pathname ?? "/";
  20. if (pathname.startsWith('/static/') ||
  21. pathname.startsWith('/generative-energy/static/')) {
  22. if (pathname.startsWith('/static/')) {
  23. return serveFile(req, `public/home/${ pathname }`);
  24. } else {
  25. return serveFile(req, `public${pathname}`);
  26. }
  27. } else if (pathname === "/") {
  28. const rendered = await renderToString(createSSRApp(Home));
  29. const content = utf8Decoder.decode(await Deno.readFile("./public/home/index.html"))
  30. .replace(`<!-- SSR OUTLET -->`, rendered)
  31. .replace(`<!-- SSR HEAD OUTLET -->`, "");
  32. return new Response(content, { headers: { "Content-Type": "text/html" } });
  33. } else if (pathname.startsWith('/generative-energy')) {
  34. const app = createSSRApp(GERoot);
  35. const router = createRouter({
  36. routes: geRoutes,
  37. history: createMemoryHistory('/generative-energy'),
  38. });
  39. app.use(router);
  40. app.provide('dom-parse', (innerHTML: string) => {
  41. return parser.parseFromString(innerHTML, 'text/html').documentElement;
  42. });
  43. const ssrContext = { registry: {}};
  44. await router.replace(pathname.split('/generative-energy')[1]);
  45. await router.isReady();
  46. const rendered = await renderToString(app, ssrContext);
  47. const content = utf8Decoder.decode(await Deno.readFile("./public/generative-energy/index.html"))
  48. .replace('%TITLE%', 'Generative Energy')
  49. .replace('<!-- SSR HEAD OUTLET -->', `
  50. <script type="importmap">
  51. {
  52. "imports": {
  53. "vue": "/deps/vue/dist/vue.esm-browser.prod.js",
  54. "vue-router": "/deps/vue-router/dist/vue-router.esm-browser.js",
  55. "vue/jsx-runtime": "/deps/vue/jsx-runtime/index.mjs",
  56. "@vue/devtools-api": "/deps/@vue/devtools-api/lib/esm/index.js",
  57. "@/": "/app/"
  58. }
  59. }
  60. </script>
  61. <script> window.appstate = ${ JSON.stringify(ssrContext.registry) }; </script>
  62. `)
  63. .replace(`<!-- SSR OUTLET -->`, rendered);
  64. return new Response(content, { headers: { "Content-Type": "text/html" } });
  65. } else if (pathname.startsWith("/app") && (pathname.endsWith(".ts") || pathname.endsWith(".tsx"))) {
  66. const response = await serveFile(req, "./" + pathname);
  67. return await transpileResponse(response, req.url, pathname);
  68. } else if (pathname.startsWith("/deps")) {
  69. return serveFile(req, `node_modules/${pathname.split("/deps")[1]}`);
  70. }
  71. return new Response("Not found.", { status: 404 });
  72. } else {
  73. return new Response("Only GET allowed.", { status: 500 });
  74. }
  75. });
  76. Deno.addSignalListener("SIGINT", () => {
  77. console.info("Shutting down (received SIGINT)");
  78. Deno.exit();
  79. });