From 79143c9e04fbf67253d8626f061662d3389971cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Tue, 14 Jul 2026 04:23:49 +0000 Subject: [PATCH] perf(producer): cache local font compression --- .../src/services/fontCompression.test.ts | 24 +++++- .../producer/src/services/fontCompression.ts | 73 ++++++++++++++++++- 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/packages/producer/src/services/fontCompression.test.ts b/packages/producer/src/services/fontCompression.test.ts index 92969481b1..e4e3716790 100644 --- a/packages/producer/src/services/fontCompression.test.ts +++ b/packages/producer/src/services/fontCompression.test.ts @@ -1,5 +1,7 @@ import { describe, expect, it } from "bun:test"; -import { existsSync, readFileSync } from "node:fs"; +import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; import { compressToWoff2, fontToDataUri } from "./fontCompression.js"; /** @@ -41,6 +43,26 @@ describe("compressToWoff2", () => { }); describe("fontToDataUri", () => { + it("reuses cached compression across calls", async () => { + const cacheDir = mkdtempSync(join(tmpdir(), "hf-local-font-cache-")); + const raw = Buffer.from("stable-font-content"); + let compressionCalls = 0; + const compressImpl = async () => { + compressionCalls += 1; + return Buffer.from("compressed-font-content"); + }; + + try { + const first = await fontToDataUri(raw, "ttf", { cacheDir, compressImpl }); + const second = await fontToDataUri(raw, "ttf", { cacheDir, compressImpl }); + + expect(second).toBe(first); + expect(compressionCalls).toBe(1); + } finally { + rmSync(cacheDir, { recursive: true, force: true }); + } + }); + it("skips compression for woff2 input and returns a data URI", async () => { const raw = Buffer.from("fake-woff2-bytes"); const uri = await fontToDataUri(raw, "woff2"); diff --git a/packages/producer/src/services/fontCompression.ts b/packages/producer/src/services/fontCompression.ts index d6be0df43e..ae3d952bfd 100644 --- a/packages/producer/src/services/fontCompression.ts +++ b/packages/producer/src/services/fontCompression.ts @@ -1,5 +1,9 @@ // @ts-expect-error -- wawoff2 ships no type declarations; ambient .d.ts only visible to producer's own tsconfig import wawoff2 from "wawoff2"; +import { createHash } from "node:crypto"; +import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs"; +import { homedir, tmpdir } from "node:os"; +import { dirname, join } from "node:path"; const { compress } = wawoff2 as { compress: (input: Buffer | Uint8Array) => Promise; @@ -18,12 +22,77 @@ function rawMimeType(format: string): string { return RAW_MIME_TYPES[format] ?? "font/ttf"; } -export async function fontToDataUri(input: Buffer, originalFormat: string): Promise { +type FontCompressionOptions = { + cacheDir?: string; + compressImpl?: (input: Buffer) => Promise; +}; + +function defaultCacheDir(): string { + const root = + process.env.HYPERFRAMES_FONT_CACHE_DIR ?? + (process.env.AWS_LAMBDA_FUNCTION_NAME + ? join(tmpdir(), "hyperframes", "fonts") + : join(homedir(), ".cache", "hyperframes", "fonts")); + return join(root, "local-compression-v1"); +} + +function cachedCompressionPath(input: Buffer, originalFormat: string, cacheDir: string): string { + const digest = createHash("sha256") + .update("hyperframes-local-font-compression-v1\0") + .update(originalFormat) + .update("\0") + .update(input) + .digest("hex"); + return join(cacheDir, `${digest}.woff2`); +} + +function readCachedCompression(path: string): Buffer | null { + try { + if (!existsSync(path)) return null; + const cached = readFileSync(path); + return cached.length > 0 ? cached : null; + } catch { + return null; + } +} + +function cacheCompression(path: string, compressed: Buffer): void { + const tmpPath = `${path}.tmp-${process.pid}-${Date.now()}`; + try { + mkdirSync(dirname(path), { recursive: true }); + writeFileSync(tmpPath, compressed, { flag: "wx", mode: 0o644 }); + renameSync(tmpPath, path); + } catch { + // A concurrent process may have populated the cache, or the cache may be + // read-only. Compression still succeeded, so rendering can continue. + } finally { + try { + rmSync(tmpPath, { force: true }); + } catch { + // Best-effort cleanup only. + } + } +} + +export async function fontToDataUri( + input: Buffer, + originalFormat: string, + options: FontCompressionOptions = {}, +): Promise { if (originalFormat === "woff2") { return `data:font/woff2;base64,${input.toString("base64")}`; } try { - const compressed = await compressToWoff2(input); + const cachePath = cachedCompressionPath( + input, + originalFormat, + options.cacheDir ?? defaultCacheDir(), + ); + const cached = readCachedCompression(cachePath); + if (cached) return `data:font/woff2;base64,${cached.toString("base64")}`; + + const compressed = await (options.compressImpl ?? compressToWoff2)(input); + cacheCompression(cachePath, compressed); return `data:font/woff2;base64,${compressed.toString("base64")}`; } catch { console.warn(