perf(fonts): heading serif slices served from public/ under content-hashed names, cached for good (BUG-1128)
Bundled media carry Next's per-deploy ?dpl= and were downloaded again after every release. Bytes unchanged; /fonts/serif-sc/* is immutable. Overturns the serif-headings contract line "bundled by Next, not served from public/" per TASK-home-first-load-20260930 decision 2. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ed4f513383
commit
8112f62b51
@@ -3,9 +3,14 @@
|
||||
|
||||
Input: upstream NotoSerifSC-SemiBold.otf (not committed; see
|
||||
frontend/src/app/fonts/serif-sc/SOURCE.txt for the URL and sha256).
|
||||
Output: frontend/src/app/fonts/serif-sc/jyotisha-serif-sc-NN.woff2
|
||||
Output: frontend/public/fonts/serif-sc/jyotisha-serif-sc-NN.<sha256[:10]>.woff2
|
||||
frontend/src/app/fonts/serif-sc/serif-sc.css (@font-face list)
|
||||
|
||||
The slices live in public/ under content-hashed names so their URL never
|
||||
carries Next's per-deploy `?dpl=` and stays cached across releases
|
||||
(TASK-home-first-load-20260930 T3-b, BUG-1128); next.config.ts serves
|
||||
/fonts/serif-sc/* as immutable.
|
||||
|
||||
Usage:
|
||||
python3 scripts/fonts/build_serif_slices.py --source /path/NotoSerifSC-SemiBold.otf
|
||||
python3 scripts/fonts/build_serif_slices.py --refresh-order --gf-slices /path/simplified-chinese_default.txt
|
||||
@@ -54,6 +59,8 @@ import sys
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[2]
|
||||
FONT_DIR = pathlib.Path(__file__).resolve().parent
|
||||
OUT_DIR = ROOT / "frontend" / "src" / "app" / "fonts" / "serif-sc"
|
||||
SLICE_DIR = ROOT / "frontend" / "public" / "fonts" / "serif-sc"
|
||||
SLICE_URL = "/fonts/serif-sc"
|
||||
LEVEL_FILES = (FONT_DIR / "tygfhzb-level-1.txt", FONT_DIR / "tygfhzb-level-2.txt")
|
||||
ORDER_FILE = FONT_DIR / "char_order.txt"
|
||||
|
||||
@@ -267,7 +274,8 @@ def build(source: pathlib.Path) -> None:
|
||||
slices = plan_slices(cmap)
|
||||
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
for old in OUT_DIR.glob(f"{FILE_PREFIX}-*.woff2"):
|
||||
SLICE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
for old in SLICE_DIR.glob(f"{FILE_PREFIX}-*.woff2"):
|
||||
old.unlink()
|
||||
css = [
|
||||
"/* Generated by scripts/fonts/build_serif_slices.py — do not edit by hand.",
|
||||
@@ -276,16 +284,16 @@ def build(source: pathlib.Path) -> None:
|
||||
" No preload and font-display: swap — headings paint in the sans stack first, then swap. */",
|
||||
]
|
||||
for i, sl in enumerate(slices):
|
||||
file_name = f"{FILE_PREFIX}-{i:02d}.woff2"
|
||||
blob = build_slice(data, sl["chars"])
|
||||
(OUT_DIR / file_name).write_bytes(blob)
|
||||
file_name = f"{FILE_PREFIX}-{i:02d}.{hashlib.sha256(blob).hexdigest()[:10]}.woff2"
|
||||
(SLICE_DIR / file_name).write_bytes(blob)
|
||||
css.append(
|
||||
"@font-face {\n"
|
||||
f" font-family: \"{FAMILY}\";\n"
|
||||
" font-style: normal;\n"
|
||||
" font-weight: 500 700;\n"
|
||||
" font-display: swap;\n"
|
||||
f" src: url(\"./{file_name}\") format(\"woff2\");\n"
|
||||
f" src: url(\"{SLICE_URL}/{file_name}\") format(\"woff2\");\n"
|
||||
f" unicode-range: {fmt_ranges(sl['ranges'])};\n"
|
||||
"}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user