Metro è un bundler JavaScript sviluppato specificamente per React Native e utilizzato di default per compilare applicazioni mobili su questa piattaforma. A differenza dei bundler universali, Metro è ottimizzato per le risorse limitate dei dispositivi mobili e fornisce integrazione con il motore Hermes e Fast Refresh. Secondo Metro Documentation (2026), il bundler gestisce oltre il 90% dei progetti React Native nel mondo.
Punti chiave
Metro è un bundler JavaScript open source creato dal team di Meta per React Native. Ha sostituito il Packager delle prime versioni di React Native ed è diventato lo strumento di compilazione standard per questa piattaforma. Metro non è progettato per lo sviluppo web: la sua architettura è focalizzata esclusivamente su applicazioni mobili che funzionano sui motori JavaScript JSC (JavaScriptCore) o Hermes.
Metro è apparso nel 2018 in sostituzione del vecchio React Native Packager. Il motivo principale della sua creazione è stata la necessità di un bundler che funzionasse efficientemente con milioni di moduli in grandi applicazioni mobili. A differenza di Webpack, Metro non supporta CSS, HTML o immagini come moduli — queste risorse sono gestite da strumenti React Native separati. Facebook utilizza Metro per compilare la sua applicazione principale, che contiene oltre 100 mila file.
Metro è distribuito tramite npm come pacchetto metro e si installa automaticamente con React Native CLI. La versione di Metro è legata alla versione di React Native, quindi l'aggiornamento del bundler avviene insieme all'aggiornamento della piattaforma.
Metro riceve in input il punto di ingresso dell'applicazione, costruisce un grafo delle dipendenze, trasforma ogni modulo e serializza il risultato in un unico bundle. Il processo attraversa tre fasi: Resolve (risoluzione dei moduli), Transform (trasformazione) e Serialize (serializzazione).
// Esempio di configurazione Metro per trasformazione personalizzata
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);
};
},
},
};
Nella fase Resolve, Metro determina la posizione di ogni modulo importato, tenendo conto di alias e node_modules. Nella fase Transform, ogni file passa attraverso un trasformatore Babel per convertire JSX, TypeScript e altre estensioni in JavaScript puro. La fase finale Serialize raccoglie tutti i moduli trasformati in uno o più file bundle.
Metro è costruito su un'architettura modulare dove ogni fase di compilazione è implementata come un componente indipendente. Ciò consente di sostituire i moduli standard con moduli personalizzati senza modificare il nucleo del bundler. L'architettura di Metro include tre pacchetti principali: metro, metro-config e metro-resolver.
Metro Server — un server di sviluppo che si avvia con il comando npx react-native start. Gestisce le richieste di trasformazione dei moduli in tempo reale, fornendo Fast Refresh. Module Store — una cache che memorizza i moduli trasformati in memoria per accelerare le ricompilazioni. Dependency Graph — un grafo delle dipendenze che viene aggiornato incrementalmente quando i file cambiano.
Watchman — un osservatore di file di Meta che Metro utilizza per rilevare le modifiche nel file system. Senza Watchman, Metro è costretto a riscansionare l'intera struttura dei file a ogni modifica, rallentando significativamente lo sviluppo. L'installazione di Watchman è obbligatoria per lavorare comodamente con Metro su progetti di qualsiasi dimensione.
La configurazione di Metro è definita nel file metro.config.js nella radice del progetto. Un file tipico definisce cartelle aggiuntive per la ricerca dei moduli, blocklist per escludere file non necessari e trasformatori personalizzati. In React Native 0.72+ viene utilizzato il rilevamento automatico della configurazione, ma per i monorepo la configurazione è obbligatoria.
// 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 esclude i file di test dalla compilazione, riducendo la dimensione del bundle. nodeModulesPaths specifica percorsi aggiuntivi per la ricerca dei pacchetti — fondamentale per i monorepo. extraNodeModules crea alias per pacchetti condivisi utilizzati in diversi progetti del monorepo.
Metro fornisce diversi meccanismi per ottimizzare la dimensione del bundle e la velocità di compilazione. Inline Requires — la tecnica più efficace, che converte le importazioni di livello superiore in chiamate require locali all'interno delle funzioni. RAM bundles consentono di caricare i moduli incrementalmente. Hermes compila JavaScript in bytecode, riducendo la dimensione dell'applicazione del 20–30%.
// metro.config.js — ottimizzazione per la produzione
const config = {
transformer: {
async transform({ src, filename, options }) {
const inlineRequires = options.dev ? false : true;
return await defaultTransform({ src, filename, options: { ...options, inlineRequires } });
},
},
serializer: {
polyfillModuleNames: [],
},
};
// Per abilitare Hermes — in build.gradle (Android):
// project.ext.react = [enableHermes: true, bundleInRelease: true]
// Per iOS — in Podfile: :hermes_enabled => true
Per la diagnosi della dimensione del bundle, Metro fornisce il flag --bundle-output con output di statistiche. Utilizza bundle-visualizer per analizzare la composizione del bundle e trovare moduli grandi che possono essere caricati in modo lazy. Il controllo regolare della dimensione del bundle dovrebbe far parte della pipeline CI/CD del progetto React Native.
Metro supporta i delta bundle — un meccanismo in cui, dopo la prima compilazione completa, il server invia solo le modifiche (delta) tra la vecchia e la nuova versione del bundle. Questo accelera radicalmente le compilazioni successive: il tempo di aggiornamento scende da secondi a decine di millisecondi. I delta bundle sono particolarmente efficaci in fase di sviluppo, quando lo sviluppatore salva frequentemente le modifiche e ricarica l'applicazione.
Per abilitare i delta bundle in React Native si utilizza il flag --delta nel comando npx react-native bundle. Sul lato client, i delta bundle sono supportati a partire da React Native 0.64. Nelle compilazioni di produzione, i delta bundle non vengono utilizzati — viene invece utilizzato un bundle completo con bytecode Hermes per le massime prestazioni di avvio. Ciò è possibile perché il guadagno in velocità di sviluppo compensa il costo della prima compilazione completa.
Hermes è un motore JavaScript sviluppato da Meta specificamente per React Native. Metro genera bytecode Hermes in fase di compilazione, consentendo all'applicazione di avviarsi senza una costosa compilazione JavaScript sul dispositivo. Per abilitare Hermes, basta aggiungere enableHermes: true in metro.config.js e configurare build.gradle o Podfile. Hermes riduce il tempo di avvio dell'applicazione del 30–50% e la dimensione dell'APK del 20–30% rispetto a JavaScriptCore.
Quando si utilizza Hermes, è importante ricordare le limitazioni: il motore non supporta Proxy, Reflect e alcune funzionalità ES6. La maggior parte delle applicazioni React Native non utilizza direttamente queste funzionalità, ma alcune librerie potrebbero entrare in conflitto. Prima di abilitare Hermes, verificare la compatibilità di tutte le dipendenze del progetto tramite la lista di controllo ufficiale di compatibilità. Metro passa automaticamente alla modalità di generazione del bytecode quando Hermes viene attivato.
Per monitorare l'efficienza di compilazione di Metro, utilizza le metriche integrate disponibili tramite Flipper — lo strumento di debug di React Native. Metro pubblica eventi: bundle_request, transform, resolve con il tempo di esecuzione di ogni fase. L'analisi di questi dati aiuta a identificare i colli di bottiglia: se la fase di trasformazione richiede più del 70% del tempo, il problema è nel trasformatore Babel. Attiva la registrazione dei log di Metro tramite il flag --verbose per una diagnosi dettagliata.
Domande frequenti
Tecnicamente sì — esistono progetti sperimentali come react-native-webpack, ma non sono ufficialmente supportati. Metro è integrato con il bridge di React Native, Turbo Modules e Hermes a un livello non accessibile per Webpack. La sostituzione di Metro comporterebbe la perdita di Fast Refresh e del supporto ufficiale.
React Native non utilizza CSS per lo styling — invece viene applicato lo styling JavaScript tramite StyleSheet.create. Poiché Metro è creato esclusivamente per React Native, il supporto CSS non è necessario. Per il rendering web tramite React Native Web, il CSS viene gestito da strumenti separati al di fuori di Metro.
Metro non elabora immagini o font come moduli. Le risorse vengono importate tramite require('./image.png'), ma Metro le registra solo come dipendenze stringa. Il caricamento effettivo delle immagini viene eseguito dal codice nativo di React Native tramite il componente Image, e Metro copia le risorse nel bundle.
Rollup genera moduli ES con tree shaking a livello di modulo, ottenendo una dimensione minima del bundle per le librerie. Metro genera un bundle CommonJS con trasformazione inline e ottimizzazione per i motori mobili. Rollup non supporta Fast Refresh e non può funzionare con i moduli nativi di React Native.
La compilazione a freddo di Metro è rallentata dalla scansione completa di node_modules. Soluzioni: aggiungere watchFolders per i monorepo, utilizzare maxWorkers per la trasformazione parallela e installare Watchman. Per progetti con oltre 10.000 file, considerare metro-memory-fs per la cache in memoria.
Riepilogo
watchFolders e extraNodeModules per la corretta risoluzione dei moduli.Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche