Полка React Native и Expo: цена пакета — в клиенте, а не в килобайтах
Здесь будет встроен видео-разбор темы (5–7 минут, YouTube / RuTube / VK Видео) — тем, кто лучше воспринимает на слух, текст ниже не обязателен.
Снимок: сентябрь 2026, Expo SDK 57. Своими руками в этой части собраны окно списка, анимация на кадрах, worklet, маршруты со стеком и диск под памятью. У каждой миниатюры есть стена, и за стеной — пакет из npm. Но на телефоне цена пакета считается не в килобайтах, а в клиенте: пакет из SDK работает в Expo Go, чужой нативный — только в своей сборке. И версию нативного пакета выбираете не вы, а SDK. Версии на полке — снимок на дату проверки, а не вечная истина; как проверить строку самому, разбирает статья «Живой ли пакет».
Полка устроена так же, как вся часть: сначала то, что дают React Native и SDK Expo, и только за стеной — пакет. У каждой строки таблицы ниже есть паспорт: когда пакет не нужен, где в учебнике своя сборка, снимок с датой проверки и условие, при котором строку пора пересмотреть.
| Задача | Сначала | Если мало |
|---|---|---|
| навигация | expo-router из SDK | React Navigation напрямую — только в проекте без Expo |
| ключ-значение и секреты | expo-sqlite/kv-store и expo-secure-store | react-native-mmkv ценой своей сборки |
| база на устройстве | expo-sqlite | op-sqlite или PowerSync |
| серверные данные | в local-first — ничего: правда в SQLite | TanStack Query и Zustand, как в вебе |
| анимация и жесты | Animated с useNativeDriver | Reanimated и gesture-handler |
| длинные списки | FlatList после замера | FlashList или LegendList |
| камера и медиа | expo-image-picker | expo-camera; VisionCamera — если нужны сами кадры |
| клавиатура | KeyboardAvoidingView | react-native-keyboard-controller |
У полок для браузера отметка «что умеет платформа» — это Baseline, поддержка во всех основных браузерах. Здесь такого мерила нет: платформа телефона — React Native 0.86 и модули SDK 57, и столбец «Сначала» состоит из них.
В таблицах-снимках ниже столбец «Вес или цена» заполнен ценой, а не килобайтами. JavaScript пакета, конечно, едет в бандле, но раньше веса решает другое: заработает ли пакет в том клиенте, который у вас есть, — об этом следующий раздел. Столбец «Версия» — закрепление SDK 57 на сервере Expo на 14.09.2026, а не последняя версия в npm; последняя записана в цене, если отличается. У пакетов, которых SDK не знает, версия — последняя в npm.
Строка полки стареет не по календарю, а по событию: вышел новый SDK, модуль попал в Expo Go, в npm сменился мажор. Поэтому у каждого паспорта своё «Пересмотреть, если…».
Цена пакета на телефоне складывается из ответов на три вопроса, и у каждого ответа свой источник. Первый: знает ли пакет SDK — есть ли он в списке закреплений, где записано, какую версию ждёт данный SDK. Второй: есть ли у пакета нативная половина — код для iOS и Android в его архиве npm. Третий: вшит ли его модуль в Expo Go.
Третий вопрос решает бинарник, а не npm install. Модуль ищется по имени в реестре — «Модуль — это запись в реестре», — и найдётся, только если его вшили при сборке. Как это выглядит в Expo Go и в своей сборке, разобрано в «Expo Go — чужой бинарник с вашим бандлом»; там же вы запускали отказ AppMetrica.
Сведём три вопроса в одну функцию. Данные в ней записанные: выдержка из bundledNativeModules.json пакета expo 57.0.16, который стоит в проекте автора, выдержка из списка модулей Expo Go для SDK 57 и признак нативной половины по файлам архивов npm. Закрепление в таком списке — точная версия или диапазон с тильдой, тем же знаком, что в диапазонах npm. Пакетов семь: первые четыре стоят в apps/mobile, последние три читатель собирается поставить обычным npm install, то есть последних версий. Строка AppMetrica в выводе — напоминание о том запуске, новое здесь — версии. Прогноз: у каких пакетов функция найдёт расхождение с SDK и в какую сторону?
Расхождения бывают в обе стороны. react-native и react-native-screens в проекте старше закреплений. react-native-reanimated и @shopify/flash-list из npm, наоборот, новее — и для проверки Expo это такое же расхождение: последняя версия не значит подходящая. zustand SDK не знает, и ему не нужно: в пакете только JavaScript. А react-native-mmkv SDK не знает, нативная половина у него есть, а в Expo Go её нет — вместе с AppMetrica он и требует своей сборки.
Две верхние строки можно сверить с настоящим CLI. Переменная CI=1 нужна, чтобы команда только читала: без неё CLI в терминале спросит, не исправить ли версии сразу. В проекте автора, без сети:
Те же два пакета и те же версии. А теперь та же команда с сетью:
Четырнадцать строк вместо двух, и react-native теперь ждёт не 0.86.2, а 0.86.3. Причина — в исходнике @expo/cli 57.0.18, в функции getVersionedNativeModulesAsync. Без EXPO_OFFLINE CLI берёт список SDK с сервера Expo, а с ней — или если сервер не ответил — файл bundledNativeModules.json из установленного expo. Файл — снимок того патча, что стоит в проекте: 57.0.16 от 24.08.2026. Сервер — живой список, и на 14.09.2026 он знает патчи до expo 57.0.22. Поэтому функция выше, записанная по файлу, ждёт 0.86.2, а таблицы-снимки ниже пишут закрепления сервера — у react-native это 0.86.3.
Вопроса «работает ли пакет на новой архитектуре» среди трёх нет, и это не забыто. В React Native 0.86 старую архитектуру не включить — это видно в таблице «Что осталось от моста в 0.86», — поэтому в SDK 57 выбирать не из чего. Пометка «только новая архитектура» в README FlashList 2 и в ошибке Reanimated 4 — цена переезда для проекта на SDK 54: он держит React Native 0.81.5, последнюю линию, где старая архитектура ещё собиралась.
У функции есть и стена: в её данных нет поля peerDependencies. В этом поле пакет называет соседей, с которыми работает, но которых в себе не везёт; подробнее — в статье «Живой ли пакет», в вопросе о доле в нише. У react-native-reanimated 4.6.0 там записан react-native-worklets 0.12.x, а SDK 57 держит worklets 0.10.1. Поставить из npm одну библиотеку пары — значит разбить пару, и функция этого не заметит. Научить её — первая задача в конце статьи.
npm install меняет только JavaScript-половину. Всё, что пакет ищет в бинарнике, должно было попасть туда при сборке — в Expo Go его вшила команда Expo, в свою сборку вшиваете вы.
Что версии библиотек сообщества под SDK подбирает npx expo install, говорилось ещё в «Трёх этажах». Подбирать есть что: последняя версия в npm и версия, которую ждёт SDK, — разные числа. Вот как далеко на 14.09.2026 они разошлись у пакетов этой полки:
| Пакет | Последняя в npm | SDK 57 держит |
|---|---|---|
react-native | 0.87.1 | 0.86.3 |
react-native-reanimated | 4.7.1 | 4.5.1 |
react-native-worklets | 0.13.0; ветка 0.10 — под тегом legacy, 0.10.4 | 0.10.1 |
react-native-gesture-handler | 3.3.0; ветка 2 — под тегом legacy, 2.33.0 | ~2.32.0 |
react-native-keyboard-controller | 1.22.5 | 1.21.9 |
@react-native-async-storage/async-storage | 3.1.1 | 2.2.0 |
@shopify/flash-list | 2.3.2 | 2.0.2 — как и в SDK 54, 55, 56 и 58 |
Отсюда три команды. Нативный пакет ставят npx expo install <пакет>: CLI допишет к имени версию из списка SDK. Расхождения в уже поставленном ищут npx expo install --check, как в прошлом разделе, а правят npx expo install --fix — оба флага есть в справке @expo/cli 57.0.18.
Две оговорки из исходника той же команды, функции getVersionedPackagesAsync. Версию, указанную руками, — npx expo install react-native-reanimated@4.7.1 — CLI не подменяет: верит вам. А пакет, которого в списке SDK нет, уходит менеджеру пакетов как есть, то есть последней версией из npm. Для такого пакета диапазон — ваш: проверять его на устройстве, помня, что старой архитектуры в SDK 57 нет, и держать запасной выход на случай, если пакет перестанет обновляться.
Закрепление меняется и внутри одного SDK. В файле expo 57.0.16 у react-native записано 0.86.2, а сервер для SDK 57 на 14.09.2026 отдаёт 0.86.3: номер SDK прежний, закрепление новое.
npm install ставит последнюю версию, npx expo install — ту, с которой собран ваш SDK. Для нативного пакета права вторая.
Начнём с темпа. В таблице — даты выпуска expo x.0.0 по реестру и версия React Native в списке каждого SDK на сервере Expo.
| SDK | Выпуск | React Native |
|---|---|---|
| 53 | 28.04.2025 | 0.79.6 |
| 54 | 10.09.2025 | 0.81.5 |
| 55 | 25.02.2026 | 0.83.10 |
| 56 | 20.05.2026 | 0.85.3 |
| 57 | 30.06.2026 | 0.86.3 |
| 58 | preview: 58.0.0-preview.0 — 10.09.2026, 58.0.0-preview.1 — 14.09.2026, под тегом next | 0.88.0-rc.0 |
За год до снимка вышли три SDK, и каждый принёс новую линию React Native. Новый react-native — это новый бинарник: в таблице «Долетит или нужна сборка» правка «поднять react-native» меняет отпечаток. По воздуху такое обновление к установленным приложениям пускать нельзя — от этого их и бережёт замок из статьи «runtimeVersion: замок, который бережёт установленные приложения». А Expo Go из магазина собран под одну версию SDK («Свой проект»); на 14.09.2026 сервер Expo называет для него SDK 57.
SDK 58 уже виден: он в preview, и сервер Expo отдаёт его список. Что в нём ждёт пакеты этой полки:
Список preview меняется на глазах: в тот же день, до выхода 58.0.0-preview.1, сервер отдавал для SDK 58 react-native 0.87.1, а теперь — кандидат в релиз 0.88.0-rc.0. Главная перемена для полки — react-native-gesture-handler ~3.2.1, новый мажор: по типам пакета 3.3.0 жесты в нём объявляются хуками вроде usePanGesture, а прежние объекты получили приставку Legacy — LegacyPanGesture, LegacyScrollView. Остальное — шаги внутри мажора: reanimated 4.6.0, keyboard-controller 1.22.4, а flash-list остаётся на 2.0.2.
Порядок обновления из этого и следует. Прочитать журнал изменений нового SDK — его адрес сервер Expo отдаёт сам, в поле releaseNoteUrl: у SDK 57 это expo.dev/changelog/sdk-57, а у SDK 58 в preview такого поля ещё нет. Поднять expo и выровнять остальное npx expo install --fix. Проверить проект целиком — для этого у Expo есть отдельный пакет expo-doctor: по описанию в реестре он ищет в проекте известные проблемы, запускается npx expo-doctor. Собрать новый dev client, проверить на устройстве — и только потом выпускать сборку и обновления к ней.
Пересмотреть, когда SDK 58 выйдет из preview: сверить закрепления всей полки.
Не нужна для пары настроек: kv-store и SecureStore из SDK. Своя сборка: ящик строк по ключу, где каждый вызов — промис, в «Асинхронном ящике», а в разделе «Данные — в базе, токен — в SecureStore» — expo-sqlite/kv-store, замена AsyncStorage один в один, и expo-secure-store для токена.
| Библиотека | Версия | Вес или цена | Проверено |
|---|---|---|---|
expo-secure-store | ~57.0.4 | в SDK 57; есть в Expo Go | 14.09.2026 |
expo-sqlite | ~57.0.3 | в SDK 57; есть в Expo Go; kv-store внутри | 14.09.2026 |
react-native-mmkv | 4.3.2 | нет в SDK; нативный (Nitro); нужен dev client | 14.09.2026 |
@react-native-async-storage/async-storage | 2.2.0 | в SDK 57 и в Expo Go; в npm уже 3.1.1 | 14.09.2026 |
На полке — kv-store и SecureStore. AsyncStorage остаётся там, где он уже стоит: SDK 57 и Expo Go держат 2.2.0 при 3.1.1 в npm, поэтому ставят его только через npx expo install.
react-native-mmkv — запас на случай, когда ящика строк мало. Синхронность сама по себе не довод: у kv-store тоже есть getItemSync. Довод — то, чего у kv-store нет: хук useMMKVString(key) перерисовывает компонент, когда значение по ключу меняется, а режим multi-process в спецификации пускает к тому же хранилищу расширения приложения и фоновые службы. Четвёртая версия построена на Nitro Modules — это отдельный нативный пакет react-native-nitro-modules того же автора, и mmkv 4.3.2 требует его в peerDependencies. Ни mmkv, ни nitro-modules нет ни в списке SDK 57, ни в Expo Go (проверено 14.09.2026), поэтому цена — своя сборка, а версия — ваша.
Пересмотреть, если SDK перейдёт на async-storage 3 или mmkv попадёт в Expo Go.
Не нужна, если данные живут на сервере: хватит кеша запросов. Если же главная копия в телефоне, своя сборка — главы 6 и 7: от «Главная копия — в телефоне» до настоящей базы в «expo-sqlite: настоящая база в телефоне», а сравнение готовых движков — в таблице «Что брать и чем платить».
| Библиотека | Версия | Вес или цена | Проверено |
|---|---|---|---|
@op-engineering/op-sqlite | 18.2.1 | нет в SDK; нативный; dev client | 14.09.2026 |
@powersync/react-native | 2.2.1 | нет в SDK; нативная половина через op-sqlite; dev client | 14.09.2026 |
Первый выбор — expo-sqlite из раздела выше: он в SDK и в Expo Go. @op-engineering/op-sqlite — запас на случай, когда упираетесь в скорость: в реестре он описывает себя как самый быстрый SQLite для React Native. Цена у него видна там же: распакованный пакет весит 351,7 миллиона байт. В архиве лежат исходники SQLite и SQLCipher, а для libsql и Turso — готовые библиотеки под каждую архитектуру Android и iOS.
PowerSync — запас для синхронизации с сервером. Нативная часть самого @powersync/react-native 2.2.1 маленькая — модуль PowerSyncOpSqlite для iOS и Android, — а база под ним — op-sqlite: в peerDependencies стоит @op-engineering/op-sqlite от 17.1.0 до 19. Та же строка «нативный код» есть в таблице движков.
Пересмотреть, если PowerSync сменит нативный драйвер или expo-sqlite получит синхронизацию.
Не нужны в local-first, где правда хранится в SQLite. Своя сборка — врезка «Кеш запросов — не движок синхронизации»: там TanStack Query из проекта автора настроен правильно, и там же видно, что его clear() в local-first стирает оригинал.
Если данные всё-таки живут на сервере — общий справочник упражнений, чужие программы тренировок, — полка та же, что в вебе. TanStack Query и Zustand — чистый JavaScript: в архивах @tanstack/react-query 5.102.8 и zustand 5.0.15 нет кода для iOS и Android, поэтому Expo Go им не помеха, а SDK их не закрепляет. Где у них стены и почему на полке именно они, разобрано на полке React и Next. В проекте автора стоят оба: @tanstack/react-query 5.102.3 и zustand 5.0.15.
| Библиотека | Версия | Вес или цена | Проверено |
|---|---|---|---|
@tanstack/react-query | 5.102.8 | только JS; SDK не закрепляет | 14.09.2026 |
zustand | 5.0.15 | только JS; SDK не закрепляет | 14.09.2026 |
Пересмотреть, если TanStack Query или Zustand выпустят v6.
Не нужна для простых переходов: Animated с useNativeDriver. Своя сборка — глава 8: значение, подписка и кадр в «Собираем анимацию», описание анимации во втором потоке в «useNativeDriver: два потока», функция в другом потоке в «Worklet: функция, уехавшая в другой поток» и то, почему сам Reanimated не запускается в предпросмотре, — «Почему Reanimated нет в предпросмотре».
| Библиотека | Версия | Вес или цена | Проверено |
|---|---|---|---|
react-native-reanimated | 4.5.1 | в SDK 57 и в Expo Go; в npm 4.7.1 | 05.10.2026 |
react-native-worklets | 0.10.1 | в SDK 57 и в Expo Go; в npm 0.12.2 | 14.09.2026 |
react-native-gesture-handler | ~2.32.0 | в SDK 57 и в Expo Go; в npm 3.3.0 | 14.09.2026 |
Reanimated и worklets ставятся парой, и пару держит SDK. react-native-reanimated 4.5.1 просит в peerDependencies react-native-worklets 0.10.x, а 4.7.1 — уже 0.13.x (по реестру на 05.10.2026). npm install react-native-reanimated принесёт 4.7.1 к worklets 0.10.1 из SDK, и пара разбита. У gesture-handler в npm уже мажор 3, а ветка 2 живёт под тегом legacy: SDK 57 держит ~2.32.0, и хуков вроде usePanGesture в этой версии ещё нет.
Пересмотреть с выходом SDK 58: gesture-handler переходит на 3.
Не нужна, пока замер не показал проблем FlatList. Своя сборка: деление, распорки и запас в «Собираем окно», а счёт строк и вызовов — в таблице «Что на телефоне иначе», где песочница сверена с React Native 0.86.
| Библиотека | Версия | Вес или цена | Проверено |
|---|---|---|---|
@shopify/flash-list | 2.0.2 | в SDK 57; только JS; в npm 2.3.2 | 14.09.2026 |
@legendapp/list | 3.3.11 | нет в SDK; только JS | 14.09.2026 |
FlashList 2 и LegendList 3 — чистый JavaScript: в архивах npm @shopify/flash-list 2.0.2 и 2.3.2 и @legendapp/list 3.3.11 нет ни ios/, ни android/, ни podspec (проверено 14.09.2026). Поэтому то, что FlashList нет в списке Expo Go, ему не мешает: вшивать нечего. Версию FlashList всё равно выбирает SDK, а LegendList SDK не знает, и его версия — ваша.
Пересмотреть, если SDK поднимет закрепление flash-list выше 2.0.2.
Не нужна камера, чтобы выбрать фото: хватит пикера. Своя сборка — «Настоящий Expo: пикер, файл и отправка»: пикер отвечает адресом файла, а в SDK 57 глобальный fetch — это expo/fetch, и часть формы { uri, name, type } он отклоняет.
| Библиотека | Версия | Вес или цена | Проверено |
|---|---|---|---|
expo-image-picker | ~57.0.20 | в SDK 57; есть в Expo Go | 05.10.2026 |
expo-camera | ~57.0.6 | в SDK 57; есть в Expo Go; тег latest в npm — 57.0.6 | 05.10.2026 |
expo-image | ~57.0.5 | в SDK 57; есть в Expo Go | 14.09.2026 |
expo-audio | ~57.0.5 | в SDK 57; есть в Expo Go | 14.09.2026 |
expo-video | ~57.0.5 | в SDK 57; есть в Expo Go | 05.10.2026 |
react-native-vision-camera | 5.2.3 | нет в SDK; нативный; dev client | 14.09.2026 |
Всё, кроме последней строки, — модули SDK, и в Expo Go они уже есть. Но и им нужен npx expo install: тег latest в npm живёт своей жизнью, а закрепление SDK — своей (на 14.09.2026 latest у expo-camera стоял на 57.0.4, ниже закрепления, к 05.10.2026 догнал его). expo-av в этом списке больше нет: его убрали из SDK 55, и звук с видео теперь у expo-audio и expo-video — подробнее в разделе «Сошли с полки».
VisionCamera — запас для случая, когда нужны сами кадры: у react-native-vision-camera 5.2.3 есть useFrameOutput и тип Frame. Как и mmkv, пятая версия стоит на Nitro Modules — в её peerDependencies react-native-nitro-modules и react-native-nitro-image, — а в SDK её нет, так что и цена та же: своя сборка.
Пересмотреть с выходом SDK 58: сверить закрепления expo-image-picker, expo-camera, expo-image, expo-audio и expo-video.
Не нужна для одного поля: KeyboardAvoidingView. Своя сборка — «Клавиатура — ещё один нижний край»: события Keyboard, расчёт сдвига по исходнику KeyboardAvoidingView и правило, что отступ клавиатуры и отступ безопасной зоны не складывают.
| Библиотека | Версия | Вес или цена | Проверено |
|---|---|---|---|
react-native-keyboard-controller | 1.21.9 | в SDK 57 и в Expo Go; в npm 1.22.5 | 14.09.2026 |
react-native-keyboard-controller есть и в SDK 57, и в Expo Go, так что цена у него только в соседях: в peerDependencies стоит react-native-reanimated не ниже 3.0.0. Reanimated в SDK тоже есть, и npx expo install поставит обоих в версиях одного SDK.
Пересмотреть с выходом SDK 58: его список уже держит 1.22.4.
Эти пакеты ещё встречаются в старых проектах и ответах на форумах. У каждого — дата последнего выпуска, номер вопроса из «Живой ли пакет», на котором он отсеялся, и что брать вместо. Номера те же: 0 — не умеет ли этого платформа, 1 — жив ли пакет. На телефоне платформа — это и SDK Expo.
| Пакет | Последний выпуск | Вопрос | Что вместо |
|---|---|---|---|
expo-av | 16.0.8 от 05.12.2025 | 0: удалён из SDK 55; в списке SDK 54 он ещё есть, с закреплением ~16.0.8 | expo-audio и expo-video — раздел «Камера, медиа, файлы» |
react-native-fast-image | 8.31.1 от 04.10.2026; до того молчал с 31.10.2022 | 0 и 1: кешировать картинки на диске умеет expo-image из SDK — у него cachePolicy по умолчанию "disk"; всплеск выпусков пакета в октябре 2026 после четырёх лет молчания — смена рук, а не повод вернуться | expo-image |
Moti, moti | 0.30.0 от 29.01.2025 | 1: последний коммит в репозитории — 11.03.2025 | Reanimated напрямую — раздел «Анимация и жесты» |
WatermelonDB, @nozbe/watermelondb | 0.28.0 от 07.04.2025 | 1: ни одного коммита после 11.08.2025 | expo-sqlite или PowerSync — раздел «База на устройстве» |
WatermelonDB сошёл с полки, но не из учебника: его разбор в статье «Готовые движки: WatermelonDB и PowerSync» остаётся, и читать его стоит как устройство движка синхронизации, а не как совет, что ставить.
Сошедший пакет не обязательно выкорчёвывать завтра. Но новый код на нём не пишут, а при переходе на новый SDK его меняют первым.
Пакеты ниже живы и не помечены устаревшими. Отказ — не оценка качества. У двух первых это вопрос 4 из «Живой ли пакет»: навязывает ли пакет устройство проекта. Оговорка та же, что на полке React и Next: вопрос 4 совпадает с укладом автора — стили здесь пишутся через StyleSheet.create, — поэтому у каждой строки названа причина, которую можно проверить.
| Пакет | Что проверено | Почему не на полке |
|---|---|---|
| NativeWind | nativewind 4.2.6 от 22.06.2026; в peerDependencies — tailwindcss | вопрос 4: стили переезжают в разметку классами Tailwind, а учебник пишет StyleSheet.create |
| Tamagui | tamagui 2.7.7 от 15.08.2026; описание в реестре обещает стили, компоненты и оптимизирующий компилятор | вопрос 4: своя система стилей и свой компилятор — экраны проекта пишутся уже на них |
| Аналитика и крэши | @react-native-firebase/app 26.4.0 и @appmetrica/react-native-analytics 4.2.0; в проекте автора стоят Firebase 26.3.2 и AppMetrica 4.2.0 | не паспорт полки: метка события, очередь, стек из прода и группы отчётов разобраны в «После релиза», а цена нативного SDK видна в функции из раздела о цене. Где сервис хранит данные пользователей — ещё и юридический вопрос; с 01.07.2025 действует Федеральный закон от 28.02.2025 № 23-ФЗ, учебник его не решает |
Строка аналитики отличается от остальных: отказ здесь не пакету, а паспорту. Ставить ли SDK аналитики, решает продукт, а полка может только назвать цену: нативная половина вне Expo Go и данные пользователей на чужом сервере.
Вопрос 4 не запрещает пакет. Он предупреждает, что уйти с него — значит переписать экраны, а не поменять строку в package.json.
- На телефоне цена пакета — клиент: знает ли пакет SDK, есть ли у него нативная половина и вшит ли модуль в Expo Go. Пакет из SDK работает в Expo Go, чужой нативный — только в своей сборке, чистый JavaScript — везде.
- Версию нативного пакета выбирает SDK:
npx expo installставит закрепление,--checkищет расхождения,--fixих правит. Последняя в npm бывает новее закрепления — reanimated 4.6.0 при 4.5.1 в SDK 57, — и это тоже расхождение. - У закреплений два источника: файл
bundledNativeModules.jsonустановленногоexpo— снимок патча — и живой список SDK на сервере Expo. СEXPO_OFFLINECLI сверяет с файлом, без неё — с сервером; в проекте автора это 2 расхождения против 14. - Соседей пакета называет поле peerDependencies: reanimated 4.6.0 просит worklets 0.12.x, а SDK 57 держит 0.10.1. Поставить из npm одну библиотеку пары — значит разбить пару.
- За год до снимка вышло три SDK, и каждый принёс новую линию React Native, то есть новый бинарник: обновление SDK — новая сборка и проверка на устройстве, а не обновление по воздуху. SDK 58 уже в preview, и gesture-handler там переходит на мажор 3.
- Каждая таблица полки — снимок на 14.09.2026 с ценой и условием «Пересмотреть, если…»; сошедшие пакеты названы с датой и вопросом, на котором отсеялись, отвергнутые — с причиной, которую можно проверить.
1/4В проект на SDK 57 добавили react-native-mmkv и открыли его в Expo Go из магазина. Что будет?
2/4CI=1 EXPO_OFFLINE=1 npx expo install --check нашёл в проекте два расхождения, а та же команда без EXPO_OFFLINE — четырнадцать. Почему?
3/4@shopify/flash-list нет в списке модулей Expo Go. Нужна ли ради него своя сборка?
4/4Проект на SDK 57, npm install react-native-reanimated поставил 4.6.0. Что сломалось?
Разбитая пара
Функция из раздела о цене не видит peerDependencies. Здесь у неё есть это поле, но только для соседства reanimated и worklets. Допишите peerProblems: для каждого поставленного пакета найти в peers его соседей, отыскать соседа среди поставленных и, если его версия не попадает в диапазон вида 0.12.x, вернуть строку «пакет, версия, просит такого-то соседа такого-то диапазона, а стоит такая-то версия». Прогноз до правки: что напечатает пример как есть?
Диапазон вида 0.12.x сверяется по частям: x подходит к чему угодно, остальные части должны совпасть.
Теперь вторая строка другая: npm install: react-native-reanimated 4.6.0 просит react-native-worklets 0.12.x, стоит 0.10.1, а первая по-прежнему «соседи сходятся». Настоящие диапазоны разнообразнее: у того же reanimated 4.6.0 рядом записан react-native 0.83 - 0.87, у keyboard-controller — >=3.0.0, и разбирает их npm по правилам semver. Своя функция на один вид диапазона — только модель. В проекте разбитую пару покажет уже npx expo install --check: reanimated 4.6.0 не совпадёт с закреплением 4.5.1.
Крышка вместо тильды
В списке закреплений SDK 57 почти все записи — точная версия или тильда, но две — с крышкой ^: @expo/vector-icons и react-native-bootsplash. Функция fits из раздела о цене крышку не понимает и сравнивает такую запись с версией как строку. Научите её: ^15.0.2 принимает тот же мажор и версию не ниже. Прогноз: сколько из трёх строк скажут «версию держит SDK» до правки и сколько — после?
Мажор сравнивается при любом знаке, дальше тильда требует тот же минор, а крышка — версию не ниже:
До правки «держит» не сказала ни одна строка, после — одна: @expo/vector-icons: версию держит SDK, потому что 15.1.1 попадает в ^15.0.2. Screens 4.25.2 ниже закрепления ~4.26.0, а bootsplash 7.3.3 — последний в npm на 14.09.2026 — ушёл в новый мажор, и крышка его не пропускает. Одна оговорка: у версий с мажором 0 крышка по semver строже — ^0.10.1 держит и минор, — но в списке SDK 57 таких записей нет.
Какой клиент нужен
Проект на SDK 57 открывают в Expo Go. Для каждой команды решите: хватит ли Expo Go после неё и кто выбрал версию — SDK или вы. В одной из команд есть ловушка.
| № | Команда |
|---|---|
| 1 | npx expo install @shopify/flash-list |
| 2 | npm install react-native-mmkv react-native-nitro-modules |
| 3 | npx expo install expo-camera |
| 4 | npm install @legendapp/list |
| 5 | npm install react-native-gesture-handler |
1. Expo Go хватит: у FlashList нет нативной половины. Версию выбрал SDK — 2.0.2, хотя в npm 2.3.2.
2. Нужна своя сборка: оба пакета нативные, и ни в списке SDK, ни в Expo Go их нет. Версии ваши — CLI Expo их бы и не подобрал.
3. Expo Go хватит: модуль из SDK, вшит в Expo Go. Версию выбрал SDK — закрепление ~57.0.5.
4. Expo Go хватит: в архиве @legendapp/list 3.3.11 нет кода для iOS и Android. SDK пакета не знает, поэтому npm install здесь не ошибка — версия ваша при любой команде.
5. Ловушка. npm install принесёт 3.3.0 — новый мажор, — а в Expo Go для SDK 57 вшит gesture-handler ~2.32.0. JavaScript-половина пакета и нативная половина в бинарнике окажутся из разных мажоров. Правильная команда — npx expo install react-native-gesture-handler: она поставит ~2.32.0.
Общее правило: клиент решает нативная половина, а версию — есть ли пакет в списке SDK. Команда npx expo install ничем не хуже npm install: пакет из SDK она закрепит, а чужой пропустит к npm как есть.