-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprerender.ts
75 lines (68 loc) · 2.22 KB
/
prerender.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import path from "node:path";
import fs from "node:fs/promises";
type Bootstrap = (
register: (key: string, value: string) => void,
initPath: string,
) => Promise<void>;
// @ts-ignore
const { bootstrap, reset } = (await import("./dist/server/main.js")) as {
bootstrap: Bootstrap;
reset: () => void;
};
async function renderPath(path: string) {
console.log(`Rendering ${path}...`);
let tmpl = await fs.readFile("./dist/client/index.html", "utf-8");
await bootstrap((key, value) => {
if (key.startsWith(":")) {
// Special keys
// TODO: assert special keys cannot occur more than one time
// TODO: render image based on og:title
if (key === ":title")
tmpl = tmpl.replace(/<title>.*<\/title>/, `<title>${value}</title>`);
else if (key === ":backlink")
tmpl = tmpl.replace(
/<\/head>/,
`<meta name="giscus:backlink" href="${value}"></head>`,
);
else if (key === ":prerendered")
tmpl = tmpl.replace(/<root /, `<root data-prerendered="${value}" `);
else if (key.startsWith(":og:"))
tmpl = tmpl.replace(
/<\/head>/,
`<meta property="${key.slice(1)}" content="${value}"></head>`,
);
else console.log("Unknown special key:", key);
} else {
// This is a little of a type hack, because value is actually string
const valueStr = value as unknown as string;
tmpl = tmpl.replace(`<!-- SSR: ${key} -->`, valueStr);
tmpl = tmpl.replace(
new RegExp(
`<!-- SSR: ${key}\\[ -->[\\s\\S]*<!-- SSR: ${key}\\] -->`,
"m",
),
valueStr,
);
}
}, path);
await fs.writeFile(
`./dist/render${path === "/" ? "/index" : path}.html`,
tmpl,
);
reset();
}
async function work() {
// Mkdirs
await fs.mkdir("./dist/render", { recursive: true });
await fs.mkdir("./dist/render/post", { recursive: true });
// Prerender root
await renderPath("/");
await renderPath("/about");
// Render all posts
for (const post of await fs.readdir("../content")) {
const filename = path.basename(post, ".md");
const [_, slug] = filename.match(/^\d{4}-\d{2}-\d{2}-(.*)$/)!;
await renderPath(`/post/${slug}`);
}
}
work().catch(console.error);