39 lines
1.3 KiB
TypeScript
39 lines
1.3 KiB
TypeScript
/**
|
|
* The built frontend's `index.html`, with its runtime placeholders filled: the
|
|
* site name, emoji, icon version and Bandcamp player mode.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
import { BANDCAMP_PLAYER, OG_SITE_NAME, SITE_EMOJI } from "../config.ts";
|
|
import { emojiToCodepoint } from "./site-icons.ts";
|
|
|
|
/** The cache-busting version of the icon URLs. */
|
|
const ICON_VERSION = emojiToCodepoint(SITE_EMOJI);
|
|
|
|
/**
|
|
* `index.html` with its placeholders filled, by root. Kept until the file
|
|
* changes (a rebuild under a running server): a stat per navigation instead of
|
|
* a read and four replaceAll.
|
|
*/
|
|
const indexHtml = new Map<string, { mtime: number; html: string }>();
|
|
|
|
/**
|
|
* Returns `${root}/index.html` with its placeholders filled.
|
|
*
|
|
* @throws {Error} When the file can't be read.
|
|
*/
|
|
export async function loadIndexHtml(root: string): Promise<string> {
|
|
const path = `${root}/index.html`;
|
|
const mtime = (await Deno.stat(path)).mtime?.getTime() ?? 0;
|
|
const cached = indexHtml.get(root);
|
|
if (cached && cached.mtime === mtime) return cached.html;
|
|
const html = (await Deno.readTextFile(path))
|
|
.replaceAll("__SITE_NAME__", OG_SITE_NAME)
|
|
.replaceAll("__SITE_EMOJI__", SITE_EMOJI)
|
|
.replaceAll("__ICON_VERSION__", ICON_VERSION)
|
|
.replaceAll("__BANDCAMP_PLAYER__", BANDCAMP_PLAYER);
|
|
indexHtml.set(root, { mtime, html });
|
|
return html;
|
|
}
|