fix: resolve font assets under development base paths

Serve font definitions beside their WOFF2 files through a base-aware stylesheet link, using relative URLs consistently in dev and static builds.

Exercise all six faces, nested-route reloads and existing font fallback/no-JS checks in the dev suite; avoid starting the preview server as part of dev checks.
This commit is contained in:
2026-10-16 06:12:57 +09:00
parent c480b67301
commit 1297d86140
6 changed files with 47 additions and 15 deletions
+30 -1
View File
@@ -5,19 +5,28 @@ test.use({ javaScriptEnabled: true });
test('self-hosted Lyth Mono and EB Garamond load with the configured base', async ({ page }, testInfo) => {
const external: string[] = [];
const fontResponses: { url: string; status: number }[] = [];
page.on('response', (response) => {
if (response.request().resourceType() === 'font') fontResponses.push({ url: response.url(), status: response.status() });
});
page.on('request', (request) => {
if (request.resourceType() === 'font' && !request.url().startsWith(testInfo.project.use.baseURL!)) external.push(request.url());
});
await page.goto('./');
// Cold dev startup may reload the document while modules initialize. Let
// initial asset traffic settle before probing FontFaceSet in that document.
await page.goto('./', { waitUntil: 'networkidle' });
const fonts = await page.evaluate(async () => {
await document.fonts.ready;
const mono = await document.fonts.load('14px "Lyth Mono"', '0W│├└─');
const bold = await document.fonts.load('700 14px "Lyth Mono"', 'WIP');
const serif = await document.fonts.load('16px "EB Garamond"', 'Worldspace');
const italic = await document.fonts.load('italic 16px "EB Garamond"', 'Worldspace');
const serifBold = await document.fonts.load('700 16px "EB Garamond"', 'Worldspace');
const boldItalic = await document.fonts.load('italic 700 16px "EB Garamond"', 'Worldspace');
return {
mono: mono.map((font) => font.status), bold: bold.map((font) => font.status),
serif: serif.map((font) => font.status), italic: italic.map((font) => font.status),
serifBold: serifBold.map((font) => font.status), boldItalic: boldItalic.map((font) => font.status),
stack: getComputedStyle(document.body).fontFamily,
prefix: document.querySelector('.branch-prefix')!.textContent!.trim(),
};
@@ -26,6 +35,14 @@ test('self-hosted Lyth Mono and EB Garamond load with the configured base', asyn
expect(fonts.bold).toEqual(['loaded']);
expect(fonts.serif).toEqual(['loaded']);
expect(fonts.italic).toEqual(['loaded']);
expect(fonts.serifBold).toEqual(['loaded']);
expect(fonts.boldItalic).toEqual(['loaded']);
const filenames = ['LythMono-Regular', 'LythMono-Bold', 'EBGaramond-Regular', 'EBGaramond-Bold', 'EBGaramond-Italic', 'EBGaramond-BoldItalic'];
expect([...new Set(fontResponses.map(({ url }) => url))].sort()).toEqual(
filenames.map((name) => new URL(`fonts/${name}.woff2`, testInfo.project.use.baseURL!).href).sort(),
);
// The dev server may revalidate the preloaded regular face after a reload.
expect(fontResponses.filter(({ status }) => status !== 200 && status !== 304)).toEqual([]);
expect(fonts.stack).toContain('Lyth Mono');
expect(fonts.prefix).toBe(''); // SSR uses the same glyph paths, not HTML wires.
expect(external).toEqual([]);
@@ -45,6 +62,18 @@ test('self-hosted Lyth Mono and EB Garamond load with the configured base', asyn
expect(await page.locator('.tree-pane .root-vector .trunk-reveal').evaluate((rect) => (rect as SVGRectElement).height.baseVal.value)).toBeGreaterThan(0);
expect(await page.locator('article.prose').evaluate((element) => getComputedStyle(element).fontFamily)).toContain('EB Garamond');
await page.screenshot({ path: testInfo.outputPath('eb-garamond-book.png') });
// A fresh nested route must resolve fonts relative to their stylesheet, not
// relative to the page URL, without relying on ClientRouter's persisted DOM.
await page.reload();
const reloaded = await page.evaluate(async () => {
await document.fonts.ready;
return [
(await document.fonts.load('14px "Lyth Mono"', 'WIP')).map((font) => font.status),
(await document.fonts.load('16px "EB Garamond"', 'Worldspace')).map((font) => font.status),
];
});
expect(reloaded).toEqual([['loaded'], ['loaded']]);
expect(external).toEqual([]);
});
test.describe('static font and tree rendering', () => {