expo-migrate-module について
Expo モジュールの保守担当者向けに、JavaScript の契約を保ちながら Swift 実装を 2.0 API へ移行するスキルです。実行時の対応状況を確認し、段階的に移行してサンプルアプリで動作を検証します。
主な機能
- 01既存の JS API の維持
- 02マクロと実行時対応の確認
- 03混在モードでの段階的な移行
- 04スレッド動作と互換性の監査
- 05サンプルアプリのビルドとテスト
活用シーン
- 01既存の Swift Expo モジュールの更新
- 02未対応の 2.0 機能への安全な対処
- 03JS から見える動作の維持
- 04移行後のネイティブモジュール登録確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ expo/ skills --skill expo-migrate-moduleインストール後、Claude Code で/expo-migrate-moduleを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlreferences/compatibility.mdexample.mdmigration-map.md詳細
Expo モジュールの移行
既存の Expo モジュールの Swift 側を、外部から見える JS API を変更せずに移行します。現在の JS/TypeScript のインターフェイスとテストを互換性の基準として扱います。ユーザーが明示的にタスクの範囲を広げない限り、Kotlin は 1.0 DSL のままにします。
前提条件
expo 57.0.21 以降を使用してください。それ以前の 57.x バージョンではマクロをコンパイルできますが、2.0 の多くの機能やパフォーマンス最適化が不足しているため、対象にしないでください。編集前に、対象のインストール済みバージョン(package.json/ロックファイル内の expo、または npm ls expo)を確認してください。それより古い場合は作業を止め、まずアップグレードするようユーザーに伝えてください。
モジュールのルートだけでなく、サンプルアプリ独自の package.json も確認してください。手順 4 でビルドして起動する統合対象はサンプルアプリなので、同じ最低バージョン要件を満たす必要があります。
これは最低要件であり、保証ではありません。正確なマクロとコアのインターフェイスは 57.x 内でも異なるため、手順 2 でチェックアウト済みのソースを確認する必要があります。
SDK 57 ではマクロは実験的かつ非公開ドキュメントとして提供されており、公式ベータ版は SDK 58 です。API は今後変更される可能性があります。大規模な移行の前には、この点をユーザーに伝え、モジュール全体を一括で変換するよりも、段階的な混在モードへの移行を優先してください。
参考資料
- ソースを変更する前に
references/migration-map.mdを読んでください。1.0 から 2.0 への対応関係、意味上の注意点、混在モードのルールが記載されています。 references/example.mdを読み、1 つのモジュールを混在モードから完全な移行まで進める手順を通して確認してください。メンバーごとのルールがどのように組み合わさるか確認する必要がある場合に参照してください。- チェックアウト済みの
expo-modules-coreのバージョンまたはブランチが、要求されたすべてのマクロに対応しているか不明な場合は、references/compatibility.mdを読んでください。バージョン番号だけで推測せず、実際のコンパイル時および実行時のインターフェイスを確認する方法と、マクロプラグインが0.10.0までに追加した機能が説明されています。
ワークフロー
1. 互換性の基準を確立する
編集前に、リポジトリの指示とワークツリーを確認してください。Swift のモジュールクラス、レコード、共有オブジェクト、ネイティブビュー、JS/TS バインディング、テスト、サンプルアプリ、podspec、expo-module.config.json、インストール済みまたはチェックアウト済みの expo-modules-core を特定してください。
書き換える前に、エクスポートされている項目をすべて洗い出してください。
- モジュール名と共有オブジェクトの JS 名
- 関数名、引数の数、ラベル、デフォルト値、null 許容性、同期/非同期動作、エラー、キュー/スレッドのセマンティクス(ブロッキング処理または長時間実行処理を行う
AsyncFunction本体と、.runOnQueue(...)の有無を記録してください) - プロパティ名、変更可能性、定数のキャッシュ動作
- イベントのワイヤ名とペイロードの形状
- レコードのフィールド名、デフォルト値、必須性、null 許容性
- 共有オブジェクトのコンストラクターとインスタンス/静的メソッドの配置(
FunctionとStaticFunction/StaticAsyncFunctionの別) - ライフサイクルフックとビュー
あいまいな点は TypeScript の宣言と JS の呼び出し箇所を使って確認してください。構文の移行中に、必須性を暗黙に「改善」したり、イベント名を変更したり、同期動作を変更したりしないでください。
2. 利用可能な 2.0 のインターフェイスを確認する
対象が実際に使用している依存関係のマクロ宣言と、対応するコアフックを確認してください。1 つのマクロがコンパイルできるからといって、2.0 の設計に含まれるすべての項目が利用可能だと想定しないでください。
1.0 の各項目を次のように分類してください。
- 移行: マクロと必要なコアランタイムのサポートが両方存在する。
- DSL に残す: 混在モードで安全に維持できる、または 2.0 に相当する機能がない。
- ブロック: 移行によって JS の互換性が変わる、または利用できないランタイムサポートが必要になる。
推測に基づいて生成コードを書くより、段階的に混在モードへ移行することを優先してください。残りの DSL 要素がある場合は definition() を維持してください。中身が空で、@ExpoModule によって解決済みのモジュール名が維持される場合に限り、削除してください。
3. 移行を適用する
モジュールの命名、関数、プロパティ/定数、イベント、共有オブジェクト、レコードの順に、意味上のグループごとに移行します。差分は最小限に抑えてください。
以下の不変条件を守ってください。
- Swift の命名規則やマクロのデフォルト値が異なる場合は、既存の JS から見える名前をすべて明示的に維持してください。
- 元のオプション指定やデフォルト値の動作を維持してください。2.0 で必須フィールドを表現できるからといって、1.0 で任意だったレコードのフィールドを必須にしてはいけません。
- チェックアウト済みのマクロが同じ JS 名のオーバーロードをグループ化してディスパッチする場合を除き、同じ JS 名のオーバーロードは移行しないでください。
- 非同期処理のスレッド動作を維持してください。1.0 の
AsyncFunctionの本体は JS スレッド外で実行されていましたが、2.0 のasyncな@JSメンバーは JS スレッド上で開始し、最初のawaitで初めてスレッドを離れます。そのため、一度も await しない本体は JS のシグネチャに変更がなくても JS スレッドをブロックします。最初のawaitより前に実行される処理を監査し、ブロッキング I/O を JS アクター上に残さないでください。@JS(.concurrent)を使うか、Swift Concurrency または継続に移行して構成し直してください。キューに固定された関数も同様に扱います。詳しくはreferences/migration-map.mdのスレッド処理のセクションを参照してください。 - ビュー、ユニオン、同期イベント、共有オブジェクトの静的メンバー、自由形式の
Any引数を移行する前に、コアでのサポートを確認してください。これらはどれも、コアより先にマクロプラグインがリリースされているため、プラグインのバージョンではなく、チェックアウト済みのコアを確認し、サポートされていないメンバーは 1.0 DSL に残してください。機能ごとの確認方法はreferences/compatibility.mdに記載されています。 expo-module.config.jsonのapple.modulesには、すべてのモジュールクラスを記載したままにしてください。エントリは Swift のクラス名のみなので、移行中にクラス名を変更するとモジュールが気付かれないまま切り離され、ビルドは成功しても実行時に見つからなくなります。移行後のクラスもpublicまたはopenのままにしてください。これらのエントリが不要になるのは SDK 58 の自動検出からです。- ユーザーが API の変更を依頼していない限り、Kotlin、JS ラッパー、公開
.d.tsファイルは変更しないでください。 - マクロが生成するシンボルをモジュールのソースに書き込まないでください。シンボルはマクロが生成するものであり、手書きしたりオーバーライドしたりすることは移行の一部ではありません。
各グループの移行後に、移行対象となる古い DSL のエントリと呼び出し箇所を検索してください。広範なフォーマット変更や無関係な整理は避けてください。
2.0 に相当する機能がない場合、またはグループの移行に失敗した場合
手順 2 で項目が Blocked に分類された場合、または移行したグループのビルドに失敗するか、契約が損なわれる場合は、無理に進めないでください。そのグループで作業を止め、次の手順に従ってください。
-
その項目の進め方について、次の 2 つの選択肢をユーザーに確認します。
- 共存: 移行済みの
@ExpoModuleと並べて 1.0 のdefinition()DSL に項目を残す(混在モード)ことで、他のグループの移行を続けます。 - 差し戻し: グループの変更を元に戻し、そのまま 1.0 に残してから先に進みます。
混在モードが安全だと確認できている場合は、最も多くの進捗を維持できるため、共存をデフォルトにします。部分的に適用した変更によってモジュールがビルドできない状態になり、段階的に修正できない場合は差し戻してください。
- 共存: 移行済みの
-
2.0 でまだ対応していない機能を記録するため、
expo/expoに追跡用の issue を作成します。黙って回避策を講じるだけにしないでください。gh issue create --repo expo/expoを使い、投稿前にユーザーの確認を得てください(リポジトリの慣例に従い、承認なしに外部公開されるコメントを投稿しないでください)。以下を記載してください。- 1.0 のメンバーとその JS 契約
- 不足している具体的なマクロまたはコアのフック(
references/compatibility.mdにある根拠の欠落を示してください) - チェックアウト済みの
expo-modules-coreのバージョン/ブランチ
引き継ぎ時にはその issue を参照し、残された DSL エントリと既知の制約を関連付けてください。
問題なく移行できるグループについては作業を続けてください。1 つのメンバーがブロックされても、他のグループまで止める必要はありません。
4. 動作を検証する
まず利用可能な中で最も範囲の狭いチェックを実行し、その後、実際の統合範囲を確認します。
- 対象の
expo-modules-coreに対して、Apple モジュールをビルドするか、型チェックします。 - ネイティブのユニットテストと JS/TS テストを実行します。
- リポジトリにサンプルアプリがある場合は、ビルドして起動します。
expo-module.config.jsonのapple.modulesに、すべてのモジュールクラスが引き続き記載されており、現在の Swift クラス名と一致していることを確認します。古いエントリが残っていてもビルドは成功し、実行時にのみ失敗するため、コンパイルだけでなく、サンプルアプリが実際にモジュールを解決できることを確認してください。- 最終的にエクスポートされる範囲を、手順 1 の一覧と比較します。
- 古い
Name、移行対象のFunction/AsyncFunction/StaticFunction/StaticAsyncFunction/Property/Constant/Eventsエントリ、古いsendEvent呼び出し、@Field、重複登録を検索します。マクロ展開の出力ではなく、自分が書いたソースを検索してください。
展開テストだけでは不十分です。生成されたマクロコードが正しく見えても、コアとの不整合によってリンクや実行に失敗することがあります。依存関係を変更した場合や、マクロプラグインのフラグが不足している場合は、必要に応じて JS 依存関係を再インストールし、リポジトリの CocoaPods インストール手順を実行してから、Xcode を再起動してください。そのうえで、プラグインとの通信障害を診断します。
引き継ぎ
マクロが生成したシンボル名やコア内部のシンボル名を、ユーザーに伝えてはいけません。references/compatibility.md には grep 用にそれらの名前が記載されていますが、実装の詳細であり、プラグインのリビジョンによって変わるため、報告には不要です。機能はマクロ(@JS static、@Event(sync:))と、観察可能な JS の動作によって説明してください。「インストール済みのコアは、自由形式の辞書引数のデコードにまだ対応していません」のように説明し、欠けているメソッドの名前は挙げないでください。例外は expo/expo のトラッキングイシューで、具体的に不足しているフック自体が論点となる場合です。
以下を報告してください。
- どのメンバーを 2.0 に移行したか
- どのメンバーを意図的に 1.0 DSL に残したか、その理由
- 互換性に影響する選択(特にイベント名、レコードの必須性、定数、キュー)
- 実行したコマンドと、未完了の検証
フィードバックの送信
このスキルにエラーや誤解を招く情報、古くなった情報があれば、Expo が改善できるよう報告してください。
npx --yes @expo/agent-cli@latest feedback --category skills --subject "expo-migrate-module" "<actionable feedback>"
具体的かつ実行可能な内容がある場合に限り、送信してください。関連するコンテキストはできるだけ多く含めてください。
エージェントが Expo のタスクを繰り返し失敗した場合、またはユーザーの介入が必要になった場合は、タスクの概要、期待した結果、問題の内容を簡潔に報告し、--category evals と、関連する Expo パッケージまたはコマンドを --subject として指定してください。