mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
perf(producer): cache local font compression (#2397)
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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<Uint8Array>;
|
||||
@@ -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<string> {
|
||||
type FontCompressionOptions = {
|
||||
cacheDir?: string;
|
||||
compressImpl?: (input: Buffer) => Promise<Buffer>;
|
||||
};
|
||||
|
||||
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<string> {
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user