Dev48
ЯЗЫК
  • О нас
  • Услуги
  • Индустрии
  • Технологии
  • Статьи
  • Контакты
Забронировать звонок
    Главная/Статьи/Pervyy vzglyad na expo modules 20
Dev48
info@dev48.org+375 29 320-40-96WhatsApp@isky_by

© 2026 · Все права защищены.

Первый взгляд на Expo Modules 2.0

Источник: Expo Blog•27 сентября 2026 г. в 08:41

Первый взгляд на Expo Modules 2.0

Expo Modules 2.0 превращает нативный модуль в аннотированный класс Swift или Kotlin. Никакого DSL, никакого шаблонного кода и до 5,6 раз более быстрые вызовы. Попробуйте на iOS в SDK 57.

Написание нативного модуля для React Native становится намного проще и быстрее. В Expo Modules 2.0 модуль — это просто аннотированный класс на Swift или Kotlin: вы пишете обычные методы и свойства, помечаете те, которые хотите сделать доступными из JavaScript, и на этом всё. Больше не нужно изучать ничего нового, кроме нескольких аннотаций, не нужно поддерживать шаблонный код, а во время выполнения эта система работает быстрее, чем заменяемый ею API.

Это краткая версия. API Expo Modules всегда брал на себя сложную работу по нативной интероперабельности: конвертацию данных между значениями JavaScript и нативными типами, запуск ваших функций в правильных потоках, чтобы ядра устройства задействовались без необходимости писать синхронизацию вручную, и интеграцию модуля в жизненный цикл приложения. Версия 2.0 меняет то, что пишите непосредственно вы. В 1.0 вы описывали то, что модуль экспортирует в JavaScript, с помощью специально созданного DSL. В 2.0 всё это берётся напрямую из нативного кода, а создание модуля сводится к написанию кода на Swift или Kotlin так же, как для любого приложения под iOS или Android.

Expo Modules 2.0 появится в скором времени, но на iOS её уже можно попробовать: SDK 57 включает макросы Swift, на которых она работает, охватывая модули, функции, записи, общие объекты и события. Компоненты пользовательского интерфейса ( Views) пока не поддерживаются (подробнее об этом ниже), а Android, для которого будет использоваться таческая же модель разработки, всё еще находится в разработке. В SDK 58 Expo Modules 2.0 перейдет в статус бета-версии: она будет задокументирована, официально поддерживаться и поставляться со специальным навыком (agent skill) для вашего ИИ-помощника, который обучит его новому API. Поскольку iOS идет первой, в примерах ниже используется Swift. Вот как это выглядит.

Если вы читали статью «Общение с JSI на Swift: что изменилось в SDK 56», этот пост является её продолжением и опирается на описанную там работу. На iOS в SDK 56 затрагивалась внутренняя часть вашего модуля: мы отказались от прослойки Objective-C++, поэтому теперь Swift напрямую взаимодействует с JSI, а вызовы происходят примерно в два раза быстрее. Подготовка для Android выглядела иначе — это плагин компилятора Kotlin, который переносит часть работы с этапа выполнения на этап сборки, о чем рассказано в статье «Как плагин компилятора Kotlin сократил время до первого рендеринга на Android на 30%». Данный пост посвящен коду, который вы пишете поверх этого фундамента.

Текущий DSL

Вот небольшой модуль, написанный с использованием API Expo Modules 1.0:

Это работает, и множество нативного кода в экосистеме Expo написано именно так. Но чтобы написать подобное, приходится держать в голове — или в контексте вашего ИИ-помощника — довольно много информации. DSL представляет собой собственную небольшую грамматику, построенную на функции Swift под названием result builders (это тот же механизм, который лежит в основе body в SwiftUI). Вам необходимо знать его словарь: Function, AsyncFunction, Property, Class, Events и так далее. Нужно указывать типы параметров замыкания и выбирать синхронный или асинхронный вариант. Ничто из этого не относится к тому, что делает ваш модуль, поэтому Expo Modules 2.0 полностью убирает это и переходит на чистый синтаксис Swift.

Тот же модуль в версии 2.0

