Metro est un bundler JavaScript développé spécifiquement pour React Native et utilisé par défaut pour compiler des applications mobiles sur cette plateforme. Contrairement aux bundlers universels, Metro est optimisé pour les ressources limitées des appareils mobiles et assure l'intégration avec le moteur Hermes et Fast Refresh. Selon Metro Documentation (2026), le bundler traite plus de 90 % des projets React Native dans le monde.
Points clés
Metro est un bundler JavaScript open source créé par l'équipe Meta pour React Native. Il a remplacé le Packager des premières versions de React Native et est devenu l'outil de compilation standard pour cette plateforme. Metro n'est pas conçu pour le développement web : son architecture est exclusivement orientée vers les applications mobiles fonctionnant sur les moteurs JavaScript JSC (JavaScriptCore) ou Hermes.
Metro est apparu en 2018 en remplacement de l'ancien React Native Packager. La principale raison de sa création était le besoin d'un bundler capable de travailler efficacement avec des millions de modules dans de grandes applications mobiles. Contrairement à Webpack, Metro ne prend pas en charge CSS, HTML ou les images en tant que modules — ces ressources sont gérées par des outils React Native séparés. Facebook utilise Metro pour compiler son application principale, qui contient plus de 100 000 fichiers.
Metro est distribué via npm en tant que paquet metro et s'installe automatiquement avec React Native CLI. La version de Metro est liée à la version de React Native, donc la mise à jour du bundler se fait avec la mise à jour de la plateforme.
Metro prend en entrée le point d'entrée de l'application, construit un graphe de dépendances, transforme chaque module et sérialise le résultat en un bundle unique. Le processus passe par trois phases : Resolve (résolution de modules), Transform (transformation) et Serialize (sérialisation).
// Exemple de configuration Metro pour une transformation personnalisée
const metroConfig = {
transformer: {
babelTransformerPath: require('metro-babel-transformer'),
async transform({ src, filename, options }) {
const result = await babelTransform({ src, filename, options });
return {
ast: result.ast,
code: result.code,
map: result.map,
dependencies: [],
};
},
},
serializer: {
createModuleIdFactory() {
let nextId = 0;
const moduleIds = new Map();
return ({ path }) => {
if (!moduleIds.has(path)) {
moduleIds.set(path, nextId++);
}
return moduleIds.get(path);
};
},
},
};
Dans la phase Resolve, Metro détermine l'emplacement de chaque module importé, en tenant compte des alias et de node_modules. Dans la phase Transform, chaque fichier passe par un transformateur Babel pour convertir JSX, TypeScript et d'autres extensions en JavaScript pur. La phase finale Serialize rassemble tous les modules transformés dans un ou plusieurs fichiers bundle.
Metro est construit sur une architecture modulaire où chaque étape de compilation est implémentée comme un composant indépendant. Cela permet de remplacer les modules standard par des modules personnalisés sans modifier le noyau du bundler. L'architecture de Metro comprend trois paquets principaux : metro, metro-config et metro-resolver.
Metro Server — un serveur de développement qui se lance avec la commande npx react-native start. Il traite les demandes de transformation de modules en temps réel, assurant Fast Refresh. Module Store — un cache qui stocke les modules transformés en mémoire pour accélérer les recompilations. Dependency Graph — un graphe de dépendances qui se met à jour de manière incrémentielle lorsque les fichiers changent.
Watchman — un observateur de fichiers de Meta que Metro utilise pour détecter les modifications dans le système de fichiers. Sans Watchman, Metro doit rescanner toute la structure de fichiers à chaque modification, ce qui ralentit considérablement le développement. L'installation de Watchman est obligatoire pour travailler confortablement avec Metro sur des projets de toute taille.
La configuration de Metro est définie dans le fichier metro.config.js à la racine du projet. Un fichier typique définit des dossiers supplémentaires pour la recherche de modules, des listes de blocage pour exclure les fichiers inutiles et des transformateurs personnalisés. Dans React Native 0.72+, la détection automatique de la configuration est utilisée, mais pour les monorepos, la configuration est obligatoire.
// metro.config.js
const config = {
resolver: {
sourceExts: ['js', 'jsx', 'ts', 'tsx', 'json'],
nodeModulesPaths: ['node_modules'],
blockList: [/\.test\.js$/, /__tests__\/.*/],
extraNodeModules: {
'shared-components': path.resolve(__dirname, '../shared/src'),
},
},
transformer: {
minifierConfig: {
keep_classnames: true,
keep_fnames: true,
mangle: { reserved: ['React', 'Component'] },
},
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
blockList exclut les fichiers de test de la compilation, réduisant ainsi la taille du bundle. nodeModulesPaths spécifie des chemins supplémentaires pour la recherche de paquets — essentiel pour les monorepos. extraNodeModules crée des alias pour les paquets partagés utilisés dans différents projets du monorepo.
Metro fournit plusieurs mécanismes pour optimiser la taille du bundle et la vitesse de compilation. Inline Requires — la technique la plus efficace, qui convertit les importations de niveau supérieur en appels require locaux dans les fonctions. RAM bundles permettent de charger les modules de manière incrémentielle. Hermes compile JavaScript en bytecode, réduisant la taille de l'application de 20 à 30 %.
// metro.config.js — optimisation pour la production
const config = {
transformer: {
async transform({ src, filename, options }) {
const inlineRequires = options.dev ? false : true;
return await defaultTransform({ src, filename, options: { ...options, inlineRequires } });
},
},
serializer: {
polyfillModuleNames: [],
},
};
// Pour activer Hermes — dans build.gradle (Android) :
// project.ext.react = [enableHermes: true, bundleInRelease: true]
// Pour iOS — dans Podfile : :hermes_enabled => true
Pour le diagnostic de la taille du bundle, Metro fournit le drapeau --bundle-output avec sortie de statistiques. Utilisez bundle-visualizer pour analyser la composition du bundle et trouver les modules volumineux qui peuvent être chargés paresseusement. La vérification régulière de la taille du bundle devrait faire partie du pipeline CI/CD du projet React Native.
Metro prend en charge les delta bundles — un mécanisme où, après la première compilation complète, le serveur n'envoie que les modifications (delta) entre les anciennes et nouvelles versions du bundle. Cela accélère radicalement les compilations suivantes : le temps de mise à jour passe de quelques secondes à des dizaines de millisecondes. Les delta bundles sont particulièrement efficaces pendant le développement, lorsque le développeur enregistre fréquemment les modifications et recharge l'application.
Pour activer les delta bundles dans React Native, on utilise le drapeau --delta dans la commande npx react-native bundle. Côté client, les delta bundles sont supportés à partir de React Native 0.64. Dans les compilations de production, les delta bundles ne sont pas utilisés — à la place, un bundle complet avec bytecode Hermes est utilisé pour des performances de démarrage maximales. Cela est possible car le gain de vitesse de développement compense le coût de la première compilation complète.
Hermes est un moteur JavaScript développé par Meta spécifiquement pour React Native. Metro génère du bytecode Hermes lors de la compilation, permettant à l'application de démarrer sans compilation JavaScript coûteuse sur l'appareil. Pour activer Hermes, il suffit d'ajouter enableHermes: true dans metro.config.js et de configurer build.gradle ou Podfile. Hermes réduit le temps de démarrage de l'application de 30 à 50 % et la taille de l'APK de 20 à 30 % par rapport à JavaScriptCore.
Lors de l'utilisation d'Hermes, il est important de se rappeler ses limitations : le moteur ne supporte pas Proxy, Reflect et certaines fonctionnalités ES6. La plupart des applications React Native n'utilisent pas ces fonctionnalités directement, mais certaines bibliothèques peuvent entrer en conflit. Avant d'activer Hermes, vérifiez la compatibilité de toutes les dépendances du projet via la liste de vérification officielle de compatibilité. Metro passe automatiquement en mode de génération de bytecode lorsque Hermes est activé.
Pour suivre l'efficacité de la compilation de Metro, utilisez les métriques intégrées disponibles via Flipper — l'outil de débogage React Native. Metro publie des événements : bundle_request, transform, resolve avec le temps d'exécution de chaque étape. L'analyse de ces données aide à identifier les goulots d'étranglement : si la phase de transformation prend plus de 70 % du temps, le problème vient du transformateur Babel. Activez la journalisation de Metro via le drapeau --verbose pour un diagnostic détaillé.
Foire aux questions
Techniquement oui — il existe des projets expérimentaux comme react-native-webpack, mais ils ne sont pas officiellement supportés. Metro est intégré avec le pont React Native, Turbo Modules et Hermes à un niveau inaccessible pour Webpack. Remplacer Metro entraînerait la perte de Fast Refresh et du support officiel.
React Native n'utilise pas CSS pour le style — à la place, le style JavaScript est appliqué via StyleSheet.create. Puisque Metro est créé exclusivement pour React Native, le support CSS n'est pas nécessaire. Pour le rendu web via React Native Web, le CSS est géré par des outils séparés en dehors de Metro.
Metro ne traite pas les images ou les polices comme des modules. Les ressources sont importées via require('./image.png'), mais Metro ne les enregistre que comme des dépendances de chaîne. Le chargement réel des images est effectué par le code natif de React Native via le composant Image, et Metro copie les ressources dans le bundle.
Rollup génère des modules ES avec tree shaking au niveau des modules, offrant une taille de bundle minimale pour les bibliothèques. Metro génère un bundle CommonJS avec transformation inline et optimisation pour les moteurs mobiles. Rollup ne supporte pas Fast Refresh et ne peut pas fonctionner avec les modules natifs de React Native.
La compilation à froid de Metro est ralentie par l'analyse complète de node_modules. Solutions : ajoutez watchFolders pour les monorepos, utilisez maxWorkers pour la transformation parallèle et installez Watchman. Pour les projets de plus de 10 000 fichiers, envisagez metro-memory-fs pour la mise en cache en mémoire.
Résumé
watchFolders et extraNodeModules est nécessaire pour une résolution correcte des modules.Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi