fix(engine): suppress font-load 404s by checking console location URL (#313)

Chrome's "Failed to load resource" message text does not include the failing
URL — it's only on msg.location().url. The previous filter in frameCapture.ts
only checked msg.text(), so every font 404 (e.g. Google Fonts <link> tags
in sandboxed render environments) fell through to the "[non-blocking]"
prefix instead of being suppressed.

Extract the classifier into isFontResourceError() and match against both
text and location.url, and extend the extension match to .ttf/.otf. Adds
a unit test covering the URL-in-location, URL-in-text, and non-font cases.

This is a targeted fix for the render-output noise that PR #311 attempted
to address by adding a ~120-entry SYSTEM_FONTS skip list. That approach
silently shadowed existing FONT_ALIASES (arial→inter, helvetica→inter,
courier new→jetbrains-mono, segoe ui→roboto, etc.) and changed render
output on Linux fleets that don't have those fonts installed. Fixing the
console-log filter here suppresses the noise without changing any font
resolution behavior.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
James Russo
2026-04-17 17:38:46 -07:00
committed by GitHub
co-authored by Claude Opus 4.7
parent 42d39866ff
commit 686e45dac0
2 changed files with 135 additions and 7 deletions
+23 -7
View File
@@ -142,6 +142,27 @@ export async function createCaptureSession(
};
}
/**
* Classify a console "Failed to load resource" error as a font-load failure.
*
* These are expected when deterministic font injection replaces Google Fonts
* @import URLs with embedded base64 — or when the render environment has no
* network access to Google Fonts. Suppressing them reduces noise in render
* output without hiding real asset failures (images, videos, scripts, etc.).
*
* Chrome's `msg.text()` for a failed resource is typically just
* `"Failed to load resource: net::ERR_FAILED"` — the URL is only on
* `msg.location().url`. We match against both so the filter works regardless
* of which form Chrome emits.
*/
export function isFontResourceError(type: string, text: string, locationUrl: string): boolean {
if (type !== "error") return false;
if (!text.startsWith("Failed to load resource")) return false;
return /fonts\.googleapis|fonts\.gstatic|\.(woff2?|ttf|otf)(\b|$)/i.test(
`${locationUrl} ${text}`,
);
}
export async function initializeSession(session: CaptureSession): Promise<void> {
const { page, serverUrl } = session;
@@ -149,13 +170,8 @@ export async function initializeSession(session: CaptureSession): Promise<void>
page.on("console", (msg: ConsoleMessage) => {
const type = msg.type();
const text = msg.text();
// Suppress font-loading 404s entirely. These are expected when deterministic
// font injection replaces Google Fonts @import URLs with embedded base64.
const isFontLoadError =
type === "error" &&
text.startsWith("Failed to load resource") &&
/fonts\.googleapis|fonts\.gstatic|\.woff2?(\b|$)/i.test(text);
const locationUrl = msg.location()?.url ?? "";
const isFontLoadError = isFontResourceError(type, text, locationUrl);
// Other "Failed to load resource" 404s are typically non-blocking (e.g.
// favicon, sourcemaps, optional assets). Prefix them so users know they