mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
* perf(landing): edge-cache HTML and precise-load thumbnails Without `public/_headers` Cloudflare Pages serves every HTML with `cf-cache-status: DYNAMIC` so each request roundtrips to the Pages origin — observed TTFB 660–900ms from Seattle, worse from Asia. With `s-maxage=3600, stale-while-revalidate=86400` HTML stays cached at the edge between deploys (CF Pages auto-purges on every deploy so freshness is unchanged in practice), and `_astro/` hash bundles flip to `immutable` so the existing 4h+must-revalidate roundtrips go away. For thumbnails, native `loading="lazy"` is browser-decided — Chrome over-prefetches (1250–3000px), Safari fires near in-viewport. A new `<LazyImg>` Astro component and global IntersectionObserver (rootMargin 300px for images, 600px for videos) replaces all 10 site-wide `loading="lazy"` usages with precise control. Above-the-fold slots (first 4 rows, detail-page hero previews) opt into `eager` or `priority` to skip the IO roundtrip. Homepage hero LCP gets `<link rel="preload" imagesrcset>`, a 4-step `srcset` (768/1280/1920/2560) plus `fetchpriority="high"` so retina devices stop repainting from the 1024-only variant — was the P99 long tail. Verified: `pnpm guard` 6/6, `pnpm typecheck` 0 errors, `pnpm build` 865 pages 28s, generated `out/index.html` contains the preload link and 15 `data-precise-src` thumbnails, `out/plugins/index.html` has 95 precise-loaded thumbnails plus the IO script. * perf(landing): logo to webp + parallelize Google Fonts load Two HAR-validated wins on top of the edge-cache / precise-load commit: logo: 500x500 192KB PNG → 200x200 7.5KB WebP. Footer/header actually render at 36x36, so the source is 5x larger than necessary at the display size and ships RGBA PNG bytes for what reads as a flat graphic. WebP at q=85 keeps the gradient ring crisp at every DPR we care about. fonts: globals.css used `@import url(...)` for Google Fonts, which serialized HTML → CSS → fonts.googleapis.com/css2 → fonts.gstatic.com/ woff2. HAR measured 953ms for the fonts CSS plus 400–800ms per woff2 × 4 — close to 3s before text could render in the intended family, even with display=swap. Moving to `<link>` + `<link rel=preconnect>` in each page's <head> lets the fonts CSS fetch race the HTML body parse, and warms the TLS handshake to gstatic.com so woff2 requests don't pay DNS+TLS at request time. A shared `font-stylesheet.astro` keeps the four-family URL canonical across all five entry points (index, sub-page-layout, plugins/index, plugins/[slug], blog/index, blog/[slug]). og.astro already had this treatment.
66 lines
2.4 KiB
TypeScript
66 lines
2.4 KiB
TypeScript
const R2_PUBLIC_ORIGIN = 'https://static.open-design.ai';
|
||
const IMAGE_RESIZING_ORIGIN = R2_PUBLIC_ORIGIN;
|
||
const ASSET_PREFIX = 'landing/assets';
|
||
|
||
type ImageOptions = {
|
||
width: number;
|
||
quality?: number;
|
||
};
|
||
|
||
export function r2Asset(name: string): string {
|
||
return `${R2_PUBLIC_ORIGIN}/${ASSET_PREFIX}/${name}`;
|
||
}
|
||
|
||
export function imageAsset(name: string, { width, quality = 85 }: ImageOptions): string {
|
||
const options = `width=${width},quality=${quality},format=auto`;
|
||
return `${IMAGE_RESIZING_ORIGIN}/cdn-cgi/image/${options}/${r2Asset(name)}`;
|
||
}
|
||
|
||
/**
|
||
* Build a responsive `srcset` value. Each width gets its own Cloudflare
|
||
* Image Resizing variant; the browser picks the closest match to
|
||
* `sizes × devicePixelRatio`.
|
||
*
|
||
* Why this exists: a single 1024-wide variant was hurting both ends —
|
||
* retina desktops repaint when a higher-DPR copy arrives (LCP P99 long
|
||
* tail), and phones download more bytes than they need.
|
||
*/
|
||
export function imageAssetSrcset(
|
||
name: string,
|
||
widths: number[],
|
||
quality = 82,
|
||
): string {
|
||
return widths
|
||
.map((width) => `${imageAsset(name, { width, quality })} ${width}w`)
|
||
.join(', ');
|
||
}
|
||
|
||
export const heroImage = imageAsset('hero.png', { width: 1280, quality: 82 });
|
||
|
||
/**
|
||
* Responsive srcset for the homepage hero. Widths cover phones (768),
|
||
* laptops at 1x (1280), retina laptops (1920) and 4K / 2x retina (2560).
|
||
*/
|
||
export const heroImageSrcset = imageAssetSrcset(
|
||
'hero.png',
|
||
[768, 1280, 1920, 2560],
|
||
);
|
||
|
||
/**
|
||
* Default Open Graph card image. Used by every page that doesn't supply
|
||
* its own hero (most blog posts in the v1 layout). 1200 wide is what most
|
||
* social platforms render at; aspect ratio is whatever hero.png ships with
|
||
* — we omit explicit og:image:width/height so platforms can resolve it.
|
||
*/
|
||
export const ogDefaultImage = imageAsset('hero.png', { width: 1200, quality: 86 });
|
||
|
||
/**
|
||
* 1×1 transparent SVG used as the initial `src` for precise-lazyloaded
|
||
* `<img>` elements. Inline data URI (~120 bytes) so it parses zero-RTT
|
||
* regardless of cache state. The real image URL lives in
|
||
* `data-precise-src` and is swapped in by the global IntersectionObserver
|
||
* script (`precise-lazyload.astro`) once the element enters the rootMargin
|
||
* window.
|
||
*/
|
||
export const PRECISE_LAZY_PLACEHOLDER =
|
||
'data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201%201%22%2F%3E';
|