UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

86 lines (74 loc) 2.45 kB
import { $hook, $inject, Alepha } from "alepha"; import { SSRManifestProvider } from "./SSRManifestProvider.ts"; /** * Adds HTTP Link headers for preloading entry assets. * * Benefits: * - Early Hints (103): Servers can send preload hints before the full response * - CDN optimization: Many CDNs use Link headers to optimize asset delivery * - Browser prefetching: Browsers can start fetching resources earlier * * The Link header is computed once at first request and cached for reuse. */ export class ReactPreloadProvider { protected readonly alepha = $inject(Alepha); protected readonly ssrManifest = $inject(SSRManifestProvider); /** * Cached Link header value - computed once, reused for all requests. */ protected cachedLinkHeader: string | null | undefined; /** * Build the Link header string from entry assets. * * Format: <url>; rel=preload; as=type, <url>; rel=modulepreload * * @returns Link header string or null if no assets */ protected buildLinkHeader(): string | null { const assets = this.ssrManifest.getEntryAssets(); if (!assets) return null; const links: string[] = []; // CSS - preload as style for (const css of assets.css) { links.push(`<${css}>; rel=preload; as=style`); } // JS - modulepreload for ES modules if (assets.js) { links.push(`<${assets.js}>; rel=modulepreload`); } return links.length > 0 ? links.join(", ") : null; } /** * Get the cached Link header, computing it on first access. */ protected getLinkHeader(): string | null { if (this.cachedLinkHeader === undefined) { this.cachedLinkHeader = this.buildLinkHeader(); } return this.cachedLinkHeader; } /** * Add Link header to HTML responses for asset preloading. */ protected readonly onResponse = $hook({ on: "server:onResponse", priority: "first", handler: ({ response }) => { // Only add to HTML responses (SSR pages) const contentType = response.headers["content-type"]; if (!contentType?.includes("text/html")) { return; } const linkHeader = this.getLinkHeader(); if (!linkHeader) { return; } // Append to existing Link header if present if (response.headers.link) { response.headers.link = `${response.headers.link}, ${linkHeader}`; } else { response.headers.link = linkHeader; } }, }); }