Это весь модуль целиком. Это класс с аннотированными методами и свойствами, и ничего лишнего: никаких definition(), никаких Name(...) (имя по умолчанию совпадает с именем класса, если вы не передадите его в качестве аргумента макроса) и никаких строителей результатов. Каждый компонент DSL сводится к обычному объявлению в Swift.

И Function, и AsyncFunction становятся обычным методом Swift, отмеченным аннотацией @JS. Его имя и типы считываются непосредственно из объявления. Синхронным или асинхронным является метод, определяет ключевое слово async в Swift: асинхронный метод отображается в JavaScript как функция, возвращающая Promise.

Свойство Expo Modules 1.0 с геттером и сеттером теперь превращается в обычный var в Swift. Свойства Swift, доступные для записи (хранимые var-свойства и вычисляемые свойства с сеттером), доступны для записи и в JS. Доступные только для чтения свойства Swift (константы let и var-свойства только с геттером) доступны только для чтения в JS. Эти свойства доступны как из Swift, так и из JS и не требуют дополнительной настройки; в Expo Modules 2.0 API для определения свойств — это просто синтаксис Swift.

Миграцию не обязательно проводить единовременно. Оба API могут сосуществовать в рамках одного модуля: сохраните существующий definition(), добавьте @ExpoModule и переносите функции и свойства на @JS по одному. Всё, что еще не имеет аналога в 2.0, может просто оставаться в definition. Они объединяются, поэтому вы можете внедрять новшество постепенно, не переписывая весь модуль целиком.

Вам даже не обязательно выполнять конвертацию вручную. Навык expo-migrate-module позволяет вашему ИИ-помощнику перенести Swift-часть модуля с версии 1.0 на 2.0, сохраняя JavaScript API неизменным. Всё, что он еще не может перенести, он оставляет в definition() версии 1.0 и указывает в своем отчете, чтобы вы точно знали, что осталось сделать. Просто запустите:

Это запускает интерактивную сессию с загруженным навыком; замените claude-code на codex, cursor или любой другой используемый вами агент. Навык находится в плагине expo-experiments и развивается вместе с API, а команда use каждый раз подтягивает последнюю версию.

Записи, общие объекты и события получают такое же отношение

Функции — это не единственное, что меняется. Остальные строительные блоки модуля следуют той же идее перехода на нативный синтаксис.

Запись (record) представляет собой структуру Swift, а каждое хранимое свойство, которое не является private, static или lazy, становится полем. Является ли поле обязательным, опциональным или допускающим значение null, считывается прямо из объявления, и ничего дополнительного писать не нужно:

Общий объект (shared object) — это класс, экземпляры которого существуют одновременно и в Swift, и в JavaScript: JS удерживает объект, за которым стоит нативный экземпляр. Вы экспортируете его так же, как и модуль, с помощью методов и свойств @JS, включая инициализатор @JS init(), который становится конструктором в JS.

Сторона JS получает API в веб-стиле (currentTime в секундах, как у элемента HTML media), в то время как класс под капотом сопоставляет его с типами AVFoundation. Вы сами определяете структуру того, что видит JavaScript; аннотации просто переносят это через границу окружений.

В версии 1.0 событие представляло собой зарегистрированную строчку-имя плюс вызовы sendEvent(...):

В Expo Modules 2.0 событие — это единственное типизированное вызываемое свойство. Вы один раз объявляете тип полезной нагрузки (payload), а вызов этого свойства отправляет событие:

Полезная нагрузка может быть любого типа, который разрешено передавать в JavaScript: примитивы, массивы, словари, записи, общие объекты, типизированные массивы, буферы массивов, а также платформенные типы, такие как Data и Date, из коробки. Поддержка любого другого нативного типа требует лишь реализации протоколов JavaScriptEncodable и JavaScriptDecodable — точно так же, как вы внедряли бы собственный Codable в Swift. Если тип полезной нагрузки нельзя передать, компилятор Swift выдаст понятную ошибку во время сборки, поэтому вы узнаете о проблеме как можно раньше, еще до того, как пользователи получат ваше приложение.

Почему «просто натив» стал важнее, чем раньше

