web-to-native について
既存の React Web アプリを Expo のネイティブアプリへ移行する段階的な手順を示すスキルです。まず DOM コンポーネントで Web UI を動かし、その後、公開可能な状態を保ちながら画面を優先順にネイティブ化します。
主な機能
- 01画面の評価と分類
- 02Expo ルートの足場作り
- 03まず DOM コンポーネントで Web UI を実行
- 04優先度に沿った画面のネイティブ化
- 05データ、認証、ストレージの接続
- 06実行時の内容と動作の検証
活用シーン
- 01既存の React Web アプリを段階的にネイティブへ移行
- 02画面を再設計する前に動作するモバイル版を公開
- 03ネイティブ化の優先順位付けと画面動作の検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ expo/ skills --skill web-to-nativeインストール後、Claude Code で/web-to-nativeを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/false-friends.mdnative-patterns.mdrun-as-goal.mdverify-on-device.md詳細
Web からネイティブへ
Web の React アプリがネイティブに 変換 されることはありません。トランスパイラーは存在しないからです。アプリは画面ごとに 移行 します。木の周りにイチジクの木が伸び、ゆっくりと置き換えていくように、まずネイティブのシェルを立ち上げ、初日から Web UI 全体をその中で動かし、その後、優先順位に沿って各画面をネイティブに置き換えていきます。このスキルは作業の順序を決める軸となります。各ステップでは既存の Expo スキルに引き継ぐため、同じ説明を繰り返すことはありません。Expo の From Web to Native with React を実践に移すものです。理由については、そちらをご覧ください。
flowchart TD
A1[1 · Assess: write the worklist] --> A2[2 · Scaffold Expo shell]
A2 --> A3[3 · DOM-component shell<br/>· use-dom · SHIP DAY ONE]
A3 --> A4[4 · Strangle screens to native<br/>highest-value first · building-native-ui]
A4 -->|more screens| A4
A4 --> A5[5 · Wire data / auth / storage<br/>· native-data-fetching]
A5 --> A6[6 · Ship · expo-deployment]
原則
- 書き換えずに移行します。 一度にすべてを置き換えることは避けます。どのステップでも、アプリをリリース可能な状態に保ちます。
- 初日からリリースします。 何もネイティブ化する前に、DOM コンポーネントのシェル(ステップ 3)で Web UI を動かします。これがマイルストーンであり、その後はすべて磨き込みです。
- 価値に応じて段階的に置き換えます。 利用頻度の高い画面をネイティブ化し、残りは WebView に残します。DOM の画面ごとに約 2 MB の Web ランタイムが必要です。すべてを DOM としてリリースしない理由として十分です。
- ネイティブ化とは、見た目の変更ではなく再設計です。 段階的に置き換えた画面は、Web ページの見た目だけを変えたものではなく、Apple や Google がリリースしたかのように見えるべきです。まずは
@expo/uiを使ってください。実際の SwiftUI/Compose を描画するため、OS に そのまま 溶け込みます。スタイル付きの RN プリミティブは、カスタムレイアウトが必要な場合にのみ代替として使います。さらに、プラットフォームのナビゲーション(expo-router:NativeTabs、大きなタイトル)、リキッドグラス、@expo/uiによるネイティブコンポーネント、モバイル向け UX(シート、スワイプ、触覚フィードバック)も活用します。Web からネイティブへのパターンマップは./references/native-patterns.mdにあります。それでも Web サイトのように感じるなら、再設計ではなく移植をしたということです。 - コンパイルではなく、実行して検証します。 ビルドが成功しても何の証明にもなりません(空の WebView でも問題なくコンパイルできます)。各画面を実行します。ただし、Web の元画面と比較する際に評価するのは コンテンツと動作 であり、ピクセル単位の一致ではありません(ネイティブ化した画面は、同一ではなく、よりネイティブに見えるべきです)。
- 一から作り直さず、連携して進めます。 各ステップでは既存のスキルに引き継ぎます。ここで重要なのは 順序 と 注意点 です。イディオムごとの対応関係は
./references/false-friends.mdにあります。
ループとして実行する(推奨)
移行は、完了するまで繰り返す長いループです。そのため、最初にすることは、画面を手作業で一つずつ進めるのではなく、目標の内容を書いて実行することです。このアプリ向けに ./references/run-as-goal.md の目標を記入して提示してください。各反復でこのスキルを 再読み込みする ため、/goal の各ターンで手順書と作業リストを読み込み直し、次の画面へと進めます(評価ステップの初期化も自動で行います)。その目標を使って /goal を実行してください。実行環境がループに対応していない場合は、目標を migration-goal.md に書き込み、ユーザーに実行してもらいます。以下のステップは各反復で行う作業です。ループを使わない場合に限り、手作業で実行してください。
移行
移行するリポジトリがありません — Web 開発者として、最初からネイティブアプリを作るだけですか? これらのステップは不要です。
building-native-uiを使い、Web からネイティブへのイディオムマップとして./references/false-friends.mdを開いておいてください。以下の内容はすべて、既存の Web アプリがあることを前提としています。
1. 評価 → 作業リストを作成する
リポジトリを読み、以降の移行作業でチェックを付けていく永続的な作業リストとして migration-progress.md を作成します。次の2つの観点で分類します。
- 画面とバックエンド。 ページルート(
page.tsx)は移行対象の画面です。サーバールート(route.ts)、ORM、認証ハンドラーはサーバー側に残します。バックエンドの方針を一度決めます。デプロイしたままにする(ネイティブアプリはHTTPクライアントになります)か、EAS Hosting(expo-api-routes)に移すかを選びます。 - 各画面の移行方針。 画面ごとに、そのまま移植(プレゼンテーション中心 → DOM WebViewで提供)、今すぐネイティブ化(利用頻度が高い、またはジェスチャー、リスト、キーボードなどネイティブらしい操作が必要)、後でネイティブ化、ハイブリッド(Webサブツリーを囲むネイティブシェル。例:Markdownレンダラーを含むチャットリスト)に分類します。
読み進める際に、RSCかクライアント側か、Tailwind/shadcnを使っているか、データをどこで取得しているかなど、フレームワークに関する情報も記録します。これらが各画面の移植方法を決めるためです(対応関係は false-friends に記載されています。特に非同期 Server Components は、移行前にクライアント側での取得とプレゼンテーションコンポーネントに分割する必要があります)。サードパーティのサービスやSDKにも印を付けます。ブラウザー用SDKはそのまま引き継げません(false-friends → サービスとSDK)。特に決済は置き換えではなく分岐です(アプリ内デジタル商品にはStripeではなく、RevenueCatを介したストアのIAPを使う必要があり、手数料は約30%です)。これはApp Storeの審査時ではなく、今決めるべきビジネスモデル上の判断です。すべてのルートが分類され、すべての画面に移行方針が決まるまでは、この作業リストは信頼できる状態とはいえません。
2. シェルを作成する
create-expo-app を実行し、Expo RouterでWebのルートを再現します。Nextのツリーはほぼ1対1で対応します([id]/page.tsx は [id].tsx に対応します。ルートは src/app/ に配置される場合もあります)。ルートごとに空の画面を用意します。
3. DOMコンポーネントでシェル化する — 初日のマイルストーン
use-dom スキルに従って、すべての画面をDOMコンポーネント('use dom')として移し、ネイティブルートからレンダリングします。これにより、ネイティブ化する前にアプリ全体をスマートフォン上で動かせます。画面ごとの編集が必要になります。Server Componentsの分割、フレームワークのインポート(next/link など)の置き換え、スタイルの引き継ぎなどです。これらはすべて false-friends で説明されています。その後、以下の手順で実行して確認します。この状態のままTestFlightに配信できます。
4. 価値に応じて画面をネイティブ化する
migration-progress.md を上から順に進めます。画面ごとに、Webレイアウトを移植するのではなく、ネイティブ向けに再設計します。まず @expo/ui を使います(本物のSwiftUI/Composeコンポーネントであるボタン、リスト、シート、ピッカー、スライダーなどが使えます。./references/native-patterns.md では、Webのパターンをどのネイティブコンポーネントに置き換えるかを説明しています)。次にプラットフォームのナビゲーション(expo-router の NativeTabs、大きなタイトルなど)とモバイル向けUX(スワイプ、触覚フィードバック、慣性スクロール/逆方向スクロール)を使い、カスタムレイアウトにはReact Nativeのプリミティブを使います。各イディオムについては ./references/false-friends.md を参照してください。@expo/ui とDOMコンポーネントは、どちらも Expo Go(SDK 56以降)で動作します。開発ビルド(expo-dev-client スキル)が必要なのは、カスタムネイティブモジュールを使う場合だけです。実行中のWeb版と照らし合わせて、コンテンツと動作を確認してから完了にします(見た目はよりネイティブになるはずです)。一度に進めるのは1画面ずつで、アプリは作業中も配信可能な状態を保ちます。これは永続的な作業リストに沿って繰り返す作業なので、無人で実行できます。ゴールループに ./references/run-as-goal.md を渡してください。
5. データ、認証、ストレージを接続する
Webのデータレイヤーは移行後にはそのまま使えません。相対パスでのfetch、Cookieセッション、localStorage、環境変数はすべて変更が必要です(置き換え方法は false-friends に記載されています)。リクエストとキャッシュには native-data-fetching を使います。バックエンドをEAS Hostingに移した場合は、expo-api-routes を追加します。
6. 配信する
ストア向けビルド(App Store/Play/TestFlight)には expo-deployment を使い、その後のOTA配信にはEAS Updateを使います。
コンパイルではなく、実行して検証する
expo export が成功しても、それは画面が バンドルされる ことを証明するだけで、レンダリングされる ことを証明するわけではありません。画面はビルドできても、何も表示されなかったり、誤ってレンダリングされたりすることがあります。そのため、シェルの構築後と、ネイティブ化した画面ごとに、同じルートで 実行中の 2つのアプリを比較してください。
- Web の元アプリ —
agent-browser(vercel-labs CLI)でキャプチャします。ルートをopenし、アクセシビリティツリーをsnapshot --jsonで取得して、screenshotを実行します。 - ネイティブアプリ —
argentでシミュレーターを操作します。構造の確認にはdescribe/debugger-component-treeを使い、各パスでチェックを再生するにはflowを使います。
合格基準は、ピクセルではなく コンテンツと動作の同等性 です。ネイティブ化した画面は、Web よりも ネイティブらしく 見える必要があり、同一にしてはいけません(DOM シェルの段階は例外です。この段階では Web UI そのものなので、一致する必要があります)。操作感もネイティブらしさの一部であり、スクリーンショットでは捉えられません。画面にトランジションやジェスチャーがある場合は、静止画だけでなく短い動画を撮影してください(native-patterns.md → Feel を参照)。このループでは 使用するツールを指定しています。agent-browser または argent がインストールされていない場合は、ユーザーに確認し、作業を続ける前にインストールしてください。手動のスクリーンショットで代用してはいけません。手順とセットアップの詳細は ./references/verify-on-device.md を参照してください。
リファレンス
./references/false-friends.md— Web のイディオムからネイティブの代替表現への対応と、それぞれの注意点です。ステップ 3〜5 の確認、および Web 開発者がイディオムを忘れる際に参照します。./references/native-patterns.md— Web の UX パターン からネイティブ向けの再設計への対応です(@expo/uiを優先)。画面を単に見た目だけ変えるのではなく、OS にネイティブに感じられるものにするための、ステップ 4 の再設計プレイブックです。./references/verify-on-device.md— 2つのエージェントを使った同等性確認の手順です。Web アプリ(ブラウザーエージェント)とネイティブアプリ(argent)を操作して、同じルートを開いて比較します。./references/run-as-goal.md— ステップ 4 を無人で実行するための、すぐに使える移行専用の目標です(反復のたびにこのスキルを読み直します)。- Expo — React で Web からネイティブへ — このスキルの基盤となる公式ガイドです。