import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; import path from "path"; import type { BundlerCTXMap, BunextPageLastmodRecord } from "../types"; import grabDirNames from "./grab-dir-names"; import { log } from "./log"; /** * # Path of the page last-modified record */ export function grabPageLastmodFile(lastmod_file?: string) { const { ROOT_DIR, PAGE_LASTMOD_JSON } = grabDirNames(); const target = lastmod_file || global.BUNEXT_CONFIG?.sitemap?.lastmod_file; return target ? path.resolve(ROOT_DIR, target) : PAGE_LASTMOD_JSON; } export function readPageLastmodRecord( lastmod_file?: string, ): BunextPageLastmodRecord | undefined { const file = grabPageLastmodFile(lastmod_file); if (!existsSync(file)) return; try { const record = JSON.parse(readFileSync(file, "utf-8")); if (record?.pages && typeof record.pages == "object") return record; } catch {} log.warn(`Ignoring invalid page lastmod record ${file}`); } /** * # Record when each page's client bundle last changed * A page's bundle hash covers its whole client import graph (including * the root layout), so a component edit re-dates every page that uses it. * Unchanged pages keep their previous date; removed pages are dropped. */ export function updatePageLastmodRecord({ ctx_map, build_date = new Date(), lastmod_file, }: { ctx_map: { [local_path: string]: BundlerCTXMap }; build_date?: Date; lastmod_file?: string; }): BunextPageLastmodRecord { const prior = readPageLastmodRecord(lastmod_file); const record: BunextPageLastmodRecord = { pages: {} }; // Sorted so a committed record produces minimal diffs const local_paths = Object.keys(ctx_map).sort(); for (const local_path of local_paths) { const artifact = ctx_map[local_path]; if (!artifact?.hash) continue; const fingerprint = `${artifact.hash}:${artifact.css_path || ""}`; const prior_page = prior?.pages[local_path]; record.pages[local_path] = prior_page?.fingerprint == fingerprint ? prior_page : { fingerprint, lastmod: build_date.toISOString() }; } const file = grabPageLastmodFile(lastmod_file); mkdirSync(path.dirname(file), { recursive: true }); writeFileSync(file, JSON.stringify(record, null, 4), "utf-8"); return record; }