ITSkillsCenter
Business Digital

Démarrer React Three Fiber v9 avec Vite et TypeScript

13 min de lecture

📍 Article principal de la série : Three.js, React Three Fiber et WebGPU en 2026 : 3D temps réel sur le web
Pour la vue d’ensemble du moteur, du renderer WebGPU et du langage TSL, lire d’abord le guide principal.

Introduction

Avant d’écrire un seul shader ou de charger un modèle 3D, il faut un projet propre. Cette première étape est anodine en apparence et pourtant c’est elle qui détermine la qualité de tout ce qui suit : la rapidité du HMR pendant le développement de shaders, la lisibilité de l’arborescence quand la scène grossit, la facilité à activer WebGPU plus tard. Ce tutoriel monte un projet React Three Fiber v9 avec Vite et TypeScript dans une configuration qui tient en production, et fait tourner un premier rendu pour vérifier que la chaîne complète fonctionne.

Prérequis

  • Node.js 22 LTS (codename Jod) ou supérieur, vérifier avec node --version
  • Un gestionnaire de paquets : npm 10+, pnpm 9+ ou yarn 4+
  • Un navigateur récent : Chrome 122+, Firefox 121+, Safari 26+, Edge 122+
  • Une connaissance de base de React (composants fonctionnels, hooks, JSX) et de TypeScript (types, interfaces)
  • Un éditeur avec support TypeScript (VS Code, WebStorm, Zed)
  • Temps estimé : 25 à 35 minutes

Étape 1 — Créer le projet Vite avec le template React + TypeScript

Vite est devenu le bundler de référence pour les projets React modernes. Sa rapidité de démarrage et son HMR quasi instantané sont précieux pour le travail itératif sur des shaders, où l’on relance la page dix fois par minute. On utilise le template officiel react-ts, qui pré-configure TypeScript avec les bons paramètres pour React 18 et au-delà.

npm create vite@latest mon-projet-r3f -- --template react-ts
cd mon-projet-r3f
npm install

La commande crée un dossier mon-projet-r3f/ contenant un projet React minimal : src/App.tsx avec le compteur d’exemple, src/main.tsx qui monte React dans le DOM, vite.config.ts avec la configuration du bundler, tsconfig.json avec le typage strict activé. Si npm install termine sans erreur, on a un projet TypeScript fonctionnel. On peut le vérifier en lançant npm run dev : Vite ouvre un serveur sur http://localhost:5173 et la page d’accueil React s’affiche. On arrête le serveur avec Ctrl+C avant de continuer.

Étape 2 — Installer React Three Fiber v9 et Drei

L’écosystème R3F repose sur trois paquets dans la quasi-totalité des projets. Le binding R3F lui-même expose le composant <Canvas> et les hooks useThree, useFrame, useLoader. Three.js est le moteur 3D sous-jacent, dépendance directe à mettre en explicite pour contrôler la version. Drei (« trois » en allemand, blague de la communauté) est la collection d’helpers : caméras orbitales, environnements HDRI, shaders prêts à l’emploi, gizmos, debug tools.

npm install three @react-three/fiber @react-three/drei
npm install --save-dev @types/three

Une fois l’installation terminée, le package.json liste three en dépendance directe — c’est important pour que la version reste pinable et que les mises à jour de Three.js ne soient pas dictées par les bumps de R3F. Avec npm list three, on confirme la présence d’une seule version dans le graphe de dépendances. Si npm rapporte plusieurs versions, c’est un signe de conflit qui causera des bugs subtils plus tard ; on les résout via overrides dans le package.json.

Étape 3 — Nettoyer le boilerplate Vite

Le template Vite contient du code d’exemple inutile pour notre cas. On supprime ce qui ne sert pas, pour partir d’une base lisible. Cette opération évite de laisser des fichiers morts qui polluent l’autocomplétion et embrouillent les nouveaux contributeurs au projet.

rm src/App.css src/index.css src/assets/react.svg
# Sous Windows PowerShell : Remove-Item src/App.css, src/index.css, src/assets/react.svg

Ces commandes effacent les feuilles de style de démonstration et l’image SVG de React. Il reste src/main.tsx, src/App.tsx et src/vite-env.d.ts. On édite ensuite src/main.tsx pour retirer l’import CSS désormais cassé : ouvrir le fichier dans son éditeur et supprimer la ligne import './index.css'. Si la commande npm run dev retourne une erreur sur ce fichier après modification, c’est qu’il reste un import cassé à enlever.

Étape 4 — Écrire le premier composant Canvas

On remplace maintenant src/App.tsx par un composant qui monte un <Canvas> R3F avec une scène minimale : un cube tournant éclairé par deux lumières. Cette scène est volontairement simple ; elle prouve que la chaîne complète (Vite, R3F, Three.js) fonctionne et sert de base pour les tutoriels suivants.

// src/App.tsx
import { Canvas, useFrame } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'
import { useRef } from 'react'
import type { Mesh } from 'three'

function SpinningBox() {
  const ref = useRef<Mesh>(null)

  useFrame((_, delta) => {
    if (!ref.current) return
    ref.current.rotation.x += delta * 0.5
    ref.current.rotation.y += delta * 0.7
  })

  return (
    <mesh ref={ref}>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color="#ff6b00" />
    </mesh>
  )
}

export default function App() {
  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <Canvas camera={{ position: [3, 2, 3], fov: 50 }}>
        <ambientLight intensity={0.3} />
        <directionalLight position={[5, 5, 5]} intensity={1.2} />
        <SpinningBox />
        <OrbitControls />
      </Canvas>
    </div>
  )
}

Plusieurs points méritent attention. Le div parent du Canvas doit avoir une hauteur explicite, sinon le Canvas est rendu à zéro pixel et la page paraît vide. Le hook useFrame reçoit en deuxième argument un delta en secondes, qu’on multiplie par la vitesse de rotation pour rester indépendant du framerate — la rotation reste fluide qu’on tourne à 60 fps ou à 144 fps. Le useRef<Mesh> typé donne l’autocomplétion sur rotation, position, scale sans cast manuel.

On lance maintenant npm run dev et on ouvre http://localhost:5173 dans le navigateur. Un cube orange tourne sur fond noir, on peut le faire pivoter à la souris grâce à OrbitControls. Si l’écran reste noir, vérifier la console : une erreur WebGLRenderingContext is not defined indique que le navigateur est trop ancien. Une erreur state is undefined indique un mismatch entre la version de R3F et celle de Three.js.

Étape 5 — Adopter une structure de dossiers évolutive

Tant que la scène tient dans App.tsx, l’organisation est sans importance. Mais dès qu’on ajoute deux ou trois objets complexes, des shaders, des animations, le fichier devient illisible. La structure suivante a fait ses preuves dans les projets R3F sérieux et facilite les évolutions ultérieures.

mkdir -p src/scenes src/components src/hooks src/shaders src/assets

Cette commande crée cinq dossiers thématiques : scenes/ pour les sous-scènes complètes (un fichier par expérience 3D), components/ pour les briques réutilisables (un mesh personnalisé, un composant lumière), hooks/ pour la logique d’animation isolée des hooks personnalisés, shaders/ pour les fichiers TSL ou GLSL, assets/ pour les modèles glTF et les textures KTX2. Cette séparation reflète la séparation des responsabilités évoquée dans le guide principal et rend le code testable indépendamment du rendu.

Étape 6 — Configurer le path alias et l’import de modèles

Les imports relatifs ../../components/SpinningBox deviennent vite illisibles. On configure un alias @/ qui pointe vers src/, à la fois côté Vite et côté TypeScript, pour pouvoir écrire @/components/SpinningBox.

// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'node:path'

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
})

La configuration Vite est faite, mais TypeScript ne sait pas encore résoudre l’alias. Il faut compléter tsconfig.json :

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

Après redémarrage du serveur de dev, l’autocomplétion de l’éditeur reconnaît @/components/.... Si l’éditeur souligne encore les imports en rouge, recharger la fenêtre TypeScript (commande VS Code : TypeScript: Restart TS Server). Les imports relatifs profonds disparaissent et la lisibilité progresse nettement à mesure que le projet grossit.

Étape 7 — Activer Strict Mode et les outils de debug

React 19 conserve le StrictMode qui double-monte les composants en développement pour traquer les effets de bord. Avec R3F, ce double-mount peut causer des doubles inscriptions dans useFrame ou des fuites de ressources Three.js mal nettoyées. La règle est de toujours nettoyer dans le retour du useEffect et de ne jamais muter d’état Three.js dans le corps direct du composant.

Pour le debug visuel, Drei fournit deux helpers indispensables : <Stats /> qui affiche FPS/MS/MB en overlay, et <axesHelper> qui matérialise les axes X (rouge), Y (vert), Z (bleu). On les ajoute dans App.tsx en développement uniquement :

import { Stats } from '@react-three/drei'

// Dans le Canvas, juste avant le retour :
{import.meta.env.DEV && (
  <>
    <Stats />
    <axesHelper args={[2]} />
  </>
)}

Le test import.meta.env.DEV est résolu par Vite à la compilation et tree-shake intégralement le code en build de production. On garde ses outils de debug à portée de main sans alourdir le bundle livré aux utilisateurs finaux. Au lancement, on doit voir un compteur FPS en haut à gauche et trois axes colorés au centre de la scène.

Étape 8 — Vérification et build de production

La dernière étape vérifie que le projet build correctement, c’est-à-dire que TypeScript ne signale aucune erreur et que le bundle final reste raisonnable. C’est la garantie qu’on peut livrer.

npm run build
npm run preview

La commande build exécute tsc puis vite build. Elle produit un dossier dist/ contenant index.html, le JS bundlé et minifié, et les assets optimisés. La sortie console affiche la taille de chaque fichier ; pour une scène minimale comme celle-ci, on doit obtenir un JS gzippé inférieur à 250 Ko (Three.js compte pour la majeure partie). La commande preview sert le bundle de production sur http://localhost:4173 pour vérifier qu’il fonctionne hors mode dev. Si le cube apparaît identique à celui du dev server, le projet est prêt à recevoir les composants des tutoriels suivants.

