Когда при запуске React Native-приложения в терминале появляется строка Metro waiting on exp://... или ошибка Unable to resolve module, виновником почти всегда оказывается именно загрузчик Metro — либо он не запущен, либо его кэш устарел, либо конфигурация не подхватывает нужные файлы. Понимание того, что это за инструмент и как он работает, снимает большинство вопросов при разработке под React Native.
Metro — это JavaScript-бандлер, который Facebook (ныне Meta) создал специально для экосистемы React Native. Его задача — взять весь ваш JS-код, стили, изображения и зависимости из node_modules, собрать их в единый бандл и отдать приложению на устройстве или эмуляторе. Без запущенного Metro приложение в режиме разработки просто не получит свой код и покажет красный экран с ошибкой подключения.
Что такое Metro и зачем он нужен
Если коротко: Metro — это аналог Webpack или Vite, но заточенный под мобильную разработку. Он выполняет три ключевые функции: разрешение модулей (находит, какие файлы импортируются), трансформацию кода (переводит JSX и современный JS через Babel в понятный движку приложения вид) и сборку бандла (склеивает всё в один файл).
Отдельная важная роль Metro — Fast Refresh, то есть мгновенное обновление интерфейса при правке кода без полной перезагрузки приложения. Именно Metro следит за изменениями файлов и отправляет обновлённый код на устройство. Поэтому разработчик видит правки на экране через секунду-две после сохранения файла.
В production-сборке Metro тоже участвует: команда npx react-native bundle использует его для создания финального бандла, который упаковывается в APK или IPA. Однако в повседневной разработке вы сталкиваетесь с ним как с локальным сервером на порту 8081.
Как запустить загрузчик Metro
В большинстве случаев Metro стартует автоматически. Когда вы выполняете команду запуска приложения, бандлер поднимается в фоне, если не обнаружен уже работающий экземпляр:
npx react-native start
Эта команда запускает Metro вручную в отдельном окне терминала. Альтернатива — привычные команды npx react-native run-android или run-ios, которые сами поднимают сервер, собирают нативную часть и устанавливают приложение. В проектах на Expo используется npx expo start, но под капотом работает тот же Metro.
После запуска в терминале появляется интерактивное меню Metro. Из него можно выполнять полезные действия без перезапуска:
- ⌨️ нажать
r— перезагрузить приложение на подключённом устройстве; - ⌨️ нажать
d— открыть меню разработчика на устройстве; - ⌨️ нажать
j— открыть отладчик (в поддерживаемых версиях); - ⌨️ нажать
c— очистить консольный вывод сервера.
⚠️ Внимание: если Metro запущен в одном проекте, а вы пытаетесь открыть приложение из другого проекта, бандл может собраться не из тех исходников. Перед сменой проекта останавливайте сервер сочетанием Ctrl+C и запускайте заново из нужной папки.
Настройка через metro.config.js
Поведение загрузчика управляется файлом metro.config.js в корне проекта. В современных версиях React Native базовая конфигурация подтягивается из пакета, а ваш файл лишь расширяет её через функцию mergeConfig. Точный состав настроек зависит от версии React Native, поэтому образец конфигурации стоит сверять с шаблоном вашей версии.
Чаще всего в конфигурацию вносят такие изменения: поддержку дополнительных расширений файлов (например, .svg через react-native-svg-transformer), настройку монорепозиториев с watchFolders, алиасы путей и параметры минификации. Изменения в metro.config.js применяются только после перезапуска сервера — горячего обновления самого конфига нет.
Пример задачи для metro.config.js
Если проект использует SVG как React-компоненты, в конфиг добавляют transformer от react-native-svg-transformer и переносят расширение svg из assetExts в sourceExts. Конкретный синтаксис зависит от версии Metro — берите его из документации пакета, а не копируйте устаревшие примеры из статей.
Типичные ошибки Metro и их решение
Большинство проблем с загрузчиком сводится к нескольким узнаваемым сценариям. Ниже — таблица частых симптомов и направлений диагностики.
| Симптом | Вероятная причина | Что проверить |
|---|---|---|
| Красный экран: не удаётся подключиться к серверу | Metro не запущен или устройство не видит порт | Запущен ли сервер; для Android — проброс порта через adb reverse |
| Unable to resolve module | Битый кэш или отсутствующая зависимость | Установлен ли пакет; перезапуск со сбросом кэша |
| Изменения кода не применяются | Watcher не отслеживает файлы | Перезапуск Metro; лимиты inotify на Linux |
| Ошибка после установки нового пакета | Старый бандл закэширован | Остановка сервера и запуск с --reset-cache |
| Порт 8081 занят | Другой процесс или второй экземпляр Metro | Завершить лишний процесс или указать другой порт |
Универсальный первый шаг при странном поведении — перезапуск с очисткой кэша:
npx react-native start --reset-cache
Эта команда заставляет Metro заново собрать весь граф зависимостей, что решает проблемы «призрачных» модулей и устаревших трансформаций. Для Android-устройств, подключённых по USB, также проверьте проброс порта командой adb reverse tcp:8081 tcp:8081 — без неё телефон не достучится до сервера на компьютере.
☑️ Диагностика Metro при ошибке бандла
⚠️ Внимание: не удаляйте папку node_modules и не переустанавливайте все зависимости при каждой ошибке Metro. В большинстве случаев достаточно сброса кэша бандлера — полная переустановка зависимостей оправдана только при повреждении самих пакетов или конфликте версий.
Производительность и кэширование
Metro спроектирован с упором на скорость: он хранит результаты трансформации файлов в кэше и пересобирает только изменённые модули. Именно поэтому первый запуск после --reset-cache заметно дольше последующих — бандлеру приходится обработать весь node_modules заново.
На скорость работы влияет и файловый наблюдатель. На Linux при очень больших проектах системный лимит inotify может оказаться недостаточным, из-за чего Metro перестаёт замечать изменения — это решается увеличением лимита на уровне ОС, а не настройками самого бандлера. На macOS и Windows подобная проблема встречается реже, но антивирус, сканирующий папку проекта, способен заметно тормозить сборку; добавление каталога проекта в исключения защитника — разумный шаг.
Metro и альтернативы
Формально Metro — не единственный бандлер для React Native: существуют экспериментальные решения вроде Re.Pack на базе Webpack. Однако Metro остаётся стандартом де-факто: его использует шаблон React Native по умолчанию, его же применяет Expo, и под него заточены Fast Refresh, символикация ошибок и интеграция с Hermes.
Менять бандлер имеет смысл только при осознанной необходимости — например, для сложных сценариев code splitting. Для типового проекта переход на альтернативу добавит больше проблем с совместимостью, чем пользы, поэтому разумнее освоить настройку самого Metro.
Часто задаваемые вопросы
Нужно ли устанавливать Metro отдельно?
Нет. Metro входит в зависимости React Native и ставится автоматически вместе с проектом через npm install. Отдельная глобальная установка не требуется — запускайте его через npx react-native start из папки проекта.
Почему приложение показывает красный экран с ошибкой подключения?
Чаще всего сервер Metro не запущен или устройство не может достучаться до порта 8081. Проверьте, что бандлер работает, а для Android по USB выполните adb reverse tcp:8081 tcp:8081. Устройство и компьютер при подключении по Wi-Fi должны быть в одной сети.
Чем Metro отличается от Webpack?
Metro оптимизирован под React Native: он быстро собирает большие графы модулей за счёт агрессивного кэширования, поддерживает платформенные расширения файлов (.ios.js, .android.js) и Fast Refresh из коробки. Webpack универсальнее, но требует дополнительной настройки для мобильной разработки.
Как применить изменения в metro.config.js?
Остановите сервер сочетанием Ctrl+C и запустите его заново, желательно с флагом --reset-cache. Конфигурация читается только при старте, поэтому горячая перезагрузка настроек невозможна.
Используется ли Metro в production-сборке?
Да. При создании релизной сборки Metro формирует финальный JS-бандл, который упаковывается внутрь приложения. В этом режиме сервер разработки не нужен — приложение работает автономно, без подключения к компьютеру.