«Важнее, чем раньше» относится к тому, кто сейчас пишет код. Нативные модули всё чаще пишутся, проверяются и мигрируют с участием ИИ-агента в цикле разработки, и именно тот API, который вы передаете этому агенту, определяет эффективность такого взаимодействия. Всё, что делает версию 2.0 удобной для вас (меньше учить, типы в одном месте, ошибки там, где допущена опечатка), — это ровно то, что необходимо и языковой модели.

Модели обучаются на кодовой базе Swift и Kotlin за последнее десятилетие, в то время как у DSL версии 1.0 сравнительно мало примеров для обучения модели, поэтому сегодня агенту требуется подробное описание API в его контекстном окне. В версии 2.0 большую часть API составляет сам язык, поэтому учиться приходится гораздо меньшему. Кроме того, версия 2.0 сокращает цикл «генерация — ошибка — исправление», так как компилятор может находить некорректные типы в объявлениях вашего модуля и сообщать об ошибках в понятном для агента виде. Агент, способный написать приложение для iOS, сможет написать и модуль Expo.

Чище снаружи, быстрее внутри

Здесь также окупается работа, проделанная в SDK 56, и именно поэтому 2.0 — это нечто большее, чем просто эргономичный синтаксис.

Expo Modules 2.0 использует макрос времени сборки (@JS) для чтения сигнатур ваших функций на Swift, благодаря чему заранее известны точные типы каждого аргумента и возвращаемого значения. Версия 1.0 не может узнать их до момента выполнения, поэтому она работает по принципу рефлексии: каждый нативный вызов оборачивает входящие аргументы в выделенный контейнер с подсчетом ссылок, пропускает каждый из них через конвертер динамических типов в массив [Any] и формирует кортеж перед вызовом вашей функции. Этот динамический путь остается самой большой издержкой при вызове на сегодняшний день. Поскольку сигнатуры функций известны заранее, сгенерированные привязки считывают каждый аргумент прямо там, где его оставил JS-рантайм, и преобразуют его сразу в параметр Swift без выделения какой-либо дополнительной памяти. Работа по преобразованию типов, которую версия 1.0 повторяет при каждом вызове, в версии 2.0 происходит на этапе сборки, а накладные расходы на управление вызовами во время выполнения также исчезают.

Прирост скорости весьма значителен благодаря оптимизациям сразу в трех SDK. В SDK 56 был удален слой Objective-C++, что сделало вызовы модулей Expo в 1.5–2 раза быстрее, чем в SDK 55, и сравняло их по производительности с Turbo Modules в React Native. SDK 57 снова улучшает общую среду выполнения, и это улучшение идет на пользу абсолютно всем модулям, включая те, что остаются на версии 1.0. Как видно на графике, они стали работать быстрее без изменения ни единой строки кода. Вдобавок к этому макрос @JS устраняет те оставшиеся динамические накладные расходы на каждый вызов.

Это общее время для 100 000 вызовов, меньше — лучше:

Все показатели были измерены на одной конфигурации: iPhone 16 Pro под управлением iOS 27, релизная сборка с предкомпилированными фреймворками.

На том же SDK путь с использованием макроса @JS в 2.5–5.6 раза быстрее по сравнению с API версии 1.0 для синхронных вызовов. Асинхронные вызовы показывают близкие результаты, так как под капотом оба API используют один и тот же механизм промисов. Более серьезное улучшение для асинхронных вызовов появится в SDK 58. Теперь самый чистый API одновременно является и самым быстрым путем для обращения к модулю.

Что ждет версию 2.0 в будущем

Следующими на очереди будут представления (Views). Они будут следовать той же модели, что и модули: представление будет представлять собой класс, отмеченный как @ExpoView, а его пропсы и колбэки событий будут объявляться единожды в типизированной структуре @ViewProps вместо разделения на нативное представление и написанный вручную тип JS-пропсов.

Второй разрабатываемый компонент — это генерация TypeScript. Поскольку каждый элемент @JS, @Record и пропсы представлений уже содержат свои типы в нативной сигнатуре, инструмент сможет генерировать декларации TypeScript для модуля на основе этого источника. Сегодня вы пишете нативные типы и соответствующие им декларации TypeScript раздельно; суть в том, чтобы писать их один раз.

