Metro — бандлер JavaScript, розроблений спеціально для React Native і використовуваний за замовчуванням для збірки мобільних застосунків на цій платформі. На відміну від універсальних бандлерів, Metro оптимізований під обмежені ресурси мобільних пристроїв і забезпечує інтеграцію з Hermes engine та Fast Refresh. За даними Metro Documentation (2026), бандлер обробляє понад 90% React Native проєктів у світі.
Головне
Metro — це бандлер JavaScript з відкритим вихідним кодом, створений командою Meta для React Native. Він замінив Packager з ранніх версій React Native і став стандартним інструментом збірки для цієї платформи. Metro не призначений для веб-розробки: його архітектура орієнтована виключно на мобільні застосунки, що працюють під керуванням JavaScript-рушіїв JSC (JavaScriptCore) або Hermes.
Metro з'явився у 2018 році як заміна старому React Native Packager. Основна причина створення — необхідність у бандлері, який ефективно працює з мільйонами модулів у великих мобільних застосунках. На відміну від Webpack, Metro не підтримує CSS, HTML або зображення як модулі — ці ресурси обробляються окремими інструментами React Native. Facebook використовує Metro для збірки свого основного застосунку, який містить понад 100 тисяч файлів.
Metro поширюється через npm як пакет metro і встановлюється автоматично разом з React Native CLI. Версія Metro прив'язана до версії React Native, тому оновлення бандлера відбувається разом з оновленням платформи.
Metro отримує на вхід точку входу застосунку, будує граф залежностей, трансформує кожен модуль і серіалізує результат у єдиний бандл. Процес проходить три фази: Resolve (розпізнавання модулів), Transform (трансформація) та Serialize (серіалізація).
// Приклад конфігурації Metro для кастомної трансформації
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);
};
},
},
};
На фазі Resolve Metro визначає місцезнаходження кожного імпортованого модуля, враховуючи аліаси та node_modules. На фазі Transform кожен файл проходить через Babel-трансформер для конвертації JSX, TypeScript та інших розширень у чистий JavaScript. Фінальна фаза Serialize збирає всі трансформовані модулі в один або кілька бандл-файлів.
Metro побудований на модульній архітектурі, де кожен етап збірки реалізований як окремий компонент. Це дозволяє замінювати стандартні модулі на кастомні без зміни ядра бандлера. Архітектура Metro включає три основні пакети: metro, metro-config та metro-resolver.
Metro Server — dev-сервер, який запускається при команді npx react-native start. Він обслуговує запити на трансформацію модулів у реальному часі, забезпечуючи Fast Refresh. Module Store — кеш, що зберігає трансформовані модулі в пам'яті для прискорення повторних збірок. Dependency Graph — граф залежностей, який оновлюється інкрементально при зміні файлів.
Watchman — файловий спостерігач від Meta, який Metro використовує для виявлення змін у файловій системі. Без Watchman Metro доводиться пересканувати всю файлову структуру при кожній зміні, що значно уповільнює розробку. Встановлення Watchman є обов'язковим для комфортної роботи з Metro на проєктах будь-якого розміру.
Конфігурація Metro задається у файлі metro.config.js в корені проєкту. Типовий файл визначає додаткові папки для пошуку модулів, блокування для виключення непотрібних файлів та кастомні трансформери. У React Native 0.72+ використовується автовиявлення конфігурації, але для монорепозиторіїв налаштування є обов'язковим.
// 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 виключає тестові файли зі збірки, зменшуючи розмір бандла. nodeModulesPaths вказує додаткові шляхи для пошуку пакетів — критично для монорепозиторіїв. extraNodeModules створює аліаси для спільних пакетів, що використовуються в різних проєктах монорепозиторію.
Metro надає кілька механізмів для оптимізації розміру бандла та швидкості збірки. Inline Requires — найбільш ефективна техніка, яка перетворює імпорти на верхньому рівні в локальні require всередині функцій. RAM bundles дозволяють завантажувати модулі інкрементально. Hermes компілює JavaScript у байт-код, зменшуючи розмір застосунку на 20–30%.
// metro.config.js — оптимізація для 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: [],
},
};
// Для ввімкнення Hermes — в build.gradle (Android):
// project.ext.react = [enableHermes: true, bundleInRelease: true]
// Для iOS — в Podfile: :hermes_enabled => true
Для діагностики розміру бандла Metro надає прапорець --bundle-output з виведенням статистики. Використовуйте bundle-visualizer для аналізу складу бандла та пошуку великих модулів, які можна завантажувати ліниво. Регулярна перевірка розміру бандла має бути частиною CI/CD пайплайну проєкту React Native.
Metro підтримує дельта-бандли — механізм, при якому після першої повної збірки сервер відправляє лише зміни (дельта) між старою та новою версіями бандла. Це радикально прискорює наступні збірки: час оновлення скорочується з секунд до десятків мілісекунд. Дельта-бандли особливо ефективні на етапі розробки, коли розробник часто зберігає зміни та перезавантажує застосунок.
Для ввімкнення дельта-бандлів у React Native використовується прапорець --delta в команді npx react-native bundle. На стороні клієнта дельта-бандли підтримуються починаючи з React Native 0.64. У production-збірках дельта-бандли не застосовуються — натомість використовується повноцінний бандл з Hermes-байткодом для максимальної продуктивності запуску. Це досягається завдяки тому, що приріст швидкості розробки компенсує витрати на першу повну збірку.
Hermes — JavaScript-рушій, розроблений Meta спеціально для React Native. Metro генерує байт-код Hermes на етапі збірки, що дозволяє застосунку запускатися без дорогої компіляції JavaScript на пристрої. Для ввімкнення Hermes достатньо додати enableHermes: true в metro.config.js та налаштувати build.gradle або Podfile. Hermes зменшує час запуску застосунку на 30–50% і скорочує розмір APK на 20–30% порівняно з JavaScriptCore.
При використанні Hermes важливо пам'ятати про обмеження: рушій не підтримує Proxy, Reflect та деякі можливості ES6. Більшість React Native застосунків не використовують ці можливості безпосередньо, але деякі бібліотеки можуть конфліктувати. Перед увімкненням Hermes перевірте сумісність усіх залежностей проєкту через офіційний чек-лист сумісності. Metro автоматично перемикається в режим генерації байт-коду при активації Hermes.
Для відстеження ефективності збірки Metro використовуйте вбудовані метрики, доступні через Flipper — інструмент налагодження React Native. Metro публікує події: bundle_request, transform, resolve з часом виконання кожного етапу. Аналіз цих даних допомагає виявити вузькі місця: якщо фаза transform займає понад 70% часу, проблема в Babel-трансформері. Увімкніть ведення логів Metro через прапорець --verbose для детальної діагностики.
Часті запитання
Технічно так — існують експериментальні проєкти на кшталт react-native-webpack, але вони не підтримуються офіційно. Metro інтегрований з React Native bridge, Turbo Modules та Hermes на рівні, недоступному для Webpack. Заміна Metro призведе до втрати Fast Refresh та офіційної підтримки.
React Native не використовує CSS для стилізації — натомість застосовується JavaScript-стилізація через StyleSheet.create. Оскільки Metro створений ексклюзивно для React Native, підтримка CSS не потрібна. Для веб-рендерингу через React Native Web CSS обробляється окремими інструментами поза Metro.
Metro не обробляє зображення або шрифти як модулі. Ресурси підключаються через require('./image.png'), але Metro лише реєструє їх як рядкові залежності. Фактичне завантаження зображень виконується нативним кодом React Native через компонент Image, а Metro копіює ресурси в bundle.
Rollup генерує ES-модулі з tree shaking на рівні модулів, що дає мінімальний розмір бандла для бібліотек. Metro генерує CommonJS-бандл з інлайн-трансформацією та оптимізацією під мобільні рушії. Rollup не підтримує Fast Refresh і не може працювати з нативними модулями React Native.
Холодна збірка Metro сповільнюється через повне сканування node_modules. Рішення: додайте watchFolders для монорепозиторіїв, використовуйте maxWorkers для паралельної трансформації та встановіть Watchman. Для проєктів з 10 000+ файлів розгляньте metro-memory-fs для кешування в пам'яті.
Підсумки
watchFolders та extraNodeModules для коректного розпізнавання модулів.Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також