feat: add safe project upgrades and production performance fixes

This commit is contained in:
2026-07-12 16:54:22 +05:30
parent a524c08126
commit 935b3103dd
68 changed files with 555 additions and 107 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/styles",
"version": "0.2.13",
"version": "0.2.14",
"type": "module",
"main": "src/index.ts",
"exports": {
+30
View File
@@ -175,6 +175,36 @@ export function renderFontHead(fonts?: FontConfig): string {
return out.join("\n ");
}
/**
* Production variant that inlines the small Google Fonts stylesheet at build
* time. This removes a render-blocking CSS round trip while retaining the same
* font files, `font-display`, CSP sources, and offline-safe fallback markup.
*/
export async function renderProductionFontHead(
fonts?: FontConfig,
fetcher: (input: string, init?: RequestInit) => Promise<Response> = fetch,
): Promise<string> {
const fallback = renderFontHead(fonts);
if (!fonts?.google?.length) return fallback;
const url = googleFontsUrl(fonts.google, fonts.display ?? "swap");
try {
const response = await fetcher(url, {
headers: {
// Google returns compact WOFF2 rules to modern browser user agents.
"user-agent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120 Safari/537.36",
},
});
if (!response.ok) return fallback;
const css = (await response.text()).replace(/<\/style/gi, "<\\/style");
const stylesheet = `<link rel="stylesheet" href="${escAttr(url)}">`;
return fallback
.replace(`<link rel="preconnect" href="${GOOGLE_CSS}">\n `, "")
.replace(stylesheet, `<style data-wrnexus-google-fonts>\n${css}\n</style>`);
} catch {
return fallback;
}
}
/**
* CSP source hosts required by the configured fonts, so the policy can be
* auto-extended (Google Fonts need their CSS + static hosts allow-listed).
+1 -1
View File
@@ -18,7 +18,7 @@ export type {
export { loadAppConfig, loadRawConfig, headToString, resolveProfile, loadEnv } from "./config.ts";
export { findStyleEntry, bundleCss } from "./styles.ts";
export type { FontConfig, GoogleFont, LocalFontFace, FontDisplay } from "./fonts.ts";
export { renderFontHead, fontCspSources } from "./fonts.ts";
export { renderFontHead, renderProductionFontHead, fontCspSources } from "./fonts.ts";
export type { ThemeConfig, ThemeTokens, ResolvedTheme } from "./theme.ts";
export {
DEFAULT_THEMES,
+11 -1
View File
@@ -1,5 +1,5 @@
import { expect, test } from "bun:test";
import { fontCspSources, renderFontHead } from "../src/index.ts";
import { fontCspSources, renderFontHead, renderProductionFontHead } from "../src/index.ts";
test("renders subsetted Google and escaped local font markup", () => {
const html = renderFontHead({
@@ -20,3 +20,13 @@ test("renders subsetted Google and escaped local font markup", () => {
font: ["https://fonts.gstatic.com"],
});
});
test("production font head inlines Google CSS and removes its blocking stylesheet", async () => {
const html = await renderProductionFontHead(
{ google: [{ family: "Plus Jakarta Sans", weights: [400, 700] }] },
() => Promise.resolve(new Response('@font-face{font-family:"Plus Jakarta Sans"}')),
);
expect(html).toContain("data-wrnexus-google-fonts");
expect(html).toContain("@font-face");
expect(html).not.toContain('<link rel="stylesheet" href="https://fonts.googleapis.com');
});