Это противоположность кодогенерации в некоторых других модулях React Native, где вы пишете спецификацию на TypeScript, а генератор создает шаблон нативного кода, который вам предстоит заполнить. С Expo Modules 2.0 вы используете нативные API платформы так же напрямую, как любое нативное приложение, остальная часть вашего приложения остается на React, а типы TypeScript проистекают из нативного кода. Декларации TypeScript для модуля становятся сгенерированным артефактом сборки, и CI может обнаруживать их рассинхронизацию с нативным кодом.

Инструментарий, создающий декларации TypeScript, сначала преобразует исходный код на Swift в машиночитаемую сводку всего, что экспортирует модуль: каждой функции, свойства, записи и события с указанием их типов. Эта сводка также дает преимущества подхода со спеками во главе угла: как только Android сможет формировать такую же сводку из своего исходного кода на Kotlin, инструментарий сможет сравнивать их и выявлять непреднамеренные различия между платформами еще до того, как они превратятся в баги в JS.

Когда я смогу это использовать?

🚀 Сегодня, на iOS, в SDK 57. Базовые макросы (@ExpoModule, @JS, @Record, @SharedObject, @Event) уже поставляются вместе с SDK. Они еще не документированы, поэтому их следует считать экспериментальными: API все еще может измениться, а руководства и справочные материалы появятся вместе с бета-версией SDK 58. Поддержка Android находится в разработке. Если вы хотите написать модуль для iOS таким образом уже сегодня, вы можете это сделать.

В более отдаленной перспективе Expo Modules 2.0 станет стандартным способом написания модулей Expo, в то время как версия 1.0 продолжит работать для всего, что уже было на ней создано. Если вы пишите нативные модули, попробуйте 2.0 в SDK 57 и расскажите нам в канале #creating-expo-modules в Discord для разработчиков Expo о том, что сработало, что нет и что вы хотели бы увидеть в дальнейшем. Официальная бета-версия появится в SDK 58.

← Все статьи

О чём эта статья

Ещё в разделе «Разработка ПО»

Все →
PrestaShop Payments: платежные решения по-новому для магазинов на PrestaShop
Prestashop

PrestaShop Payments: платежные решения по-новому для магазинов на PrestaShop

Лучшие стратегии SEO для малого бизнеса в 2026 году
Shopify

Лучшие стратегии SEO для малого бизнеса в 2026 году

Запуск экономичных постоянно работающих агентов для мониторинга вашей среды: техническая сторона Watchers
Grafana Labs

Запуск экономичных постоянно работающих агентов для мониторинга вашей среды: техническая сторона Watchers

Лучшее программное обеспечение для доставки: как выбрать подходящее решение для вашего бизнеса
Shipstation

Лучшее программное обеспечение для доставки: как выбрать подходящее решение для вашего бизнеса

Аналитика отправки: как превратить данные перевозчиков в лучшие решения по доставке
Shipstation

Аналитика отправки: как превратить данные перевозчиков в лучшие решения по доставке

Примеры платной таргетированной рекламы: эффективная реклама в соцсетях в 2026 году
Shopify

Примеры платной таргетированной рекламы: эффективная реклама в соцсетях в 2026 году

Ещё от Expo

Сколько инженеров нужно для создания социальной сети?
Expo

Сколько инженеров нужно для создания социальной сети?

Разбор нового слоя JNI в Expo Modules 2.0
Expo

Разбор нового слоя JNI в Expo Modules 2.0

Как один разработчик занял 2-е место в нидерландском App Store с образовательным приложением на Expo
Expo

Как один разработчик занял 2-е место в нидерландском App Store с образовательным приложением на Expo

Программа Apple Developer Program: бесплатная и платная версия
Expo

Программа Apple Developer Program: бесплатная и платная версия

Игра-головоломка про котиков на WebGPU, созданная на Expo за три дня с ИИ-агентом в роли отдела тестирования
Expo

Игра-головоломка про котиков на WebGPU, созданная на Expo за три дня с ИИ-агентом в роли отдела тестирования

Представляем @expo/agent-cli: CLI, созданный для агентов
Expo

Представляем @expo/agent-cli: CLI, созданный для агентов