Preact est une alternative à React. Plus précisément, voici sa description officielle :
Fast 3kB alternative to React with the same ES6 API.
Cette description semble alléchante au premier coup d'oeil. Si on peut avoir un React de 3ko, banco, on switch !
Pas si vite. L'API est la même, mais rien n'indique que Preact est un React qui tient dans 3 petits ko (bien que c'est ce qu'on peut parfois lire). Ça ferait bien longtemps que les ingénieurs de Facebook auraient réagit s'il était possible de faire en sorte que React soit si petit. Preact fait donc des compromis, des choix, et présente donc des différences avec React qu'il faut connaître et prendre en compte avant d'envisager de switcher.
Cet article est destiné aux gens qui connaissent déjà au moins un petit peu React. Tous les concepts liés à (P)React ne seront pas détaillés. Si vous ne connaissez rien à React, je vous invite à lire l'introduction à React.
Premièrement, Preact se concentre uniquement sur le DOM. Cela signifie qu'il n'existe pas d'équivalent à react-native, react-vr ou tout autre renderer du côté de Preact. Celui-ci a pour but d'afficher du DOM le plus efficacement possible.
Cette spécialisation pour le DOM permet à Preact de ne pas avoir à implémenter
le système de Synthetic Events utilisé par React. Ainsi, Preact peut se
permettre d'utiliser simplement le système d'événements standard du navigateur.
Il faut bien avoir cela en tête lorsqu'on a l'habitude de travailler avec React,
car celui-ci corrige, ou du moins unifie certains comportements entre les
navigateurs (notamment sur onChange
). Des différences dans le comportement de
votre app est donc à prévoir en cas de switch.
Preact n'embarque pas de gestion de validation des PropTypes. Partant du principe que celles-ci ne sont pas utilisées par tout le monde, la décision a été prise de ne pas les inclure dans le coeur de la bibliothèque.
Pour finir, Preact n'expose pas (encore, tout du moins) les nouvelles APIs de
React 16 telles que React.Fragment
(dont
le support est prévu),
ReactDOM.createPortal
(la fonctionnalité existe tout de même sous une forme
différente dans preact-portal) ou
ReactDOM.hydrate
.
Preact utilise la bibliothèque
hyperscript, qui est une version
générique de React.createElement
. Le résultat est le même, la signature de la
fonction h()
exposée par hyperscript étant la même que celle de
React.createElement
. Il faudra quand même indiquer au compiler qu'il doit
utiliser cette fonction pour transpiler le JSX.
La méthode render()
des composants reçoit toujours this.props
et
this.state
en paramètres, ce qui permet de les destructurer directement dans
les paramètres de la fonction, et ainsi de les traiter comme s'ils étaient
eux-mêmes des paramètres.
Preact gère l'API context
, mais il n'existe pas de contextTypes
ni de
childContextTypes
(ce qui est raccord avec l'absence de propTypes
). Tous les
enfants reçoivent le context
définit dans la méthode getChildContext()
de
leurs parents. Si plusieurs parents implémentent cette méthode, alors les
descendants recevront un agrégat.
Dans Preact, props.children
est un Array
. On peut donc utiliser toutes les
méthodes de Array.prototype
dessus, sans avoir à passer par un équivalent de
React.Children
. Toutefois, certains patterns tels que le function as child
nécessitent un peu de bricolage pour fonctionner.
Enfin, il est possible d'utiliser l'attribut class
sur un noeud JSX.
className
est aussi supporté, mais vous ne vous prendrez plus d'erreur lorsque
votre esprit se croira dans un fichier HTML et vous fera écrire class
.
Pour démarrer sur de bonnes bases, le plus simple est d'utiliser
preact-cli
. C'est un outil en ligne
de commande qui vous permet de créer toute la structure de base de votre
application. Si vous connaissez create-react-app
, alors vous aurez deviné que
preact-cli
est l'équivalent pour Preact.
Commençons par l'installer :
npm install -g preact-cli
Nous avons maintenant accès à la commande preact
. Celle-ci s'utilise de la
manière suivante :
preact create <template-name> <project-name>
Où <template-name>
est le nom d'un template officiel (listé sur l'org GitHub
preactjs-template
) ou un repository
GitHub contenant un dossier template
(de la forme <username>/<repository>
);
et <project-name>
est le nom du dossier dans lequel la structure du projet
sera créée. Pour notre exemple, nous utiliserons le template default
, et le
nom test-preact
pour notre projet :
preact create default test-preact
En utilisant le template default
, nous obtenons une application qui embarque
par défaut :
index.html
prérendue pour un affichage le plus rapide possibleIl ne vous reste plus qu'à écrire votre app sur ces bases solides ! Pour
information, le routing est géré par
preact-router
.
Oui, et pour ça il y a deux possibilités : ajouter une couche de compatibilité, ou passer purement et simplement à Preact.
preact-compat
Le plus rapide est d'utiliser
preact-compat
. Ce module vient
s'ajouter à Preact pour y ajouter une couche de compatibilité le rendant
compatible avec preque n'importe quel module écrit pour React (tant que celui-ci
n'utilise pas les quelques bouts d'API manquants). Pour cela, preact-compat
expose l'ensemble de l'API de react
et react-dom
. Cela vous permettra de
continuer à utiliser sereinement tous vos composants écrits spécifiquement pour
React, ainsi que vous son écosystème.
Il faut donc l'installer, ainsi que Preact :
npm install --save preact preact-compat
Puis il faut ajouter des alias à votre système de build, afin que tous vos
imports de react
et react-dom
soient reroutés vers preact-compat
. Par
exemple, pour webpack :
module.exports = {
//... votre configuration webpack
resolve: {
alias: {
"react": "preact-compat",
"react-dom": "preact-compat"
}
}
}
Si vous n'utilisez pas webpack, votre système de build est très certainement listé sur la documentation.
Cette solution a l'avantage d'être très rapide à mettre en place. Toutefois, le
principal avantage de Preact est son poids de seulement 3ko. En ajoutant
preact-compat
,vous ajouterez environ 2ko supplémentaires. Ce n'est pas énorme,
surtout si on prend en compte les avantages que ce module apporte, mais il est
possible de ne pas avoir à ajouter cette couche de compatibilité.
Cette solution est un peu plus longue à mettre en place, mais si votre code n'est pas dépendant d'un module qui utilise des parties de l'API de React qui ne sont pas prises en compte par Preact, alors elle vous permettra d'obtenir le bundle le plus léger possible.
Premièrement, il faut installer Preact :
npm install --save preact
Puis il faut indiquer à votre compiler le pragma JSX qu'il doit utiliser. Pour
babel, vous pouvez installer le plugin babel-plugin-transform-react-jsx
:
npm instal --save-dev babel-plugin-transform-react-jsx
Puis indiquer le pragma JSX dans les options de ce plugin dans votre fichier
.babelrc
:
{
"plugins": [
["transform-react-jsx", { "pragma": "h" }]
]
}
Même si vous connaissez React, cette histoire de pragma JSX pourrait ne pas
vous évoquer grand chose. Si vous souhaitez en savoir plus, je vous conseille de
lire l'article suivant : WTF is JSX. Si
vous utilisez React et n'avez jamais eu à configurer ce pragma, c'est parce que
la plupart des compilers utilisent le pragma @jsx React.createElement
par
défaut.
Si vous utilisez une version de React qui n'est pas à jour, il est possible que
votre codebase utilise l'ancienne syntaxe React.createClass()
. Dans ce cas, il
faut que vous installiez
preact-classless-component
,
ou que vous passiez votre codebase dans le
preact-codemod
qui transformera
vos composants en classes ES6. De même, il se peut que vous utilisiez des
références par chaîne de caractères, qui ne sont pas supportées par Preact. Dans
ce cas, il faudra les transformer en références fonctionnelles.
Il ne vous reste plus qu'à mettre à jour vos imports pour que ceux-ci pointent vers Preact. Voici un petit exemple :
import { h, Component, render } from "preact";
const Header = () => <header>Ma putain d'app</header>;
class App extends Component {
render() {
return (
<div>
<Header />
<main>Hello, world !</main>
</div>
);
}
}
render(<App />, document.getElementById("app"));
Voilà, vous avez maintenant une aperçu de ce qu'est Preact et des moyens à votre disposition pour l'utiliser. Facebook ne vous est plus d'aucune utilité, vous pouvez fermer votre compte.
Plus sérieusement, nous avons vu que Preact est en grande partie compatible avec React et peut presque le remplacer sur une app web. Cela nécessite tout de même un peu de travail et de vigilance, mais le switch est possible et peut vous permettre de faire économiser à vos utilisateurs le téléchargement de précieux ko.