From 60f58cfc2045aec0b4519a4d8940f24692354471 Mon Sep 17 00:00:00 2001 From: Alejandro Veras Date: Thu, 1 Oct 2026 11:29:31 -0400 Subject: [PATCH] Fingerprint CSS and JS URLs so deploys never serve stale styles Assets are cached for a week, so the browser kept the previous styles.css and rendered the new markup with old rules. Each build now appends a content hash. Co-Authored-By: Claude Opus 5.5 --- build.mjs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/build.mjs b/build.mjs index cc3eb02..3cdd6f6 100644 --- a/build.mjs +++ b/build.mjs @@ -1,5 +1,6 @@ // Builds the static site into ./dist. No dependencies: `node build.mjs`. -import { mkdir, rm, writeFile, cp } from 'node:fs/promises'; +import { mkdir, rm, writeFile, cp, readFile } from 'node:fs/promises'; +import { createHash } from 'node:crypto'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { page, eyebrow, btn } from './src/layout.mjs'; @@ -12,22 +13,27 @@ await rm(out, { recursive: true, force: true }); await mkdir(out, { recursive: true }); await cp(join(root, 'static'), out, { recursive: true }); +// Fingerprint CSS/JS so a new deploy never reuses a stale cached copy. +const hashOf = async (f) => createHash('sha256').update(await readFile(join(root, 'static', f))).digest('hex').slice(0, 10); +const assetVersions = { '/assets/styles.css': await hashOf('assets/styles.css'), '/assets/site.js': await hashOf('assets/site.js') }; +const fingerprint = (html) => Object.entries(assetVersions).reduce((h, [u, v]) => h.replaceAll(`"${u}"`, `"${u}?v=${v}"`), html); + const urls = []; for (const name of pages) { const def = (await import(`./src/pages/${name}.mjs`)).default; const file = join(out, def.path, 'index.html'); await mkdir(dirname(file), { recursive: true }); - await writeFile(file, page(def)); + await writeFile(file, fingerprint(page(def))); urls.push(def.path); console.log('built', def.path); } -await writeFile(join(out, '404.html'), page({ +await writeFile(join(out, '404.html'), fingerprint(page({ path: '/404/', title: 'Page Not Found | Dylan Mazzei', description: 'This page could not be found.', body: `
${eyebrow('404')}

Page Not Found

${btn('BACK TO HOME', '/')}
`, -})); +}))); const today = new Date().toISOString().slice(0, 10); await writeFile(join(out, 'sitemap.xml'), `