perf: optimize production assets and proxy-aware URLs
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-server",
|
||||
"version": "0.2.14",
|
||||
"version": "0.2.15",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -65,6 +65,8 @@ export interface ProdOptions {
|
||||
stylesPath?: string;
|
||||
/** Small production stylesheet inlined into the document head. */
|
||||
inlineStyles?: string;
|
||||
/** `stylesPath` contains theme + UI + app CSS in cascade order. */
|
||||
stylesIncludeFramework?: boolean;
|
||||
/** Absolute path to the pre-built reactive runtime. */
|
||||
reactivePath?: string;
|
||||
/** Absolute path to the pre-built theme stylesheet (`theme.css`). */
|
||||
@@ -287,6 +289,7 @@ export function createProductionHandlers(
|
||||
theme: opts.theme,
|
||||
i18n: opts.i18n,
|
||||
inlineStyles: opts.inlineStyles,
|
||||
stylesIncludeFramework: opts.stylesIncludeFramework,
|
||||
assetVersion: opts.assetVersion,
|
||||
head: opts.head,
|
||||
seo: opts.seo,
|
||||
|
||||
@@ -33,6 +33,9 @@ function cachePolicy(filePath: string, mode: Mode): string {
|
||||
if (mode !== "production") return "no-cache";
|
||||
const name = filePath.split(/[\\/]/).pop() ?? "";
|
||||
if (/\.html?$/i.test(name)) return REVALIDATE_CACHE;
|
||||
// Font URLs are content assets with expensive transfer costs and are almost
|
||||
// always renamed when changed. Cache them like fingerprinted build assets.
|
||||
if (/\.(?:woff2?|ttf|otf|eot)$/i.test(name)) return IMMUTABLE_CACHE;
|
||||
return /(?:^|[.-])[a-f0-9]{8,}(?:[.-]|$)/i.test(name) ? IMMUTABLE_CACHE : "public, max-age=3600";
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,8 @@ export interface RuntimeDeps {
|
||||
hasUi?: boolean;
|
||||
/** Production build combined theme + UI stylesheet. */
|
||||
hasFrameworkStyles?: boolean;
|
||||
/** App stylesheet already contains theme + UI CSS and is the only CSS request needed. */
|
||||
stylesIncludeFramework?: boolean;
|
||||
/** Resolved theme config: enables `/__wrnexus/theme.css` + `<html data-theme>`. */
|
||||
theme?: ResolvedTheme;
|
||||
/** Resolved i18n bundle: enables `ctx.t`, `<html lang>`, and `{t:key}` markers. */
|
||||
@@ -569,15 +571,15 @@ export function createHandlers(deps: RuntimeDeps): Handlers {
|
||||
// Order: theme tokens, then Wire UI, then the app stylesheet — so the app's
|
||||
// own CSS (loaded last) can override both the tokens and the UI classes.
|
||||
const headParts: string[] = [];
|
||||
if (deps.hasFrameworkStyles) {
|
||||
if (deps.hasFrameworkStyles && !deps.stylesIncludeFramework) {
|
||||
headParts.push(
|
||||
`<link rel="stylesheet" href="${versionAssetUrl("/__wrnexus/framework.css", deps.assetVersion)}" />`,
|
||||
);
|
||||
} else if (deps.theme) {
|
||||
} else if (deps.theme && !deps.stylesIncludeFramework) {
|
||||
const themeHref = versionAssetUrl(THEME_CSS_HREF, deps.assetVersion);
|
||||
headParts.push(`<link rel="stylesheet" href="${themeHref}" />`);
|
||||
}
|
||||
if (deps.hasUi && !deps.hasFrameworkStyles) {
|
||||
if (deps.hasUi && !deps.hasFrameworkStyles && !deps.stylesIncludeFramework) {
|
||||
headParts.push(
|
||||
`<link rel="stylesheet" href="${versionAssetUrl("/__wrnexus/ui.css", deps.assetVersion)}" />`,
|
||||
);
|
||||
|
||||
@@ -9,11 +9,14 @@ test("production HTML revalidates while fingerprinted assets are immutable", asy
|
||||
mkdirSync(join(root, "assets"));
|
||||
writeFileSync(join(root, "index.html"), "home");
|
||||
writeFileSync(join(root, "assets", "app.abcdef1234.js"), "app");
|
||||
writeFileSync(join(root, "brand.woff2"), "font");
|
||||
const html = await servePublicAsset(root, "/index.html", "production");
|
||||
const asset = await servePublicAsset(root, "/assets/app.abcdef1234.js", "production");
|
||||
const font = await servePublicAsset(root, "/brand.woff2", "production");
|
||||
expect(html?.headers.get("cache-control")).toBe("public, max-age=0, must-revalidate");
|
||||
expect(asset?.headers.get("cache-control")).toBe("public, max-age=31536000, immutable");
|
||||
expect(asset?.headers.get("x-content-type-options")).toBe("nosniff");
|
||||
expect(font?.headers.get("cache-control")).toBe("public, max-age=31536000, immutable");
|
||||
});
|
||||
|
||||
test("public server rejects encoded traversal", async () => {
|
||||
|
||||
Reference in New Issue
Block a user