42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
/**
|
|
* Fills the placeholders of the frontend's `index.html` with settings read at
|
|
* runtime, so they change with a restart and no rebuild. The static and OG
|
|
* middlewares serve what it returns.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
import { BANDCAMP_PLAYER, OG_SITE_NAME, SITE_EMOJI } from "../config.ts";
|
|
import { emojiToCodepoint } from "./site-icons.ts";
|
|
|
|
/**
|
|
* Versions the icon URLs, so browsers fetch new icons when the emoji changes.
|
|
*/
|
|
const ICON_VERSION = emojiToCodepoint(SITE_EMOJI);
|
|
|
|
/**
|
|
* Caches each root's filled file until its mtime changes, as a rebuild under a
|
|
* running server does, so a navigation costs a stat instead of a read.
|
|
*/
|
|
const indexHtml = new Map<string, { mtime: number; html: string }>();
|
|
|
|
/**
|
|
* Returns `${root}/index.html` with the site name, emoji, icon version and
|
|
* Bandcamp player mode filled in.
|
|
*
|
|
* @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;
|
|
}
|