Utiliser des bibliothèques React dans Preact avec preact/compat
Utilisez preact/compat pour exécuter des bibliothèques React dans Preact, avec les alias pour Vite, webpack, Rollup, Jest, TypeScript et les cas de panne courants.
preact/compat est une couche de compatibilité, livrée à l’intérieur du package principal preact depuis Preact X, qui projette l’API publique de React sur Preact afin que la plupart des bibliothèques React fonctionnent sans modification, tandis que votre application n’embarque qu’environ 9,5 Ko de framework au lieu du runtime bien plus volumineux de React.
Mettre en place l’alias est l’affaire de cinq minutes. Découvrir trois jours plus tard qu’un date picker lève des erreurs depuis les profondeurs de node_modules, c’est la partie dont personne ne vous prévient. On active la couche en créant un alias de react et react-dom vers preact/compat dans son bundler : aucune modification de code dans vos composants, aucun package supplémentaire à installer. Ce guide vous donne la configuration d’alias exacte pour chaque toolchain majeure, un parcours de migration avec le gain en taille de bundle à la clé, et un état des lieux honnête des bibliothèques qui cassent.
Points clés
preact/compatest livré à l’intérieur du packagepreact. Compat fait désormais partie du cœur, si bien que le package autonomepreact-compatest obsolète et quenpm install preactsuffit.- Tout le mécanisme consiste à créer des alias pour quatre chemins d’import :
react,react-dom,react-dom/test-utilsetreact/jsx-runtimepointent tous vers Preact. - Avec
@preact/preset-vite, l’aliasing est automatique : vous n’écrivez donc pasresolve.aliasà la main. - Dans webpack, l’alias
react-domdoit être listé aprèsreact-dom/test-utils, sinon la règle plus large masque le mapping de test-utils. - Compat couvre l’API publique de React, pas ses rouages internes. Les bibliothèques qui vont piocher dans les chemins internes profonds de
react-dom, ou qui dépendent des API React 19 les plus récentes, peuvent toujours casser.
Qu’est-ce que preact/compat, et pourquoi existe-t-il ?
preact/compat traduit la surface d’API publique de React (React.Component, les hooks, createPortal, forwardRef, memo, le runtime JSX) en équivalents Preact, de sorte que les composants tiers écrits pour React soient résolus vers Preact au moment du build. La fiche npm de Preact met en avant une large prise en charge de React derrière un simple alias, et c’est cette compatibilité qui vous permet de réutiliser l’écosystème React sans réécriture.
Il n’y a plus de package preact-compat à installer. Le guide de mise à niveau officiel explique que la couche était autrefois publiée séparément avant d’être intégrée au dépôt principal pour simplifier la coordination : quiconque effectue la montée de version doit donc remplacer les anciens imports et alias preact-compat par preact/compat. Le package non scopé est une voie sans issue : son dépôt GitHub est archivé et en lecture seule depuis décembre 2021, et sa page npm vous invite à le désinstaller, puisque Preact X embarque compat par défaut. Preact 10.x est la ligne stable actuelle, la 11.0.0 étant au stade de release candidate et non en disponibilité générale ; la page des releases de Preact indique les numéros de version exacts.
L’aliasing, c’est toute l’astuce
Discover how at OpenReplay.com.
Tout le mécanisme repose sur l’aliasing : vous faites pointer react, react-dom, react-dom/test-utils et react/jsx-runtime vers Preact, si bien que chaque import existant, y compris ceux des bibliothèques tierces enfouies dans node_modules, est résolu vers preact/compat plutôt que vers React. Rien ne change dans le code de vos composants. Une instruction import { useState } from 'react' reste exactement telle quelle ; c’est le bundler qui réécrit la cible de résolution de react.
Les quatre entrées canoniques, d’après le guide de Preact sur l’aliasing de React vers Preact :
| Chemin d’import | Cible de l’alias | Pourquoi |
|---|---|---|
react | preact/compat | API React de base |
react-dom/test-utils | preact/test-utils | Utilitaires de test |
react-dom | preact/compat | Renderer DOM (doit être placé après test-utils) |
react/jsx-runtime | preact/jsx-runtime | Transformation JSX automatique |
Se contenter d’aliaser react et react-dom, raccourci fréquent dans les tutoriels plus anciens, laisse les bibliothèques qui importent le runtime JSX ou react-dom/test-utils se résoudre vers React, ce qui réintroduit précisément les octets que vous cherchiez à éliminer.
Configuration des alias par toolchain
Vite (choix par défaut recommandé)
Avec @preact/preset-vite, l’aliasing est automatique et vous ne devez pas écrire resolve.alias à la main. Le preset active les alias React pour vous : l’option reactAliasesEnabled les gouverne et vaut true sauf si vous la désactivez. Il configure également la transformation JSX à votre place.
// vite.config.ts
import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';
export default defineConfig({
plugins: [preact()], // JSX + react→preact/compat aliasing handled automatically
});
Si vous utilisez Vite sans le preset, ajoutez la solution de repli manuelle :
export default defineConfig({
resolve: {
alias: {
react: 'preact/compat',
'react-dom/test-utils': 'preact/test-utils',
'react-dom': 'preact/compat',
'react/jsx-runtime': 'preact/jsx-runtime',
},
},
});
Webpack
Dans webpack, l’alias react-dom doit être listé après react-dom/test-utils, sinon la règle react-dom, plus large, masque le mapping de test-utils et les utilitaires de test sont silencieusement résolus vers le mauvais module.
const config = {
resolve: {
alias: {
react: 'preact/compat',
'react-dom/test-utils': 'preact/test-utils',
'react-dom': 'preact/compat', // Must be below test-utils
'react/jsx-runtime': 'preact/jsx-runtime',
},
},
};
Rollup
Installez @rollup/plugin-alias et enregistrez-le avant @rollup/plugin-node-resolve, afin que les réécritures aient lieu avant que Rollup ne résolve les modules.
import alias from '@rollup/plugin-alias';
export default {
plugins: [
alias({
entries: [
{ find: 'react', replacement: 'preact/compat' },
{ find: 'react-dom/test-utils', replacement: 'preact/test-utils' },
{ find: 'react-dom', replacement: 'preact/compat' },
{ find: 'react/jsx-runtime', replacement: 'preact/jsx-runtime' },
],
}),
],
};
Node / Next.js (sans alias de bundler)
Les runtimes Node ignorent les alias de bundler, Next.js compris : l’alias se place donc dans package.json, en utilisant le package publié @preact/compat. Ce package scopé n’existe que pour donner une cible au mécanisme d’aliasing intégré de npm ; son unique rôle est de réexporter preact/compat sans modification. Notez que le @preact/compat scopé n’est pas le preact-compat non scopé et abandonné.
{
"dependencies": {
"react": "npm:@preact/compat",
"react-dom": "npm:@preact/compat"
}
}
Jest
Jest réécrit les chemins de modules via des entrées regex sous moduleNameMapper :
{
"moduleNameMapper": {
"^react$": "preact/compat",
"^react-dom/test-utils$": "preact/test-utils",
"^react-dom$": "preact/compat",
"^react/jsx-runtime$": "preact/jsx-runtime"
}
}
TypeScript
TypeScript résout les types indépendamment de votre bundler : mappez donc les chemins dans tsconfig.json et activez skipLibCheck. Activez skipLibCheck parce qu’une poignée de bibliothèques React s’appuient sur des types que compat ne fournit pas, et qu’un contrôle complet de chaque .d.ts dans node_modules échouerait sur ces déclarations.
{
"compilerOptions": {
"skipLibCheck": true,
"baseUrl": "./",
"paths": {
"react": ["./node_modules/preact/compat/"],
"react/jsx-runtime": ["./node_modules/preact/jsx-runtime"],
"react-dom": ["./node_modules/preact/compat/"],
"react-dom/*": ["./node_modules/preact/compat/*"]
}
}
}
Un parcours de migration minimal
Migrer une application React existante vers Preact avec un outillage moderne se fait en quatre étapes :
- Remplacez les dépendances. Supprimez
react,react-domet leurs@types, puisque Preact fournit ses propres types TypeScript, puis exécuteznpm install preactetnpm install -D @preact/preset-vite. - Ajoutez le preset. Placez
preact()dans vos plugins Vite. Il prend en charge à la fois la transformation JSX et l’aliasreact → preact/compat: vous pouvez donc supprimer toute configuration manuelleesbuild.jsxInject/jsxFactoryhéritée des installations de l’époque Vite 2. - Modifiez le point d’entrée de rendu. Remplacez l’appel de montage de React DOM par le
renderde Preact :
// Before
import ReactDOM from 'react-dom';
ReactDOM.render(<App />, document.getElementById('root'));
// After
import { render } from 'preact';
render(<App />, document.getElementById('root'));
- Buildez et mesurez la taille. Le gain est tout l’enjeu : le cœur de Preact plus
preact/compatatteint environ 9,5 Ko min+gzip, contre plutôt 60 Ko pour React 19 plus React DOM, dont la quasi-totalité dans l’entréereact-dom/client. Pour une application dont les composants passent déjà par compat, cette différence est quasi gratuite.
Quand preact/compat casse-t-il ?
Compat couvre l’API publique de React, pas ses rouages internes. Les bibliothèques qui vont piocher dans les chemins internes privés de react-dom, ou qui s’appuient sur certaines des API plus récentes de React 19, peuvent casser même lorsque l’alias est correct : vérifiez donc chaque dépendance avant la mise en production. Les incohérences de types provenant de bibliothèques typées pour React sont attendues et gérées par skipLibCheck ; ce sont les défaillances à l’exécution qu’il faut surveiller, et les session replays de ces intégrations les font souvent apparaître sous forme d’erreurs console levées depuis l’intérieur d’une dépendance plutôt que depuis votre propre code.
Une rapide vérification préalable avant d’adopter une bibliothèque :
- Faites un grep du package à la recherche d’imports internes profonds
react-dom/, le signal de rupture le plus courant. - Vérifiez les API exclusives à React 19 dont dépend la bibliothèque ; contrôlez leur prise en charge par la version actuelle de Preact plutôt que de la présumer.
- Exécutez la suite de tests de la bibliothèque avec le
moduleNameMapperJest ci-dessus pour détecter tôt les échecs. - Faites un smoke test en développement, en surveillant la console pour repérer les erreurs provenant de la dépendance.
Les utilisateurs de SSR et de frameworks se heurtent à une autre catégorie de problèmes : comme les alias de bundler ne s’appliquent pas dans Node, Next.js et les runtimes similaires ont besoin de l’alias dans package.json, et le chemin ssrLoadModule de Vite peut contourner certaines configurations d’alias. Vérifiez donc que le client comme le serveur se résolvent bien vers preact/compat.
Créez les alias des quatre entrées pour votre toolchain, faites passer les tests de vos dépendances par le même mapping, et vous pourrez réutiliser l’essentiel de l’écosystème React pour une fraction des octets. Les exceptions, en toute honnêteté, sont les bibliothèques couplées aux internes de React plutôt qu’à son API publique. Commencez par ajouter @preact/preset-vite sur une branche et mesurez votre bundle de production avant et après.
FAQ
Quelle est la différence entre @preact/compat et l'ancien package preact-compat ?
Le package scopé @preact/compat est un package npm actif qui réexporte preact/compat ; il sert uniquement à aliaser react via package.json dans les runtimes Node comme Next.js, où les alias de bundler ne s'appliquent pas. Le package non scopé preact-compat est un package différent, archivé, dont le dépôt est en lecture seule depuis décembre 2021 ; il visait Preact 8.x, alors que Preact X embarque désormais compat dans son cœur. N'installez jamais la version non scopée.
Dois-je encore écrire resolve.alias à la main si j'utilise @preact/preset-vite ?
Non. Avec @preact/preset-vite, l'aliasing de react et react-dom vers preact/compat est pris en charge pour vous, gouverné par l'option reactAliasesEnabled, active sauf si vous la désactivez. Ajouter preact() à vos plugins Vite couvre à la fois la transformation JSX et l'aliasing : écrire resolve.alias à la main est donc redondant et peut créer des conflits. Vous n'écrivez le bloc manuel de quatre alias que si vous utilisez Vite sans le preset.
Pourquoi mes utilitaires de test se résolvent-ils vers le mauvais module après l'aliasing dans webpack ?
Parce que l'alias react-dom est listé avant react-dom/test-utils dans votre configuration webpack. Webpack fait d'abord correspondre la règle react-dom, plus large, qui masque le mapping plus spécifique de test-utils : les utilitaires de test se résolvent alors silencieusement vers preact/compat au lieu de preact/test-utils. Corrigez le problème en plaçant l'entrée react-dom après react-dom/test-utils. Rollup a une règle d'ordre analogue : placez @rollup/plugin-alias avant @rollup/plugin-node-resolve.
Pourquoi une bibliothèque React casse-t-elle alors que mon alias preact/compat est correct ?
Parce que compat projette l'API publique de React, pas ses rouages internes. Les bibliothèques qui importent des chemins internes profonds de react-dom, ou qui dépendent des API React 19 les plus récentes, peuvent échouer à l'exécution même avec un alias correct. Ces défaillances apparaissent sous forme d'erreurs console levées depuis l'intérieur de la dépendance, et non depuis votre propre code. Avant d'adopter une bibliothèque, faites un grep à la recherche d'imports profonds react-dom/, et exécutez sa propre suite de tests avec le moduleNameMapper de Jest.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k