Landing performance: flag font subset, responsive mascots, AVIF cache, HTML minify

- Flag font: ship a committed fontTools subset (43 KB, -45%) of
  TwemojiCountryFlags.woff2 with only the 15 flags the site uses, under a
  content-hashed name with a preload on every flag-bearing page. The build
  validates the subset against a manifest and fails when a new flag
  appears without regenerating (npm run subset-flags). JS subsetters
  (subset-font/harfbuzzjs) were rejected: their wasm builds silently drop
  the COLR/CPAL color tables, rendering all flags invisible.
- Responsive mascots: legal/join/404 pages served 434-500px sources for
  175-180px slots; the build now emits 180w/360w variants (AVIF 1x: ~7 KB
  vs ~22 KB) and the pages use srcset. Small logo spots (14-42px) now use
  the existing 64/128px variants instead of the 256px file.
- injectAvifPictures copies the img sizes attribute onto the AVIF
  <source>; without it Chrome mis-selects w-descriptor candidates and can
  drop the image entirely.
- AVIF conversion is cached by content hash (.avif-cache.json); the old
  mtime check never hit because copyDirSync refreshes mtimes, so every
  verify re-encoded all 26 files.
- HTML output is minified (comments + indentation, <pre> preserved,
  newlines kept for inline-script safety): index.html 121 KB -> 93 KB.
- unicode-range trimmed to U+1F1E6-1F1FF; tag-sequence flags fall through
  to the system emoji font.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
KoalaDev
2026-07-12 04:34:53 +02:00
parent 9fd4e870f3
commit af4ac943a9
17 changed files with 397 additions and 36 deletions
+48
View File
@@ -0,0 +1,48 @@
/**
* Shared helpers for the country-flag font subset.
* Used by build.cjs (validation) and tools/subset-flag-font.mjs (generation).
*
* Flags are regional-indicator pairs; tag-sequence flags (🏴 England etc.)
* are NOT extracted or subset — if one is ever added it will render via the
* system emoji font.
*/
const fs = require('fs');
const path = require('path');
const FLAG_PAIR_RE = /[\u{1F1E6}-\u{1F1FF}]{2}/gu;
function collectFlagSourceFiles(websiteDir) {
const files = [];
for (const entry of fs.readdirSync(websiteDir)) {
if (entry.endsWith('.html')) files.push(path.join(websiteDir, entry));
}
for (const dir of ['alternatives', 'locales']) {
const p = path.join(websiteDir, dir);
if (!fs.existsSync(p)) continue;
for (const entry of fs.readdirSync(p)) {
if (/\.(html|json)$/.test(entry)) files.push(path.join(p, entry));
}
}
return files;
}
function extractUsedFlags(files) {
const flags = new Set();
for (const file of files) {
for (const m of fs.readFileSync(file, 'utf8').matchAll(FLAG_PAIR_RE)) {
flags.add(m[0]);
}
}
return [...flags].sort();
}
// 🇩🇪 → "DE" (for readable manifests and tool output)
function flagToCountryCode(flag) {
return [...flag].map(c => String.fromCharCode(c.codePointAt(0) - 0x1F1E6 + 65)).join('');
}
function countryCodeToFlag(code) {
return [...code].map(c => String.fromCodePoint(0x1F1E6 + c.charCodeAt(0) - 65)).join('');
}
module.exports = { FLAG_PAIR_RE, collectFlagSourceFiles, extractUsedFlags, flagToCountryCode, countryCodeToFlag };