mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 16:03:02 +00:00
fabefed39f
The book catalogue grows from 7 families to 34, all self-hosted through @fontsource under the SIL OFL 1.1 or the Apache License 2.0: condensed and poster faces, heavy retro display, elegant display serifs, Montserrat, twelve scripts and DM Mono. Weights run from 100 to 900, each family offering only the weights it ships, and the serifs gain real italics. The catalogue lives in @trek/shared (book-fonts.data.ts) with each family's roles (display, heading, body, script, mono), weights, italics and letter width, so the Studio, the findings, the design engine and the assistant read one list. Page operations and the design engine set a weight a family lacks at its nearest one, describe_book_page names the role and the weight, and font_mix no longer counts scripts and mono faces, warning above three. The Studio gets StudioFontPicker: the current family set in itself, a searchable list grouped by kind with every family in its own face and the book's own families first, and a weight slider over the weights the family has. Faces load only when used; the assistant's page snapshot embeds only the faces a page draws, the service worker installs only the latin files of the original seven families, and the faces of an opened book are cached for offline use. BOOK_SCHEMA_REV goes to 2.
94 lines
4.8 KiB
TypeScript
94 lines
4.8 KiB
TypeScript
import { readFileSync } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
import { describe, expect, it } from 'vitest';
|
|
import { APP_FACES, bookFontFile, keepInPrecache, withoutRuntimeFonts } from '../../../bookFontPrecache.js';
|
|
|
|
/**
|
|
* Which font files the service worker installs (FE-SW-FONTS): the app's own
|
|
* faces as before, the latin woff2 of the seven book families that shipped
|
|
* first, and nothing else of the book's catalogue, which waits in the
|
|
* book-fonts runtime cache for a book that uses it.
|
|
*/
|
|
|
|
// Vitest runs with the client package as its root, so cwd is stable here.
|
|
const read = (rel: string) => readFileSync(resolve(process.cwd(), rel), 'utf8');
|
|
|
|
const asset = (name: string) => `assets/${name}`;
|
|
|
|
describe('reading a font file name', () => {
|
|
it('FE-SW-FONTS-001: reads package, subset, weight and style as the build names them, and nothing else as a book face', () => {
|
|
expect(bookFontFile(asset('dm-serif-display-latin-ext-400-italic-Ab12_cD3.woff2'))).toEqual({
|
|
pkg: 'dm-serif-display',
|
|
subset: 'latin-ext',
|
|
weight: 400,
|
|
italic: true,
|
|
ext: 'woff2',
|
|
});
|
|
expect(bookFontFile(asset('dm-mono-latin-500-normal-xyz.woff'))).toMatchObject({ pkg: 'dm-mono', subset: 'latin' });
|
|
expect(bookFontFile(asset('geist-sans-latin-400-normal-abc.woff2'))).toBeNull();
|
|
expect(bookFontFile(asset('index-abc.js'))).toBeNull();
|
|
expect(bookFontFile(asset('lora.woff2'))).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('the precache', () => {
|
|
it('FE-SW-FONTS-002: keeps the faces the app draws, whatever their subset and format', () => {
|
|
expect(keepInPrecache(asset('poppins-latin-500-normal-abc.woff'))).toBe(true);
|
|
expect(keepInPrecache(asset('poppins-devanagari-700-normal-abc.woff2'))).toBe(true);
|
|
expect(keepInPrecache(asset('museomoderno-latin-800-normal-abc.woff2'))).toBe(true);
|
|
expect(keepInPrecache(asset('geist-sans-latin-600-normal-abc.woff2'))).toBe(true);
|
|
expect(keepInPrecache(asset('index-abc.js'))).toBe(true);
|
|
});
|
|
|
|
it('FE-SW-FONTS-003: keeps only the latin woff2 of the seven book families that shipped first', () => {
|
|
expect(keepInPrecache(asset('lora-latin-400-normal-abc.woff2'))).toBe(true);
|
|
expect(keepInPrecache(asset('bebas-neue-latin-400-normal-abc.woff2'))).toBe(true);
|
|
expect(keepInPrecache(asset('museomoderno-latin-500-normal-abc.woff2'))).toBe(true);
|
|
expect(keepInPrecache(asset('lora-latin-400-normal-abc.woff'))).toBe(false);
|
|
expect(keepInPrecache(asset('lora-cyrillic-400-normal-abc.woff2'))).toBe(false);
|
|
expect(keepInPrecache(asset('lora-latin-400-italic-abc.woff2'))).toBe(false);
|
|
expect(keepInPrecache(asset('eb-garamond-latin-800-normal-abc.woff2'))).toBe(false);
|
|
expect(keepInPrecache(asset('poppins-latin-900-normal-abc.woff2'))).toBe(false);
|
|
});
|
|
|
|
it('FE-SW-FONTS-004: leaves every file of the new families to the runtime cache', () => {
|
|
for (const name of [
|
|
'anton-latin-400-normal-abc.woff2',
|
|
'caveat-latin-700-normal-abc.woff2',
|
|
'fraunces-latin-ext-900-italic-abc.woff',
|
|
]) {
|
|
expect(keepInPrecache(asset(name)), name).toBe(false);
|
|
}
|
|
const manifest = [
|
|
{ url: asset('index-abc.js'), revision: null },
|
|
{ url: asset('anton-latin-400-normal-abc.woff2'), revision: null },
|
|
{ url: asset('inter-latin-400-normal-abc.woff2'), revision: null },
|
|
];
|
|
expect(withoutRuntimeFonts(manifest)).toEqual({ manifest: [manifest[0], manifest[2]], warnings: [] });
|
|
});
|
|
|
|
it('FE-SW-FONTS-005: knows the app faces main.tsx imports, so the chrome never loses one offline', () => {
|
|
const imported = [...read('src/main.tsx').matchAll(/@fontsource\/([a-z0-9-]+)\/(\d+)\.css/g)].map(
|
|
(m) => `${m[1]}/${m[2]}`
|
|
);
|
|
const declared = Object.entries(APP_FACES).flatMap(([pkg, weights]) => weights.map((w) => `${pkg}/${w}`));
|
|
expect(imported.filter((face) => !face.startsWith('geist-sans/')).sort()).toEqual(declared.sort());
|
|
});
|
|
|
|
it('FE-SW-FONTS-006: is wired into the worker, with the runtime rule the Studio fills', () => {
|
|
const config = read('vite.config.js');
|
|
expect(config).toContain('manifestTransforms: [withoutRuntimeFonts]');
|
|
const rule =
|
|
/urlPattern:\s*(\/[^\n]*woff2[^\n]*\/i),\s*\n\s*handler:\s*'CacheFirst',\s*\n\s*options:\s*\{\s*\n\s*cacheName:\s*'book-fonts'/.exec(
|
|
config
|
|
);
|
|
expect(rule).not.toBeNull();
|
|
const literal = rule?.[1] ?? '//';
|
|
const pattern = new RegExp(literal.slice(1, literal.lastIndexOf('/')), 'i');
|
|
expect(pattern.test('https://trek.example/assets/anton-latin-400-normal-abc.woff2')).toBe(true);
|
|
expect(pattern.test('https://trek.example/assets/lora-latin-400-normal-abc.woff')).toBe(true);
|
|
expect(pattern.test('https://trek.example/assets/index-abc.js')).toBe(false);
|
|
expect(pattern.test('https://trek.example/api/photos/1/file.woff2')).toBe(false);
|
|
});
|
|
});
|