From 6364988f0f152302fb86dabd0ec0efc57f38b189 Mon Sep 17 00:00:00 2001 From: lfirmin Date: Sat, 28 Feb 2026 20:22:24 +0100 Subject: [PATCH] patch perf n1 --- index.html | 25 +++++++---- public/.htaccess | 63 ++++++++++++++++++++++++--- public/favicon.ico | Bin 0 -> 16958 bytes src/components/ComparisonSection.jsx | 6 +-- src/components/Footer.jsx | 12 ++--- src/components/GuideSection.jsx | 8 ++-- src/components/MutuelleCard.jsx | 2 + 7 files changed, 89 insertions(+), 27 deletions(-) create mode 100644 public/favicon.ico diff --git a/index.html b/index.html index 52f2ca1..6ab7832 100644 --- a/index.html +++ b/index.html @@ -1,17 +1,24 @@ - + - - - - - - - - AssurezMoi — Comparateur de mutuelles santé + + + + + + + + + + + + + + +
diff --git a/public/.htaccess b/public/.htaccess index 2830860..49a19eb 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -7,28 +7,79 @@ Options -Indexes Deny from all -# ─── Bloquer l'accès direct aux fichiers cachés (.htaccess, .env, etc.) ───── +# ─── Bloquer l'accès direct aux fichiers cachés ────────────────────────────── Order allow,deny Deny from all -# ─── Headers de sécurité ───────────────────────────────────────────────────── +# ─── Cache long terme pour assets statiques (hachés par Vite) ─────────────── + + ExpiresActive On + + # HTML → toujours revalider + ExpiresByType text/html "access plus 0 seconds" + + # JS / CSS (noms hachés par Vite → 1 an) + ExpiresByType application/javascript "access plus 1 year" + ExpiresByType text/javascript "access plus 1 year" + ExpiresByType text/css "access plus 1 year" + + # Images + ExpiresByType image/webp "access plus 1 year" + ExpiresByType image/png "access plus 1 year" + ExpiresByType image/jpeg "access plus 1 year" + ExpiresByType image/svg+xml "access plus 1 year" + ExpiresByType image/x-icon "access plus 1 year" + ExpiresByType image/vnd.microsoft.icon "access plus 1 year" + + # Vidéo + ExpiresByType video/mp4 "access plus 1 year" + ExpiresByType video/webm "access plus 1 year" + + # Polices + ExpiresByType font/woff2 "access plus 1 year" + ExpiresByType font/woff "access plus 1 year" + + # JSON (données dynamiques → courte durée) + ExpiresByType application/json "access plus 1 hour" + + + # Assets immutables (Vite génère des noms hachés) + + Header set Cache-Control "public, max-age=31536000, immutable" + + + # HTML → pas de cache + + Header set Cache-Control "no-cache, no-store, must-revalidate" + Header set Pragma "no-cache" + + + # JSON → courte durée + + Header set Cache-Control "public, max-age=3600, must-revalidate" + + + # Headers de sécurité Header always set X-Content-Type-Options "nosniff" Header always set X-Frame-Options "SAMEORIGIN" Header always set Referrer-Policy "strict-origin-when-cross-origin" -# ─── SPA routing (React Router / Vite) ────────────────────────────────────── +# ─── Compression gzip ──────────────────────────────────────────────────────── + + AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json + AddOutputFilterByType DEFLATE image/svg+xml font/woff2 font/woff + + +# ─── SPA routing (React / Vite) ────────────────────────────────────────────── RewriteEngine On RewriteBase / - # Ne pas réécrire les fichiers et dossiers existants RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d - - # Tout le reste → index.html RewriteRule ^ index.html [L] diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7a337d1719fc1fe4c1f66b7d36a244f99dc6f4d1 GIT binary patch literal 16958 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 literal 0 HcmV?d00001 diff --git a/src/components/ComparisonSection.jsx b/src/components/ComparisonSection.jsx index ab8278e..d54c9e9 100644 --- a/src/components/ComparisonSection.jsx +++ b/src/components/ComparisonSection.jsx @@ -105,7 +105,7 @@ export default function ComparisonSection() { @@ -140,7 +140,7 @@ export default function ComparisonSection() { key={m.rang} initial={{ opacity: 0, y: 24 }} whileInView={{ opacity: 1, y: 0 }} - viewport={{ once: false }} + viewport={{ once: true }} transition={{ delay: i * 0.1, duration: 0.45 }} > @@ -162,7 +162,7 @@ export default function ComparisonSection() { key={m.rang} initial={{ opacity: 0, x: -16 }} whileInView={{ opacity: 1, x: 0 }} - viewport={{ once: false }} + viewport={{ once: true }} transition={{ delay: i * 0.06, duration: 0.4 }} > diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx index 031cac5..588d4fb 100644 --- a/src/components/Footer.jsx +++ b/src/components/Footer.jsx @@ -33,7 +33,7 @@ export default function Footer() { @@ -41,6 +41,8 @@ export default function Footer() { AssurezMoi @@ -70,7 +72,7 @@ export default function Footer() {

@@ -95,7 +97,7 @@ export default function Footer() {

@@ -120,7 +122,7 @@ export default function Footer() {

@@ -142,7 +144,7 @@ export default function Footer() { diff --git a/src/components/GuideSection.jsx b/src/components/GuideSection.jsx index 13adee9..1f9984c 100644 --- a/src/components/GuideSection.jsx +++ b/src/components/GuideSection.jsx @@ -78,7 +78,7 @@ export default function GuideSection({ bgSrc }) { @@ -99,7 +99,7 @@ export default function GuideSection({ bgSrc }) { key={i} initial={{ opacity: 0, y: 12 }} whileInView={{ opacity: 1, y: 0 }} - viewport={{ once: false }} + viewport={{ once: true }} transition={{ delay: i * 0.07, duration: 0.4 }} > @@ -115,7 +115,7 @@ export default function GuideSection({ bgSrc }) { @@ -144,7 +144,7 @@ export default function GuideSection({ bgSrc }) { diff --git a/src/components/MutuelleCard.jsx b/src/components/MutuelleCard.jsx index 747eabe..f27cb4d 100644 --- a/src/components/MutuelleCard.jsx +++ b/src/components/MutuelleCard.jsx @@ -19,6 +19,8 @@ export function LogoMutuelle({ mutuelle, className = '' }) { setFaviconError(true)} />