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 поддерживает delta-бандлы — механизм, при котором после первой полной сборки сервер отправляет только изменения (дельта) между старой и новой версиями бандла. Это радикально ускоряет последующие сборки: время обновления сокращается с секунд до десятков миллисекунд. Delta-бандлы особенно эффективны на этапе разработки, когда разработчик часто сохраняет изменения и перезагружает приложение.
Для включения delta-бандлов в React Native используется флаг --delta в команде npx react-native bundle. На стороне клиента delta-бандлы поддерживаются начиная с React Native 0.64. В production-сборках delta-бандлы не применяются — вместо них используется полноценный бандл с 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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также