Ce que vous saurez faire
- Comprendre LCP, INP, CLS
- Mesurer avec Lighthouse et web-vitals
- Optimiser chaque métrique
- Monitoring RUM continu
Étape 1 — Les 3 métriques
LCP Largest Contentful Paint < 2.5s
Temps d'affichage de l'élément principal
INP Interaction to Next Paint < 200ms
Réactivité aux interactions
CLS Cumulative Layout Shift < 0.1
Stabilité visuelle (pas de décalages)
Étape 2 — Mesurer avec Lighthouse
npx lighthouse https://example.sn --only-categories=performance --view
# Audit plus proche réalité
npx lighthouse https://example.sn --preset=desktop \
--throttling.cpuSlowdownMultiplier=4
Étape 3 — web-vitals pour RUM
// Dans index.html
import {onCLS, onINP, onLCP} from 'web-vitals';
function send(metric) {
navigator.sendBeacon('/api/vitals', JSON.stringify({
name: metric.name,
value: metric.value,
id: metric.id,
url: location.href,
}));
}
onCLS(send);
onINP(send);
onLCP(send);
Étape 4 — Optimiser LCP
<!-- Précharger l'image LCP -->
<link rel="preload" as="image"
href="/wp-content/uploads/hero.avif"
fetchpriority="high"
imagesrcset="/hero-800.avif 800w, /hero-1600.avif 1600w"
imagesizes="100vw">
<!-- Image LCP: PAS de lazy -->
<img src="hero.webp" fetchpriority="high" alt="..." width="1200" height="600">
Étape 5 — WebP/AVIF
apt install -y webp libheif-examples
for f in *.{jpg,png}; do
cwebp -q 82 "$f" -o "${f%.*}.webp"
heif-enc -q 55 "$f" -o "${f%.*}.avif"
done
Étape 6 — Optimiser INP
// Mauvais: bloque UI
function calculerGros() {
for (let i = 0; i < 1000000; i++) { /* ... */ }
}
// Bon: scheduler.postTask
async function calculerChunk() {
const scheduler = window.scheduler;
for (let i = 0; i < 10; i++) {
await scheduler.postTask(() => {
for (let j = 0; j < 100000; j++) { /* ... */ }
}, { priority: 'background' });
}
}
<!-- Différer JS non critique -->
<script src="/chat.js" defer></script>
<script src="/analytics.js" async></script>
Étape 7 — Optimiser CLS
<!-- TOUJOURS width + height -->
<img src="photo.webp" width="1200" height="800" alt="...">
<!-- Embeds: container fixe -->
<style>
.ad-slot { min-height: 250px; display: grid; place-items: center; }
img { aspect-ratio: attr(width) / attr(height); height: auto; max-width: 100%; }
</style>
<!-- Fonts: swap ou optional -->
<style>
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter.woff2') format('woff2');
font-display: swap;
size-adjust: 100%;
}
</style>
Étape 8 — Lazy native
<img src="galerie.avif" loading="lazy" decoding="async" alt="...">
<iframe src="..." loading="lazy" width="560" height="315"></iframe>
Étape 9 — Picture pour format moderne
<picture>
<source srcset="photo.avif" type="image/avif">
<source srcset="photo.webp" type="image/webp">
<img src="photo.jpg" alt="..." width="1200" height="800" loading="lazy">
</picture>
Étape 10 — Cache serveur + CDN
location ~* \.(avif|webp|jpg|png|svg|css|js|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
Cloudflare activation:
- Auto Minify JS/CSS/HTML
- Brotli
- Tiered Cache
- Cloudflare APO for WordPress (5 USD/mo)
Étape 11 — GitHub Actions Lighthouse CI
name: Perf
on: pull_request
jobs:
lhci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: treosh/lighthouse-ci-action@v12
with:
urls: https://preview.example.sn
configPath: .lighthouserc.json
uploadArtifacts: true
Étape 12 — Monitoring Search Console
Search Console > Expérience > Core Web Vitals. Passage rouge/orange au vert après 2-4 semaines. Cliquez Valider la correction après optim.
Checklist
✓ Images AVIF/WebP + width/height + fetchpriority LCP
✓ Fonts woff2 + swap, 2 max
✓ JS différé ou dynamic import
✓ CSS critique inline, reste différé
✓ Cache 1 an assets versionnés
✓ Brotli activé
✓ CDN avec PoPs Afrique (Cloudflare)
✓ RUM monitoring (web-vitals + GA4)
✓ Lighthouse CI sur chaque PR