Metro Bundler: что это, сборка проекта и принцип работы

Автор: IT Sectr Опубликовано: 2026-07-06 Время чтения: 8 мин

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-бандлер React Native с поддержкой платформенных расширений
  • Fast Refresh — горячая перезагрузка с сохранением состояния компонентов при изменении кода
  • Haste Module System — система стабильных module IDs для инкрементальных сборок
  • Платформенные расширения — .native.js, .ios.js, .android.js для разделения кода под платформу
  • Hermes bytecode — режим сборки напрямую в байт-код для движка Hermes

Что такое Metro Bundler

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

Архитектура 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: разрешение модулей и platform-aware поиск

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: Babel и транспиляция

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

Одна из ключевых особенностей 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.

js
// 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')],
};

Hot Reload и Fast Refresh в Metro

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 Refresh200-500msДаИзменение JS/TS файлов
HMR100-300msДаИзменение CSS/стилей
Live Reload1-3sНетИзменение native config
Full Rebuild10-60sНетИзменение podspec/build.gradle

Конфигурация Metro: metro.config.js

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'.

Hermes bundling: сборка в байт-код

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 vs Webpack: сравнение подходов

Разница между 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

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 для мобильных бандлов.

Часто задаваемые вопросы

Как очистить кеш Metro Bundler?

Запустите npx react-native start --reset-cache или удалите папку $TMPDIR/metro-* и директорию .metro-health-check* в корне проекта. Альтернативно: npx react-native clean — эта команда очищает все временные файлы Metro, включая кеш Babel и Haste map. После очистки первая сборка будет полной (60-120 секунд), но последующие инкрементальные сборки вернутся к нормальной скорости.

Почему Metro не видит модуль из node_modules?

Проверьте наличие пакета в package.json dependencies (не devDependencies). Если модуль находится в монорепозитории, добавьте путь в watchFolders metro.config.js. Metro не следует symlinks по умолчанию — используйте resolver.extraNodeModules для явного маппинга. Для Yarn PnM установите resolver.useWatchman: false. Если модуль использует платформенные расширения, убедитесь, что .ios.js или .android.js файлы существуют в указанном пути.

Как ускорить сборку Metro в большом проекте?

Увеличьте maxWorkers в metro.config.js до числа CPU минус 1. Настройте watchFolders только на необходимые директории. Используйте Hermes bytecode для продакшн сборок — это ускоряет финальную сборку за счёт пропуска JS минификации. Для разработки включите Fast Refresh (он включён по умолчанию). Ограничьте sourceExts только необходимыми расширениями. Рассмотрите разбиение бандла на чанки через lazy loading.

Можно ли использовать Metro для веб-проектов?

Технически да, но это не рекомендуется. Metro не оптимизирован для веб-сборок: отсутствует поддержка CSS, HTML, изображений как модулей, нет code splitting с динамическим импортом на уровне браузера. Для веба используйте Webpack, Vite или Parcel. Metro — специализированное решение для React Native, и попытка адаптировать его под веб приведёт к потере производительности и отсутствию экосистемы лоадеров.

Чем отличается Metro от Re.Pack?

Re.Pack — это community-инструмент для замены Metro на Webpack в React Native проектах. Он даёт доступ к экосистеме Webpack лоадеров (css-loader, svg-loader) и продвинутому code splitting. Однако Re.Pack сложнее в настройке, не поддерживается официально Meta и не гарантирует совместимость с новыми версиями React Native. Metro остаётся единственным официально поддерживаемым бандлером, что даёт стабильность и гарантию совместимости с каждым релизом.

Итоги

  • Metro Bundler — официальный JavaScript-бандлер React Native с архитектурой Resolver-Transformer-Bundler
  • Платформенные расширения (.ios.js, .android.js, .native.js) — ключевая фича для разделения платформенного кода
  • Fast Refresh — горячая перезагрузка с сохранением состояния компонентов, работающая через WebSocket
  • Конфигурация через metro.config.js: sourceExts, watchFolders, maxWorkers для оптимизации сборки
  • Hermes bytecode — режим сборки в байт-код для более быстрого старта и меньшего размера бандла
  • Resolver использует Haste Module System и platform-aware resolution — несовместимо с Webpack
  • Transformer работает параллельно через Babel с пулом worker-процессов
  • Metro входит в состав React Native CLI и не требует отдельной установки или настройки для старта

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также