/** * 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, DEFAULT_STYLE, OG_SITE_NAME, SITE_EMOJI, SMTPS_URL, } 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(); /** * Returns `${root}/index.html` with the site name, emoji, icon version, * Bandcamp player mode, default style and whether email is on filled in. * * @throws {Error} When the file can't be read. */ export async function loadIndexHtml(root: string): Promise { 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) .replaceAll("__DEFAULT_STYLE__", DEFAULT_STYLE) .replaceAll("__EMAIL_ENABLED__", SMTPS_URL ? "on" : "off"); indexHtml.set(root, { mtime, html }); return html; }