Optimisez les performances de votre site

À la fin du chapitre précédent, vous avez externalisé vos données dans des fichiers JSON et créé des pages dynamiques pour vos projets et formations. Votre portfolio fonctionne parfaitement. Mais si vous ouvrez les outils de développement de votre navigateur et regardez l'onglet Network, vous remarquerez que :

  • Vos images se chargent sans optimisation… Les images Placeholder de placehold.co pèsent quelques kilooctets, mais imaginez avec de vraies photos de projets en haute résolution : plusieurs mégaoctets par image ! 

  • Votre police par défaut n'est pas optimisée, ce qui peut créer un flash de texte non stylé lors du chargement.

Dans ce chapitre, vous allez découvrir deux fonctionnalités puissantes de Next.js qui vont transformer les performances de votre portfolio :

  1. Image  pour l'optimisation automatique des images,

  2. next/font  pour des polices ultra-rapides. 

Comprenez le problème des images classiques

Actuellement, votre code utilise la balise HTML standard  <img>  :

<img 
  src={project.image} 
  alt={project.title}
  className={styles.image}
/>

Cette approche fonctionne, mais elle présente plusieurs problèmes de performance :

  • Taille non optimisée : L'image est chargée dans sa taille originale, même si elle est affichée en plus petit. Une image de 3000x2000 pixels sera téléchargée même si elle n'est affichée qu'en 400x300.

  • Format non adapté : L'image est servie dans son format d'origine (JPG, PNG), alors que des formats modernes comme WebP sont 30% plus légers.

  • Chargement non optimisé : Toutes les images se chargent immédiatement, même celles qui ne sont pas visibles à l'écran.

  • Cumulative Layout Shift (CLS) : Sans dimensions définies, la page "saute" quand l'image se charge, ce qui est agaçant pour l'utilisateur.

C'est exactement ce que le composant Image de Next.js résout automatiquement !

Utilisez le composant Image de Next.js

Le composant  Image  est une version améliorée de  <img>  qui optimise automatiquement vos images. Modifiez  app/projets/page.js  :

import Link from 'next/link'
import Image from 'next/image'
import styles from './page.module.css'
import projectsData from '@/data/projects.json'
import Tag from '@/components/Tag/Tag'

export default function Projects() {
    return (
        <div className={styles.container}>
            {/* …… */}
            <Image
                src={project.image}
                alt={project.title}
                width={800}
                height={500}
                className={styles.image}
             />
            {/* …… */}
         </div>
         )
}

Il y a deux changements importants :

  1. Import du composant :  import Image from 'next/image'  au lieu d'utiliser  <img>

  2. Propriétés  width  et  height : Elles sont obligatoires ! Next.js en a besoin pour calculer le ratio d'aspect et éviter le layout shift. Ces valeurs correspondent aux dimensions originales de l'image (ici 800x500 pour nos placeholders), pas à la taille d'affichage finale.

Faites la même modification dans  app/projets/[slug]/page.js  :

import Link from 'next/link'
import Image from 'next/image'
import { notFound } from 'next/navigation'
import Tag from './../../../components/Tag/Tag'
import styles from './page.module.css'
import projectsData from '@/data/projects.json'

export default async function ProjectDetail({ params }) {
    const { slug } = await params
    const project = projectsData.find(p => p.slug === slug)

    if (!project) {
        notFound()
    }

    return (
        <div className={styles.container}>
            {/* … */}
            <Image
               src={project.image}
               alt={project.title}
               width={800}
               height={500}
               className={styles.image}
               preload={true}
             />
         </div>
         {/* … */}
    )
}

Remarquez l'ajout de la propriété  preload={true}  sur l'image de détail. Cette prop indique à Next.js que cette image est importante et doit être chargée en priorité, car elle est visible immédiatement quand l'utilisateur arrive sur la page.

Avant de tester votre code il vous faudra faire un dernier changement si vous utilisez comme moi des images qui proviennent de sources externes. Allez dans  next.config.mjs  et modifiez cela : 

/** @type {import('next').NextConfig} */
const nextConfig = {
 /* config options here */
 images: {
   remotePatterns: [
     {
       protocol: 'https',
       hostname: 'placehold.co',
     },
     {
       protocol: 'https',
       hostname: 'oc-static.imgix.net',
     },
   ],
 },
};

