Metro Bundler — это специализированный JavaScript-бандлер от Meta, разработанный исключительно для React Native и входящий в ядро фреймворка. По данным официальной документации React Native 0.76 (2025), Metro обеспечивает инкрементальную сборку с Fast Refresh и разрешение модулей с учётом платформенных расширений .native.js, .ios.js и .android.js. В отличие от Webpack, Metro не использует долгоживущий кеш module graph — вместо этого он перестраивает граф каждый раз при изменении файлов, что даёт мгновенный Hot Reload при разработке.
Главное
Metro Bundler — это JavaScript-бандлер с открытым исходным кодом, разработанный Meta для React Native и используемый по умолчанию во всех проектах фреймворка. Задача Metro — взять JavaScript-код проекта вместе с зависимостями и собрать в один или несколько бандлов, которые выполняются на устройстве. В отличие от универсальных бандлеров (Webpack, Rollup, Parcel), Metro оптимизирован под специфику мобильной разработки: минимальное время сборки, инкрементальные обновления при разработке и корректная работа с платформенными модулями (Objective-C, Swift, Java, Kotlin нативные модули). Metro поставляется в составе React Native CLI и не требует отдельной установки. Начиная с React Native 0.72, Metro версии 0.80+ поддерживает параллельную транспиляцию модулей, что ускоряет сборку на многоядерных процессорах до 40%.
Архитектура Metro разделена на три независимых компонента: Resolver, Transformer и Bundler. Resolver отвечает за поиск и разрешение модулей — он читает import/require выражения, находит соответствующие файлы с учётом платформенных расширений и возвращает абсолютные пути. Transformer выполняет транспиляцию: применяет Babel с presets и plugins, преобразует JSX, TypeScript или Flow в чистый JavaScript. Bundler — финальный этап: он принимает граф зависимостей от Resolver и трансформированные файлы от Transformer, затем сериализует их в один или несколько бандлов (module bundles). Разделение на три шага позволяет Metro кешировать результаты каждого этапа: если изменился только один файл, Resolver и Bundler могут использовать кеш для остальных модулей, что даёт прирост скорости сборки до 10 раз в режиме разработки.
Resolver в Metro реализует алгоритм разрешения модулей, частично совместимый с Node.js module resolution. Ключевое отличие от Node.js — поддержка платформенных расширений: require('./Component') ищет Component.native.js, Component.ios.js, Component.android.js в указанном порядке приоритета. Resolver также поддерживает package.json поле "react-native" для маппинга модулей в альтернативные реализации — это стандартный механизм для библиотек с платформенным кодом. Если файл не найден, Resolver выбрасывает ошибку с полным стеком поиска.
Transformer внутри Metro использует Babel с пресетом metro-react-native-babel-preset. Стандартная конфигурация включает: преобразование JSX в React.createElement, поддержку TypeScript (удаление типов), поддержку Flow и полифиллы для современных JavaScript-стандартов (async/await, optional chaining, nullish coalescing). Transformer работает в параллельном режиме: каждый модуль транспилируется независимо, используя пул worker-процессов (по умолчанию количество соответствует числу CPU). Начиная с Metro 0.80, поддерживается Granular Transformer Cache — инвалидация кеша на уровне отдельного файла.
Одна из ключевых особенностей Metro — поддержка платформенных расширений файлов. React Native проект может содержать три версии одного модуля: Component.ios.js (iOS), Component.android.js (Android) и Component.native.js (обе платформы). При импорте require('./Component') Resolver автоматически выбирает правильную версию в зависимости от целевой платформы сборки. Это позволяет писать платформо-зависимый код без условных конструкций Platform.OS. Порядок приоритета: имя.платформа.js > имя.native.js > имя.js. Расширение .native.js применяется для общего кода, работающего на обеих платформах, но несовместимого с вебом. Расширения .ios.js и .android.js служат для реализации специфичных фич — навигация, жесты, работа с файловой системой. Metro поддерживает кастомные расширения через конфигурацию resolver.sourceExts.
// metro.config.js — sourceExts and watchFolders setup
const config = {
resolver: {
sourceExts: ['jsx', 'js', 'tsx', 'ts', 'json'],
platformExtensions: ['ios', 'android', 'native'],
},
transformer: {
babelTransformerPath: require('metro-react-native-babel-transformer'),
},
watchFolders: [path.resolve('../shared')],
};
Fast Refresh — это механизм горячей перезагрузки React Native, реализованный поверх Metro. Когда разработчик изменяет файл, Metro перетранспилирует только изменённый модуль и отправляет обновление в приложение через WebSocket. Fast Refresh обновляет UI без перезагрузки всего приложения и сохраняет React-состояние компонентов, если изменён только JSX или стили. Если изменён код с хуками или состоянием, Fast Refresh выполняет перемонтирование только изменённого компонента. Metro поддерживает два режима: Hot Module Replacement (HMR) для замены модулей на лету и Live Reload для полной перезагрузки приложения при изменении нативных модулей или конфигурации. Fast Refresh включён по умолчанию в React Native 0.76 и не требует дополнительной настройки — достаточно запустить npx react-native start.
| Режим | Скорость | Сохраняет state | Триггер |
|---|---|---|---|
| Fast Refresh | 200-500ms | Да | Изменение JS/TS файлов |
| HMR | 100-300ms | Да | Изменение CSS/стилей |
| Live Reload | 1-3s | Нет | Изменение native config |
| Full Rebuild | 10-60s | Нет | Изменение podspec/build.gradle |
metro.config.js — это файл конфигурации Metro, расположенный в корне React Native проекта. В нём настраиваются: resolver (sourceExts, platformExtensions, extraNodeModules), transformer (babelTransformerPath, minifierConfig), server (port, host, enableFastRefresh) и watcher (watchFolders, healthCheck). Стандартная конфигурация Metro наследуется от пакета @react-native/metro-config (React Native 0.76+). Для проектов с монорепозиторием добавьте watchFolders — это позволит Metro отслеживать изменения в пакетах за пределами корня проекта. Для настройки sourceExts добавьте 'svg', 'png', 'gql' для кастомных трансформеров. Metro поддерживает асинхронные конфигурации через async function — это полезно для динамической генерации конфига на основе окружения.
Оптимизация сборки Metro начинается с правильной конфигурации кеша. Установите maxWorkers равным числу CPU минус 1. Для дистрибутивов используйте resetCache на CI. Минимизируйте sourceExts — лишние расширения замедляют разрешение модулей. Для больших проектов настройте watchFolders только на необходимые директории. Metro поддерживает Hermes bytecode minification, который даёт меньший размер бандла чем стандартный Terser — используйте minifierPath: 'metro-minify-terser'.
Metro поддерживает режим сборки напрямую в Hermes bytecode — пропуская этап JavaScript AST. При сборке с HermesTransformer модули компилируются в HBC (Hermes ByteCode) вместо plain JavaScript. Это даёт: меньший размер бандла (на 30-40%), более быстрый старт приложения (на 20-30%) и меньшее потребление памяти. Для включения установите hermesCommand в metro.config.js и активируйте флаг Hermes в build.gradle (Android) или Podfile (iOS). Сборка Hermes-бандлов выполняется в два этапа: сначала Metro собирает JavaScript бандл, затем Hermes CLI конвертирует его в HBC. Начиная с React Native 0.70, Hermes является движком по умолчанию на Android, на iOS требуется явное включение.
Разница между Metro и Webpack обусловлена разными целями. Webpack — универсальный бандлер для веба с огромной экосистемой плагинов и лоадеров. Metro — специализированный бандлер для React Native, где приоритет — скорость инкрементальной сборки и корректная работа с нативными модулями. Webpack использует долгоживущий граф модулей с умной инвалидацией кеша — это даёт быстрые повторные сборки в вебе, но создаёт проблемы с платформенными расширениями. Metro не кеширует граф между сборками, а строит его каждый раз — это упрощает обработку платформенных расширений и Haste модулей. Webpack поддерживает динамические импорты с чанками, Metro — тоже, через React.lazy() и Suspense, но с ограничением на один активный requests. Экосистема Metro значительно меньше: нет замены style-loader, css-loader, file-loader — эти задачи решаются иначе в React Native.
Metro — единственно правильный выбор для React Native проектов. Webpack не поддерживает platform-aware resolution из коробки, и настройка React Native с Webpack требует значительных усилий (haul bundler, expo web packager). Metro интегрирован в React Native CLI, поддерживается официальной командой Meta и получает обновления с каждым релизом React Native. Для React Native Web проектов можно использовать Webpack для веб-сборки, сохраняя Metro для мобильных бандлов.
Часто задаваемые вопросы
Запустите npx react-native start --reset-cache или удалите папку $TMPDIR/metro-* и директорию .metro-health-check* в корне проекта. Альтернативно: npx react-native clean — эта команда очищает все временные файлы Metro, включая кеш Babel и Haste map. После очистки первая сборка будет полной (60-120 секунд), но последующие инкрементальные сборки вернутся к нормальной скорости.
Проверьте наличие пакета в package.json dependencies (не devDependencies). Если модуль находится в монорепозитории, добавьте путь в watchFolders metro.config.js. Metro не следует symlinks по умолчанию — используйте resolver.extraNodeModules для явного маппинга. Для Yarn PnM установите resolver.useWatchman: false. Если модуль использует платформенные расширения, убедитесь, что .ios.js или .android.js файлы существуют в указанном пути.
Увеличьте maxWorkers в metro.config.js до числа CPU минус 1. Настройте watchFolders только на необходимые директории. Используйте Hermes bytecode для продакшн сборок — это ускоряет финальную сборку за счёт пропуска JS минификации. Для разработки включите Fast Refresh (он включён по умолчанию). Ограничьте sourceExts только необходимыми расширениями. Рассмотрите разбиение бандла на чанки через lazy loading.
Технически да, но это не рекомендуется. Metro не оптимизирован для веб-сборок: отсутствует поддержка CSS, HTML, изображений как модулей, нет code splitting с динамическим импортом на уровне браузера. Для веба используйте Webpack, Vite или Parcel. Metro — специализированное решение для React Native, и попытка адаптировать его под веб приведёт к потере производительности и отсутствию экосистемы лоадеров.
Re.Pack — это community-инструмент для замены Metro на Webpack в React Native проектах. Он даёт доступ к экосистеме Webpack лоадеров (css-loader, svg-loader) и продвинутому code splitting. Однако Re.Pack сложнее в настройке, не поддерживается официально Meta и не гарантирует совместимость с новыми версиями React Native. Metro остаётся единственным официально поддерживаемым бандлером, что даёт стабильность и гарантию совместимости с каждым релизом.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также