mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
perf(producer): renders embed local fonts as-is instead of re-compressing them (#5865)
* perf(producer): renders embed local fonts as-is instead of re-compressing them Local ttf/otf fonts in a render were woff2-compressed on every cold font cache, which costs seconds per font. The compiled HTML is a render-time artifact, so embed them raw. fontToDataUri gains a compress: false option; its default is unchanged. * refactor(producer): name the raw local font option instead of explaining it in comments
This commit is contained in:
@@ -136,6 +136,25 @@ describe("fontToDataUri", () => {
|
||||
expect(uri).toMatch(/^data:font\/otf;base64,/);
|
||||
});
|
||||
|
||||
it("embeds ttf and otf raw without compressing or caching when compress is false", async () => {
|
||||
const cacheDir = mkdtempSync(join(tmpdir(), "hf-font-compression-off-"));
|
||||
const compressImpl = vi.fn(async () => Buffer.from("woff2"));
|
||||
try {
|
||||
const raw = Buffer.from("font-bytes");
|
||||
const options = { cacheDir, compressImpl, compressToWoff2: false };
|
||||
expect(await fontToDataUri(raw, "ttf", options)).toBe(
|
||||
`data:font/ttf;base64,${raw.toString("base64")}`,
|
||||
);
|
||||
expect(await fontToDataUri(raw, "otf", options)).toBe(
|
||||
`data:font/otf;base64,${raw.toString("base64")}`,
|
||||
);
|
||||
expect(compressImpl).not.toHaveBeenCalled();
|
||||
expect(readdirSync(cacheDir)).toEqual([]);
|
||||
} finally {
|
||||
rmSync(cacheDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("embeds ttc collections raw without attempting slow woff2 compression", async () => {
|
||||
const warnings: unknown[][] = [];
|
||||
const originalWarn = console.warn;
|
||||
|
||||
@@ -33,6 +33,7 @@ function rawMimeType(format: string): string {
|
||||
type FontCompressionOptions = {
|
||||
cacheDir?: string;
|
||||
compressImpl?: (input: Buffer) => Promise<Buffer>;
|
||||
compressToWoff2?: boolean;
|
||||
};
|
||||
|
||||
function defaultCacheDir(): string {
|
||||
@@ -94,8 +95,8 @@ export async function fontToDataUri(
|
||||
if (originalFormat === "woff2") {
|
||||
return `data:font/woff2;base64,${input.toString("base64")}`;
|
||||
}
|
||||
if (originalFormat === "ttc") {
|
||||
return `data:font/collection;base64,${input.toString("base64")}`;
|
||||
if (originalFormat === "ttc" || options.compressToWoff2 === false) {
|
||||
return `data:${rawMimeType(originalFormat)};base64,${input.toString("base64")}`;
|
||||
}
|
||||
try {
|
||||
const cachePath = cachedCompressionPath(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// fallow-ignore-file code-duplication
|
||||
import { describe, expect, it, mock, beforeAll } from "bun:test";
|
||||
import { createHash } from "node:crypto";
|
||||
import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from "node:fs";
|
||||
import { mkdtempSync, writeFileSync, mkdirSync, rmSync, readFileSync, readdirSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { runInThisContext } from "node:vm";
|
||||
@@ -1211,6 +1211,52 @@ describe("local font embedding", () => {
|
||||
expect(embeddedMessages).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("embeds local ttf and otf fonts as-is without woff2 compression", async () => {
|
||||
const projectDir = mkdtempSync(join(tmpdir(), "hf-local-font-raw-"));
|
||||
const cacheDir = mkdtempSync(join(tmpdir(), "hf-local-font-cache-"));
|
||||
const font = readFileSync(
|
||||
join(
|
||||
import.meta.dirname,
|
||||
"../../../../docs/public/catalog/items/frost-sequence-camera-orbit/assets/fonts/Geist-Regular.ttf",
|
||||
),
|
||||
);
|
||||
writeFileSync(join(projectDir, "a.ttf"), font);
|
||||
writeFileSync(join(projectDir, "b.otf"), font);
|
||||
writeFileSync(
|
||||
join(projectDir, "index.html"),
|
||||
`<!DOCTYPE html>
|
||||
<html><head><style>
|
||||
@font-face { font-family: "A"; src: url("a.ttf"); }
|
||||
@font-face { font-family: "B"; src: url("b.otf"); }
|
||||
</style></head><body>
|
||||
<div data-composition-id="root" data-width="640" data-height="360" data-duration="1">Text</div>
|
||||
</body></html>`,
|
||||
);
|
||||
|
||||
const previousCacheDir = process.env.HYPERFRAMES_FONT_CACHE_DIR;
|
||||
process.env.HYPERFRAMES_FONT_CACHE_DIR = cacheDir;
|
||||
let html: string;
|
||||
try {
|
||||
({ html } = await compileForRender(projectDir, join(projectDir, "index.html"), projectDir));
|
||||
} finally {
|
||||
if (previousCacheDir === undefined) delete process.env.HYPERFRAMES_FONT_CACHE_DIR;
|
||||
else process.env.HYPERFRAMES_FONT_CACHE_DIR = previousCacheDir;
|
||||
}
|
||||
|
||||
const embedded = (mime: string) =>
|
||||
Buffer.from(
|
||||
html.match(new RegExp(`data:${mime};base64,([A-Za-z0-9+/=]+)`))?.[1] ?? "",
|
||||
"base64",
|
||||
);
|
||||
expect(embedded("font/ttf").equals(font)).toBe(true);
|
||||
expect(embedded("font/otf").equals(font)).toBe(true);
|
||||
expect(html).not.toContain("data:font/woff2");
|
||||
// The woff2 compressor writes every result to this cache; empty means it never ran.
|
||||
expect(readdirSync(cacheDir, { recursive: true })).toEqual([]);
|
||||
rmSync(projectDir, { recursive: true, force: true });
|
||||
rmSync(cacheDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("keeps large local font collections file-backed instead of expanding them into HTML", async () => {
|
||||
const projectDir = mkdtempSync(join(tmpdir(), "hf-large-local-font-"));
|
||||
const assetsDir = join(projectDir, "assets");
|
||||
|
||||
@@ -1841,7 +1841,7 @@ async function embedLocalFontFaces(html: string, projectDir: string): Promise<st
|
||||
embeddedPaths.add(localPath);
|
||||
continue;
|
||||
}
|
||||
dataUri = await toDataUri(font.buffer, ext);
|
||||
dataUri = await toDataUri(font.buffer, ext, { compressToWoff2: false });
|
||||
dataUriByAbsolutePath.set(absPath, dataUri);
|
||||
defaultLogger.info(
|
||||
`[Compiler] Embedded local font file: ${localPath} (${(font.buffer.length / 1024).toFixed(0)} KB → data URI)`,
|
||||
|
||||
Reference in New Issue
Block a user