export default nextConfig;

Ici nous ajoutons à la configuration de Next les domaines que nous autorisons à charger des images sur notre site. Ici nous avons laissé un remote pattern simple mais il existe plusieurs options pour ces patterns.

Testez : Rechargez vos pages de projets. Visuellement, rien ne change, mais si vous ouvrez l'inspecteur et regardez les requêtes réseau, vous verrez que Next.js a automatiquement optimisé les images !

Utilisez des images locales

Pour un portfolio professionnel, vous voudrez utiliser vos propres images plutôt que des placeholders. Créez un dossier  public/images/projets  à la racine de votre projet.

Le dossier public est spécial dans Next.js : tout ce qui s'y trouve est accessible publiquement. Par exemple, un fichier  public/images/logo.png  sera accessible à l'URL  /images/logo.png.

Pour l'instant, gardons les placeholders dans le JSON, mais sachez que pour utiliser des images locales, vous modifieriez simplement le chemin dans  data/projects.json :

{
  "id": 1,
  "slug": "taskflow-app",
  "title": "TaskFlow",
  "image": "/images/taskflow.jpg",
  ...
}

Le composant  Image  fonctionnerait exactement de la même manière ! La seule différence : Next.js optimiserait automatiquement vos images locales au moment du build, ce qui est encore plus rapide.

Ajoutez des polices Google Fonts optimisées

Maintenant que vos images sont optimisées, passons aux polices ! Actuellement, votre site utilise les polices par défaut du navigateur. Ajoutons une belle police moderne qui donnera un aspect professionnel à votre portfolio.

Next.js propose  next/font  , un système qui télécharge les polices au moment du build et les sert directement depuis votre serveur. Résultat : pas de requête externe vers Google Fonts, pas de flash de texte non stylé, et des performances optimales !

Modifiez  app/layout.js  :

import { Inter, Poppins } from 'next/font/google'
import "./globals.css"
import Navigation from '../components/Navigation/Navigation'
import Footer from '../components/Footer/Footer'

// Configurer Inter pour le texte courant
const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
})

// Configurer Poppins pour les titres
const poppins = Poppins({
  weight: ['400', '600', '700'],
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-poppins',
})

export const metadata = {
  title: "Portfolio d'Aurélien",
  description: "Développeur web passionné par React et Next.js",
}

export default function RootLayout({ children }) {
  return (
    <html lang="fr" className={`${inter.variable} ${poppins.variable}`}>
      <body className={inter.className}>
        <Navigation />
        <main>{children}</main>
        <Footer />
      </body>
    </html>
  )
}

Que se passe-t-il ici ?

1. Import des polices :  next/font/google  vous donne accès à toutes les Google Fonts directement dans votre code.

2. Configuration :

  • subsets: ['latin'] télécharge uniquement les caractères dont vous avez besoin

  • display: 'swap' affiche le texte avec une police par défaut en attendant le téléchargement (évite le texte invisible)

  • variable: '--font-inter' crée une variable CSS personnalisée pour utiliser la police

3. Application :

  • Sur<html>: Les variables CSS sont disponibles partout

  • Sur<body>: Inter est la police par défaut pour tout le texte

Maintenant, ajoutez les styles pour utiliser Poppins sur les titres. Dans  app/globals.css, ajoutez :

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-poppins), sans-serif;
  font-weight: 700;
}

body {
  font-family: var(--font-inter), sans-serif;
  font-weight: 400;
  line-height: 1.6;
}

Testez : Rechargez votre page, les polices sont maintenant appliquées ! Regardez l'onglet Network de vos outils de développement : les polices sont servies directement depuis votre serveur, pas depuis Google. C'est plus rapide et plus sécurisé !

Améliorez vos metadata pour le SEO

Vous avez déjà des metadata de base dans votre  layout.js, mais chaque page devrait avoir ses propres metadata optimisées pour le SEO. Ajoutons des metadata personnalisées à vos pages de projets.

Modifiez  app/projets/page.js:

import Link from 'next/link'
import Image from 'next/image'
import styles from './page.module.css'
import projectsData from '@/data/projects.json'
import Tag from '@/components/Tag/Tag'

export const metadata = {
  title: 'Mes Projets | Portfolio',
  description: 'Découvrez mes projets de développement web : applications React, sites Next.js et plus encore.',
}

