This commit is contained in:
Daniel Ledda
2024-11-01 21:29:13 +01:00
parent 64640300dd
commit 20479958bd
17 changed files with 224 additions and 96 deletions

71
main.ts
View File

@@ -13,20 +13,23 @@ const utf8Decoder = new TextDecoder("utf-8");
const parser = new DOMParser();
function appHeaderScript(params: { appstate: Record<string, unknown>; entryPath: string }) {
function appHeaderScript(params: { ssrContext: DJSSRContext, entryPath: string }) {
return `<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",
"@vue/devtools-api": "/app/devtools-shim.ts",
"@/": "/app/"
}
}
</script>
<style>
${ Object.values(params.ssrContext.styles).join('\n') }
</style>
<script type="module">
window.appstate = ${JSON.stringify(params.appstate)};
window.appstate = ${JSON.stringify(params.ssrContext.registry)};
import('${params.entryPath}');
</script>`;
}
@@ -47,7 +50,7 @@ for await (const path of publicFiles) {
sites.push(path);
}
function getAPIResponse(apiReq: Request): Response {
async function getAPIResponse(apiReq: Request): Promise<Response> {
let jsonResponse: DJAPIResult | { error: string } | null = null;
let status = 200;
@@ -62,22 +65,42 @@ function getAPIResponse(apiReq: Request): Response {
const apiPath = pathname.split("/api")[1];
if (apiPath === "/rp-articles") {
jsonResponse = [
{ name: "Koffein: ein vitamin-ähnlicher Nährstoff, oder Adaptogen", slug: "caffeine" },
{
name: "TSH, Temperatur, Puls, und andere Indikatoren bei einer Schilddrüsenunterfunktion",
slug: "hypothyroidism",
},
] satisfies DJAPIResultMap["/rp-articles"];
}
const paths: string[] = [];
const contentDir = './public/generative-energy/content/';
for await (const dirEnt of Deno.readDir(contentDir)) {
if (dirEnt.isFile && dirEnt.name.endsWith('.html')) {
paths.push(`${contentDir}${dirEnt.name}`);
}
}
const result: DJAPIResultMap['/rp-articles'] = [];
for (const filePath of paths) {
const content = await Deno.readTextFile(filePath);
const dom = parser.parseFromString(content, 'text/html');
const metadata = { title: '', tags: [] as string[], slug: '' };
const metaTags = dom.querySelectorAll('meta') as unknown as NodeListOf<HTMLMetaElement>;
for (const metaTag of metaTags) {
const name = metaTag.attributes.getNamedItem('name')?.value ?? '';
const content = metaTag.attributes.getNamedItem('content')?.value ?? '';
if (name === 'title') {
metadata.title = content;
} else if (name === 'tags') {
metadata.tags = content ? content.split(",") : [];
} else if (name === 'slug') {
metadata.slug = content;
}
}
result.push(metadata);
}
jsonResponse = result;
console.log(result);
}
}
if (!jsonResponse) {
jsonResponse = { error: `API route ${ apiPath } not found.` };
status = 404;
}
}
const headers = new Headers();
headers.set("Content-Type", "application/json");
return new Response(JSON.stringify(jsonResponse), {
@@ -93,13 +116,17 @@ Deno.serve({
console.log(`Listening on port http://${hostname}:${port}/`);
},
}, async (req, _conn) => {
const timeStart = new Date().getTime();
let response: Response | null = null;
const url = URL.parse(req.url);
if (req.method === "GET") {
const pathname = URL.parse(req.url)?.pathname ?? "/";
const pathname = url?.pathname ?? "/";
if (pathname.startsWith("/api/")) {
response = getAPIResponse(req);
response = await getAPIResponse(req);
}
// Public/static files
@@ -144,7 +171,7 @@ Deno.serve({
app.provide("dom-parse", (innerHTML: string) => {
return parser.parseFromString(innerHTML, "text/html").documentElement;
});
const ssrContext: DJSSRContext = { registry: {}, head: { title: "" } };
const ssrContext: DJSSRContext = { styles: {}, registry: {}, head: { title: "" } };
if (router) {
await router.replace(pathname.split("/generative-energy")[1]);
await router.isReady();
@@ -155,7 +182,7 @@ Deno.serve({
.replaceAll("%TITLE%", toValue(ssrContext.head?.title) ?? "Site")
.replace(
`<!-- SSR HEAD OUTLET -->`,
appHeaderScript({ appstate: ssrContext.registry, entryPath: clientEntry }),
appHeaderScript({ ssrContext, entryPath: clientEntry }),
);
response = new Response(content, { headers: { "Content-Type": "text/html" } });
}
@@ -164,7 +191,13 @@ Deno.serve({
response = new Response("Only GET allowed.", { status: 500 });
}
return response ?? new Response("Not found.", { status: 404 });
response ??= new Response("Not found.", { status: 404 })
const timeEnd = new Date().getTime();
console.log(`Request ${ url?.pathname ?? 'malformed' }\tStatus ${ response.status }, Duration ${ timeEnd - timeStart }ms`);
return response;
});
Deno.addSignalListener("SIGINT", () => {