fix(cli): bundle preview font localization (#2449)

This commit is contained in:
Miguel Ángel
2026-07-14 18:02:51 -04:00
committed by GitHub
parent 0b3dfb3f84
commit 9ce44b6603
2 changed files with 23 additions and 10 deletions
@@ -1,9 +1,19 @@
import { afterEach, describe, expect, it, vi } from "vitest";
const producerMocks = vi.hoisted(() => ({
loadProducer: vi.fn(async () => ({
injectDeterministicFontFaces: async (html: string) => `${html}<!--bundled-producer-->`,
})),
}));
vi.mock("@hyperframes/core/compiler", () => ({
bundleToSingleHtml: vi.fn(async () => "<html><body>bundled</body></html>"),
}));
vi.mock("./producer.js", () => ({
loadProducer: producerMocks.loadProducer,
}));
import {
__resetFontLocalizationWarningsForTests,
bundleWithLocalizedFonts,
@@ -31,6 +41,12 @@ describe("bundleWithLocalizedFonts (call-site integration)", () => {
});
describe("localizeWithProducer", () => {
it("loads the injector through the producer module bundled with the CLI", async () => {
const out = await localizeWithProducer("<html></html>");
expect(producerMocks.loadProducer).toHaveBeenCalledOnce();
expect(out).toBe("<html></html><!--bundled-producer-->");
});
it("embeds fonts when the injector is available", async () => {
const inject = vi.fn(async (html: string) => `${html}<!--fonts-->`);
const warn = vi.fn();
@@ -29,14 +29,11 @@ export async function bundleWithLocalizedFonts(
type FontInjector = (html: string) => Promise<string>;
/**
* Load the render pipeline's `injectDeterministicFontFaces`, resolving
* `@hyperframes/producer` at RUNTIME only. The specifier is kept out of the
* bundler's/test-runner's static module graph (`@vite-ignore` + a variable
* specifier) on purpose: the CLI test job builds with `--filter
* '!@hyperframes/producer'`, so a static `import("@hyperframes/producer")`
* would fail Vitest's transform-time resolution. At runtime — the built CLI or
* an installed package — producer is a real dependency and resolves via
* node_modules.
* Load the render pipeline's `injectDeterministicFontFaces` through the CLI's
* canonical producer loader. That loader uses a literal dynamic import, which
* lets tsup see and inline producer into the published CLI bundle. A variable
* bare-package import is invisible to tsup and silently fails after `npm
* install`, because producer is intentionally only a workspace devDependency.
*
* Returns `null` (not a throw) when the module simply isn't available in this
* environment, so the caller can treat "producer absent" — a benign, expected
@@ -44,8 +41,8 @@ type FontInjector = (html: string) => Promise<string>;
*/
async function loadFontInjector(): Promise<FontInjector | null> {
try {
const producerSpecifier = "@hyperframes/producer";
const mod = (await import(/* @vite-ignore */ producerSpecifier)) as {
const { loadProducer } = await import("./producer.js");
const mod = (await loadProducer()) as {
injectDeterministicFontFaces?: FontInjector;
};
return mod.injectDeterministicFontFaces ?? null;