Étape 9 — Configurer les scripts de qualité

Un projet 3D web sérieux a besoin de scripts qui détectent les problèmes avant qu’ils n’arrivent en production. Trois outils complètent le couple Vite + TypeScript : ESLint pour la qualité du code, Prettier pour le formatage, et un script de typecheck séparé qui ne dépend pas du build complet. Le template Vite installe ESLint par défaut, on enrichit la configuration pour y ajouter les règles propres à React et à React Hooks.

npm install --save-dev eslint-plugin-react-hooks prettier eslint-config-prettier

On édite ensuite le package.json pour exposer trois scripts : typecheck qui appelle tsc --noEmit et signale toute erreur de types sans produire de fichier, lint qui exécute ESLint sur l’ensemble du projet, et format qui applique Prettier en place. Ces commandes deviennent les portes d’entrée de la CI quand on aura un dépôt distant.

{
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "preview": "vite preview",
    "typecheck": "tsc --noEmit",
    "lint": "eslint .",
    "format": "prettier --write \"src/**/*.{ts,tsx,css,json}\""
  }
}

Lancer npm run typecheck à la fin de chaque session de travail et npm run lint avant chaque commit attrape la majorité des bugs avant qu’ils n’apparaissent dans le rendu 3D. Une erreur de typecheck silencieuse sur un useRef<Mesh> mal typé peut prendre une heure à diagnostiquer si on la découvre à l’exécution. C’est l’investissement de cinq minutes qui fait gagner des heures sur la durée du projet.

Étape 10 — Préparer le projet pour Git et un dépôt distant

Le template Vite initialise déjà un .gitignore correct, mais il faut vérifier que node_modules, dist, les fichiers .env.local et les caches de l’éditeur sont bien exclus. On veut commiter le code source et la configuration, jamais les artéfacts de build ni les secrets. Un git status initial doit montrer une trentaine de fichiers maximum, tous dans src/, à la racine ou dans public/.

git init
git add .
git commit -m "init: vite + react + r3f baseline"

Avant de pousser sur un dépôt distant, on vérifie qu’aucun fichier suspect n’est inclus. La commande git ls-files | head -40 liste les premiers fichiers suivis. Si elle remonte du .env ou un dossier dist/, on les retire avec git rm --cached et on les ajoute au .gitignore. Cette discipline initiale évite les fuites accidentelles de configuration sensible plus tard, quand on intégrera des clés d’API pour des services tiers comme un CMS ou une analytics.

Erreurs fréquentes

Erreur Cause Solution
Canvas vide, page blanche Conteneur parent sans hauteur Donner height: '100vh' ou un parent avec hauteur fixe
R3F: Hooks can only be used within the Canvas component useFrame appelé hors d’un descendant de <Canvas> Déplacer le composant à l’intérieur du Canvas
Multiple versions de Three.js Drei ou autre paquet a sa propre version npm dedupe ou overrides dans package.json
HMR cassé sur les shaders Vite ne sait pas invalider les fichiers .glsl Plugin vite-plugin-glsl ou import en string brute
Cannot find module '@/...' Alias pas reflété dans tsconfig.json Ajouter baseUrl et paths et redémarrer TS server

Tutoriels frères

Dans la continuité

FAQ

Pourquoi Vite et pas Next.js ?
Pour un projet 3D pur côté client, Vite est plus rapide en HMR et plus simple à configurer. Next.js a sa place quand on a besoin de SSR pour la partie 2D du site et qu’on monte la scène 3D dans une page 'use client'. Les deux sont valides selon le contexte.

Faut-il TypeScript pour faire du R3F ?
Pas obligatoire mais fortement recommandé. Three.js a une API riche et l’autocomplétion typée évite des heures de lecture de documentation. Les types @types/three sont à jour avec la version courante.

Quelle différence entre useRef et useState pour un mesh ?
useRef conserve une référence mutable sans déclencher de re-render. C’est ce qu’il faut pour les animations continues. useState déclenche un re-render à chaque setState, ce qui est très coûteux pour de l’animation à 60 fps. Règle simple : useState pour les changements discrets (ouvert/fermé), useRef pour les changements continus (rotation, position).

Le Strict Mode pose-t-il problème avec R3F ?
Pas si les composants sont propres. Le double-mount révèle les ressources Three.js non disposées et les useEffect sans cleanup. Il faut le voir comme un outil de qualité plutôt qu’un obstacle. La documentation R3F détaille les patterns sûrs.

Comment ajouter du HTML par-dessus le Canvas ?
Pour de l’UI superposée, on positionne un div en position: absolute par-dessus le Canvas. Pour des labels 3D liés à des objets de la scène, le composant <Html> de Drei projette automatiquement les coordonnées 3D vers du DOM. Les deux approches cohabitent dans le même projet.

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité