Accueil / Articles / Modules Nitro : comment les liens statiques surpassent React Native TurboModules

Modules Nitro : comment les liens statiques surpassent React Native TurboModules

Explique comment les Nitro Modules utilisent des liens statiques précompilés au lieu de recherches dynamiques pour surpasser de manière significative les TurboModules et les Expo Modules dans React Native.

1178 mots

TurboModules devaient être la solution idéale. Ils ont remplacé l’architecture ancienne de pont, éliminé les surcoûts inutiles et sont devenus l’approche reconnue pour écrire du code natif capable de communiquer avec JavaScript. Puis une bibliothèque plus récente nommée Nitro Modules est apparue, rendant cette « solution finale » désuète.

Les benchmarks publiés montrent que, lorsqu’on teste une même appel de fonction synchrone, les Nitro Modules peuvent surpasser les Expo Modules par un facteur allant jusqu’à 59, et dépasser les TurboModules d’environ 15 fois. Même en présence de chaînes de caractères, qui ajoutent généralement des surcoûts lors du passage entre JavaScript et le code natif, Nitro conserve un avantage de 5 à 13 fois. Lorsqu’on traite des données plus volumineuses comme des images ou des buffers bruts, Nitro obtient une amélioration supplémentaire de 8 à 40 pour cent, grâce à une approche sans copie qui évite de dupliquer les données en mémoire.

Des chiffres à cette échelle exigent une explication. Que fait exactement Nitro en arrière-plan, et pourquoi cette conception n’a-t-elle pas été mise au point plus tôt ?

Le problème que personne d’autre n’avait résolu

Nitro n’a pas été conçu comme un exercice de référence. Il est né du travail de Marc Rousavy, créateur de VisionCamera, en réponse à une limitation très concrète : ni les TurboModules ni les Expo Modules ne pouvaient gérer correctement le traitement des images.

En VisionCamera, on peut considérer une seule image comme un buffer de 10 mégaoctets. Ce buffer ne peut pas être copié via le pont de communication, même avec les TurboModules, et il ne convient pas non plus à une structure similaire au JSON. Ce dont Rousavy avait réellement besoin, c’était d’un moyen de transmettre directement à JavaScript un objet natif complexe et doté d’état, écrit en C++ ou Swift, accompagné de méthodes et de propriétés fonctionnelles. Les TurboModules ne disposaient d’aucun mécanisme pour ce type d’objet.

Nitro a donc été conçu spécifiquement pour rendre cela possible, et les gains de vitesse considérables se sont avérés être un avantage qui a fini par attirer bien plus d’attention que le problème initial qu’il résolvait.

Un seul choix architectural

La véritable différence entre TurboModules et Nitro réside en une décision de conception : la manière dont chaque système représente un objet natif une fois qu’il se trouve à l’intérieur du moteur JavaScript.

TurboModules s’appuient sur jsi::HostObject. Chaque fois que du code JavaScript accède à une propriété ou appelle une méthode sur l’un de ces objets, le moteur doit résoudre cet accès dynamiquement, sur le moment. Cette recherche a lieu à chaque appel, et ce coût répété s’accumule rapidement pour les modules qui sont souvent invoqués.

Nitro emprunte une approche différente en utilisant jsi::NativeState. Associé à un outil de génération de code nommé Nitrogen, il crée à l’avance tous les liens nécessaires en C++, Swift ou Kotlin, avant même que l’application ne soit exécutée. Rien n’est résolu dynamiquement en temps de exécution. La conversion entre JavaScript et les types natifs est compilée statiquement à l’avance, ce qui signifie que l’appel à un module Nitro se comporte davantage comme l’exécution d’une fonction ordinaire que comme le passage par un pont en temps de exécution.

Cette différence, à savoir des liens statiques précompilés au lieu de recherches dynamiques en temps de exécution, explique la majeure partie du retard de performance observé dans les benchmarks.

Dans Nitro, tout objet natif, qu’il soit écrit en C++, Swift ou Kotlin, est désigné comme un objet hybride. Nitrogen analyse une définition d’interface TypeScript et génère automatiquement le code nécessaire pour faire passer cet objet de l’environnement natif JS vers un autre, en gérant notamment les enums, les unions et les structs. Ce type d’outil est précisément ce qui a permis à Rousavy de mettre à disposition quelque chose d’aussi atypique qu’une image en temps réel provenant d’une caméra, sans avoir à écrire manuellement du code de liaison distinct pour chacune des trois plateformes.

Pourquoi cela dépasse le cadre d’une simple bibliothèque

VisionCamera a servi de preuve initiale que cette approche fonctionnait, mais la conception de Nitro n’était jamais destinée à rester une solution ponctuelle pour un seul cas d’usage. Son architecture offre à tout module natif un support intégré pour les buffers de tableau, les objets natifs à état et l’interopérabilité directe en C++, des fonctionnalités qui, selon les approches précédentes, étaient au mieux peu pratiques, voire complètement inutilisables.

L’écosystème plus vaste de React Native a commencé à s’en rendre compte. Des projets tels que react-native-nitro-cache, ainsi que des outils destinés au cache d’images, aux charges de travail en apprentissage automatique et aux moteurs de jeu, sont reconstruits sur Nitro afin de réduire la charge liée à la conversion JavaScript en code natif là où les performances sont cruciales. Cela reflète une tendance plus large déjà en cours au sein de React Native, où les bibliothèques fondamentales sont restructurées autour de la Nouvelle Architecture plutôt que d’être considérées comme quelque chose à adopter ultérieurement de manière optionnelle. L’adoption de Nitro reste bien en retrait par rapport à TurboModules, qui continue d’être le choix par défaut pour la plupart des bibliothèques, mais la trajectoire est indéniable. Là où les performances brutes sont une priorité, Nitro devient de plus en plus l’outil auquel les développeurs ont recours en premier.

Quelles en sont les conséquences pour les auteurs de modules natifs

Si vous gérez actuellement un module natif, ce changement mérite votre attention. Les TurboModules ne disparaîtront pas de sitôt, et pour les modules simples, l’écart de performance ne sera probablement pas perceptible pour les utilisateurs finaux. Cependant, si votre module implique des éléments sensibles à la performance, une fréquence élevée d’appels, de gros volumes de données ou des objets qui ne se traduisent pas facilement en JSON, Nitro est désormais très certainement la base plus adaptée sur laquelle s’appuyer.

Choisir de créer un module natif entièrement nouveau sur TurboModules en 2026 signifie en réalité s’appuyer sur une architecture que d’autres solutions, plus rapides et en pleine expansion, ont déjà dépassées. Le générateur de code de Nitro gère automatiquement une grande partie du travail répétitif sur les trois plateformes en même temps, ce qui permet d’obtenir des performances plus élevées tout en nécessitant moins de code natif manuellement écrit pour son entretien. Pour les équipes disposant déjà d’un TurboModule, la migration n’est pas une opération simple, mais les mêmes résultats de benchmark qui rendent Nitro attrayant fournissent également de solides arguments en faveur d’une migration le plus tôt possible.

React Native a déjà connu plusieurs véritables tournants architecturaux : l’abandon de l’ancienne architecture, l’introduction de la Nouvelle Architecture, et maintenant celui-ci. Nitro n’est pas apparu suite à une directive officielle de Meta. Il est apparu parce que un développeur avait besoin d’une fonctionnalité que TurboModules ne pouvait tout simplement pas fournir ; ce dernier a alors développé la solution en public et laissé les résultats des benchmarks parler d’eux-mêmes.

Lectures complémentaires

  • React 19.2 expliqué : Activity, useEffectEvent et rendering statique — Découvrez comment le nouveau composant Activity, l’hook useEffectEvent et le rendering statique partiel de React 19.2 permettent de corriger les coûts de performance cachés dans les interfaces utilisateur modernes.
  • Pourquoi le départ de Shopify vers React Native ne menace pas Expo — On explique pourquoi le passage de Shopify de React Native à Swift et Kotlin natifs ne signifie pas la fin du développement multiplateforme avec Expo pour la plupart des équipes.
  • Construire un lecteur PDF résistant aux crashes pour de gros documents en React Native — Découvrez une architecture permettant d’afficher des PDF massifs de plusieurs milliers de pages en React Native, avec des arbres de signets différés, une fonction de recherche et une navigation stable sur les appareils à faibles ressources.
  • Fuites de mémoire en React Native : tracer le heap JS et les propriétaires de la mémoire native — Comprenez pourquoi le collecteur de déchets ne peut pas protéger une application React Native des fuites natives, et apprenez comment identifier ce qui maintient en vie les callbacks, les objets JSI et les images décodées.
  • Pourquoi Codegen rend la spécification préliminaire obligatoire pour React Native TurboModules — Découvrez comment Codegen de React Native transforme la spécification TypeScript de TurboModule en un contrat à l’heure de la compilation, ce qui se passe lorsque vous l’omettez, et où cette règle cesse d’être applicable.