perf(landing): inline critical CSS + preload latin woff2
All checks were successful
Build & Deploy Landing / build-and-deploy (push) Successful in 59s

Élimine ~130 ms du critical path LCP rapportés par l'audit Lighthouse :

- `build.inlineStylesheets: "always"` dans astro.config.mjs : la
  feuille `_astro/Layout.<hash>.css` (~42 KiB) n'est plus une requête
  séparée render-blocking, elle est inlinée dans le HTML. Coût : +42 KiB
  par page prerenderée (≈10 KiB gzippé sur la wire). Gain : 80 ms FCP.
  `"auto"` aurait été ignoré (Layout.css > 4 KiB du seuil interne).

- `<link rel="preload">` sur les 2 woff2 latin (Inter body + Bricolage
  Grotesque display) dans Layout.astro. Casse la chaîne HTML→CSS→fonts
  du network dependency tree (~50 ms gagnés). URLs résolues via Vite
  `?url` import → hashing préservé entre les builds.

On ne preload que latin-wght-normal — les autres subsets (latin-ext,
vietnamese, cyrillic, greek) sont chargés à la demande et ne valent
pas le poids upfront pour un trafic FR/latin.

Vérifié build : `<link rel="stylesheet">` disparu du HTML rendu, 1
seul `<style>` inline présent, 2 `<link rel="preload">` avec les bons
hashes d'asset.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
ordinarthur 2026-05-09 18:45:06 +02:00
parent eda5436d12
commit 6993d80089
2 changed files with 42 additions and 0 deletions

View File

@ -26,6 +26,26 @@ export default defineConfig({
integrations: [ integrations: [
react(), react(),
], ],
build: {
/**
* Inline TOUS les <link rel="stylesheet"> dans le HTML. Élimine 80 ms
* de render-blocking sur le critical path LCP en faisant disparaître
* la requête `/_astro/Layout.<hash>.css` (~42 KiB) du chemin critique
* cf. audit Lighthouse render-blocking-resources.
*
* Tradeoff assumé : le HTML pèse +42 KiB par page (mais ~10 KiB
* gzippé) au lieu d'avoir une feuille séparée cacheable. Pour une
* landing à 5 pages prerendered c'est négligeable, et sur SSR le
* gain LCP est plus important que la mutualisation cross-page (le
* cache HTTP côté Traefik garde déjà les pages prêtes).
*
* `"auto"` aurait été plus conservateur mais le seuil par défaut
* (`vite.build.assetsInlineLimit` = 4 KiB) est inférieur à la taille
* de Layout.css la feuille restait externe et le render-blocking
* persistait.
*/
inlineStylesheets: "always",
},
vite: { vite: {
plugins: [tailwindcss()], plugins: [tailwindcss()],
}, },

View File

@ -14,6 +14,20 @@ import "../styles/app.css";
import { SiteHeader } from "../components/SiteHeader"; import { SiteHeader } from "../components/SiteHeader";
import { SiteFooter } from "../components/SiteFooter"; import { SiteFooter } from "../components/SiteFooter";
/**
* URLs hashées (au build) des deux woff2 latin que la quasi-totalité du
* contenu utilise — Inter (body) + Bricolage Grotesque (display). Le
* suffix `?url` Vite retourne le path final après hashing, donc le
* preload reste valide même après un rebuild qui change le hash.
*
* Préchargées en HEAD pour casser la chaîne `HTML → CSS → fonts` du
* critical path (cf. audit Lighthouse network-dependency-tree, ~50 ms
* gagnés sur le LCP). On NE preload PAS les latin-ext / vietnamese /
* cyrillic / greek : poids inutile pour 99% du trafic FR/latin.
*/
import interLatinWoff2 from "@fontsource-variable/inter/files/inter-latin-wght-normal.woff2?url";
import bricolageLatinWoff2 from "@fontsource-variable/bricolage-grotesque/files/bricolage-grotesque-latin-wght-normal.woff2?url";
const SITE_URL = "https://rubis.pro"; const SITE_URL = "https://rubis.pro";
/** /**
@ -105,6 +119,14 @@ const jsonLdArray = jsonLd ? (Array.isArray(jsonLd) ? jsonLd : [jsonLd]) : [];
<meta name="twitter:description" content={description} /> <meta name="twitter:description" content={description} />
<meta name="twitter:image" content={resolvedOgImage} /> <meta name="twitter:image" content={resolvedOgImage} />
{/* Preload des fonts critiques (latin uniquement) — coupe la chaîne
HTML→CSS→woff2 en faisant démarrer le téléchargement au plus tôt.
crossorigin="anonymous" est obligatoire pour matcher la requête
woff2 que Vite émet derrière (sans cred), sinon le browser refait
un round-trip et le preload est ignoré. */}
<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous" href={interLatinWoff2} />
<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous" href={bricolageLatinWoff2} />
{/* Favicons */} {/* Favicons */}
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png" /> <link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png" />