export default function Projects() {
    // ... reste du code inchangé
}

Pour les pages dynamiques, utilisez generateMetadatadansapp/projets/[slug]/page.js:

import Link from 'next/link'
import Image from 'next/image'
import { notFound } from 'next/navigation'
import Tag from './../../../components/Tag/Tag'
import styles from './page.module.css'
import projectsData from '@/data/projects.json'

export async function generateMetadata({ params }) {
    const { slug } = await params
    const project = projectsData.find(p => p.slug === slug)

    if (!project) {
        return {
            title: 'Projet non trouvé',
        }
    }

    return {
        title: `${project.title} | Portfolio`,
        description: project.longDescription,
        openGraph: {
            title: project.title,
            description: project.shortDescription,
            images: [project.image],
        },
    }
}
export default async function ProjectDetail({ params }) {
    // ... reste du code inchangé
}

export function generateStaticParams() {
    return projectsData.map((project) => ({
        slug: project.slug,
    }))
}

La fonction  generateMetadata  est appelée automatiquement par Next.js avant de rendre la page. Elle peut être asynchrone et a accès aux mêmes params que votre composant. Ici, nous créons des metadata personnalisées pour chaque projet !

Testez : Visitez une page de projet et affichez le code source (clic droit > Afficher le code source). Vous verrez les balises  <meta>  dans le  <head>  avec les informations de votre projet !

Comprenez les Core Web Vitals

Google utilise trois métriques principales pour évaluer la performance d'un site web. Ces métriques s'appellent les Core Web Vitals et influencent directement votre référencement :

  1. LCP (Largest Contentful Paint) : Temps avant que le plus gros élément visible soit affiché. Doit être inférieur à 2,5 secondes.

  2. FID (First Input Delay) : Temps avant que l'utilisateur puisse interagir avec la page. Doit être inférieur à 100 millisecondes.

  3. CLS (Cumulative Layout Shift) : Stabilité visuelle de la page.

La bonne nouvelle ? Next.js optimise automatiquement ces trois métriques avec :

  • Le composantImagequi évite le CLS en définissant les dimensions

  • next/fontqui évite le flash de texte (CLS)

  • La génération statique qui rend le LCP ultra-rapide

  • L'optimisation du code JavaScript qui améliore le FID

À vous de jouer !

Avant de passer au chapitre suivant, appliquez ce que vous avez appris !

  1. Remplacez les <img> par le composantImagedansapp/formations/[slug]/page.js

  2. Ajoutez des metadata personnalisées pour la page de liste des formations, et chaque page de détail de formation (avec  generateMetadata)

  3. Ajoutez des images locales pour au moins une formation dans  public/images/formations/ 

Conseils :

  • Pour les images de formations sans photo, vous pouvez utiliser des icônes ou des illustrations représentant l'école ou le sujet.

  • Les dimensions width et heightdoivent correspondre aux dimensions réelles de vos images.

  • N'oubliez pas d'ajouter un altdescriptif pour l'accessibilité.

  • Pour les metadata, pensez aux mots-clés pertinents pour le SEO.

En résumé

  • Le composant  Imagepermet une optimisation automatique des images (format, taille, lazy loading)

  • Avec next/font, les polices Google Fonts optimisées et servies localement. On peut utiliser des polices via des variables CSS personnalisées.

  • openGraph  permet une optimisation du partage sur les réseaux sociaux.

Avant ces optimisations

Après ces optimisations

  • Images de plusieurs Mo chargées en pleine taille

  • Polices téléchargées depuis Google (requête externe)

  • Metadata génériques pour toutes les pages

  • Layout shift quand les images se chargent

  • Score Lighthouse autour de 60-70

  • Images optimisées automatiquement (WebP, dimensions adaptées)

  • Polices servies localement (0 requête externe)

  • Metadata SEO-friendly pour chaque page

  • Pas de layout shift (dimensions définies)

  • Score Lighthouse de 90+ facilement

Dans le prochain chapitre, vous allez déployer votre portfolio en production sur Vercel et le rendre accessible au monde entier !

Et si vous obteniez un diplôme OpenClassrooms ?
  • Formations jusqu’à 100 % financées
  • Date de début flexible
  • Projets professionnalisants
  • Mentorat individuel
Trouvez la formation et le financement faits pour vous