OpenAIExpo2026/02/06 0:30

How to modernize mobile retail apps with Expo

要点だけを先に読めるように短く再構成したセクションです。

元記事

Quick Digest

要約

要点だけを先に読めるように短く再構成したセクションです。

openaijamodel: gpt-5-mini-2025-08-07

Expoで小売モバイルアプリを近代化 — DEPOT事例

Key Points

  • アップグレード工数80%削減
  • パフォーマンス36→90改善
  • expo prebuild導入

Summary

DEPOTの古いReact NativeアプリをbitglowがExpoへ移行し、アップグレード工数を80%削減、Lighthouseスコアを36から90へ向上させた事例の要点を実務的にまとめます。狙いはネイティブ管理の自動化(Prebuild)、依存関係の整理、ビルド/配信の自動化、JS側のパフォーマンス改善です。

Key Points

  • 事前監査と準備

    • package.jsonの各依存を「ネイティブ」「純JS」に分類し、未使用ライブラリを削除。低使用頻度のライブラリは小さな自作実装に置換してネイティブリスクを低減。
    • @react-navigation/compat を除去し、useNavigationなどで最新APIへリファクタ。
  • Expo Prebuild採用の判断と準備

    • 移行工数は単一のRNアップグレードと同等と評価。以降のアップグレードは約20%の工数で完了(週→数日)。
    • config-pluginを確認し、無ければカスタムプラグインを実装してネイティブSDK連携を回復。
    • ios/ と android/ を.gitignoreに追加し、最小エントリでビルド確認後に順次機能を戻す。
    • npx expo install expo --fix と expo-dev-client を導入。app.jsonをapp.config.ts化してAPP_VARIANTでフレーバーを管理。
  • トラブル対応の実務例

    • AndroidでのGradleエラーは古いEmarsys SDKが原因:SDKを上げ、ビルドキャッシュをクリアして解決。ネイティブ依存はまずバージョン互換を疑う。
    • ナビゲーション周りのジャンクやクラッシュはv5の修正ではなくv7へアップグレードして解決(長期的にローコスト)。
  • パフォーマンス改善と検証

    • Maestroで実ユーザーフローを自動化し、FlashlightでJS/ネイティブ両面のLighthouseスコアを取得。
    • ボトルネックはJS側のレンダリングや不必要な依存によるオーバーヘッドが中心。不要処理の削減とスクロール最適化で改善。
  • 運用とROI

    • Expo Cloud Servicesでビルド・提出を自動化し、OTA配信で素早く修正を反映。ターゲットAPI要件などの運用リスクを低減。
    • 結果:アップグレード工数約80%削減、Lighthouseスコア36→90、開発速度と安定性の向上。

Practical checklist for engineers

  • 依存関係をネイティブ/純JSに分類し未使用を削除
  • 小さなライブラリは自作実装で置換してネイティブ結合を減らす
  • Expo config-pluginsの有無を確認、必要ならカスタム作成
  • ios/ android/ を管理外にしてPrebuildへ移行
  • app.config.tsでビルドフレーバー管理、expo-dev-client導入
  • 古いネイティブSDKは早めに更新してビルドエラーを回避
  • Maestro + Flashlightでベンチマークを自動化し改善効果を測定
  • Expo Cloud ServicesとOTAでビルド/配信を自動化

短く言えば、「依存削減→Prebuild移行→ナビ/ネイティブSDK更新→JS最適化→自動化」が再現可能な近代化パスです。

Full Translation

翻訳

原文の流れを保ったまま読める翻訳セクションです。

openaijamodel: gpt-5-mini-2025-08-07

Expoでモバイル小売アプリをモダナイズする方法

Expoでモバイル小売アプリをモダナイズする方法

Users • Development • React Native • February 6, 2026 • 21 minutes read

Jonathan Bones Guest Author

bitglowがExpo Prebuildを使ってDEPOTのReact Nativeアプリをどのようにモダナイズし、アップグレード時間を80%短縮し、パフォーマンススコアを36から90に向上させたかを解説します。この記事はbitglowのSenior Frontend Dev、Jonathan Bonesによるゲスト投稿です。彼はアップグレード、最適化、デバッグなどの詳細を大切にしています。You can find him on GitHub & Bluesky.

ExpoとReact Nativeは開発者に高速で美しいアプリを作る力を与えます。しかし、特に低スペック端末では細部に注意を払わないとその約束は簡単に薄れ、開発者のフラストレーションと顧客の不満につながります。心当たりはありますか?それがまさにDEPOT(ドイツの大手ホームデコレーション小売業者)が直面していた課題でした。

Expoの最新機能とExpoのCloud Services、そしてbitglowの深いReact Nativeの専門知識を組み合わせ、古くなったReact Nativeのセットアップを完全に刷新し、何年分もの技術的負債を取り除いて将来に耐えうるコードベースを構築しました。

なぜこれはあなたにとって重要なのか?技術的負債が開発チームを遅らせると、どんなに優れたアイデアでも顧客に届くのが遅くなります。証拠として、着手前のユーザーの声をどうぞ:

★☆☆☆☆ “The app could be so great if it didn’t keep crashing. You constantly have to wait because everything takes forever to load or doesn’t load at all.”

過去1年でアプリを段階的に改修するにつれて、フィードバックは変わり始めました。今では一部の懸念は特定の機能やバグに移っていますが、明らかにパフォーマンスに対する不満は減っています:

★★★★★ “Excellent app. It would be even better if users could bookmark a nearby store and the app would then show whether the item is available at that branch or not.”

この変化は一夜にして起きたわけではありません。既存コードベースの監査から始まり、痛点を理解してベースラインを確立することが最初の一歩でした。

コードベースの監査

参加時の監査で判明したのは次の構成でした:

  • Ejected Expo app - React Native 0.63
  • React Navigation v5(deprecatedなv4互換レイヤーを多用)
  • Reduxによる状態管理 + SagasでAPI呼び出しなどの副作用を処理
  • TypeScript v4.4

最新のセットアップとは言えませんでしたが、TypeScriptを活用することで大規模なリファクタリングを行っても新たな問題発生をほぼ抑えられる見通しがありました。

監査の結果、対応すべき主要な4つの領域が見えました:

  • Prebuildを採用してReact Nativeのメンテナンス負荷を減らす
  • アプリのパフォーマンス最適化
  • ExpoのServicesでビルドとサブミッションを自動化する
  • OTAデプロイで迅速なアップデートを行えるようにする

数週間から数日に:Expo Prebuildでアップグレードを加速

最大の課題は古い・未メンテナンスのReact Nativeバージョンの維持と更新でした。アプリはReact Native 0.63で稼働しており、最新安定版から数回分のメジャーリリースに遅れていました。Google PlayやApple App StoreのターゲットSDK更新ポリシーが頻繁になっているため、期限対応は負担が大きくなる一方です。

さらに、v4互換レイヤーに依存したReact Navigation v5の使用は、アップグレード時に微妙なバグを招く可能性を高めていました。過去にはReact Nativeの数回のアップグレードを手作業で行い、State of React Nativeの報告でもそれが痛点であると指摘されていました。Upgrade Helperの登場で作業は管理しやすくなりましたが、それでも数週間はかかっていました。

注: Expoは最近、アップグレードを支援する新しいClaude Code skillを導入しました。私たちはまだ試していませんが、非常に役立つと聞いています。

手作業での変更、ビルドのQA、バグ修正、リリース準備には数週間を要しました。これはフレームワークで必要なネイティブコードの管理に費やされている貴重な開発時間であり、スプリントでは機能開発を止めてアップグレードに注力するダウンタイムと見なされることが多かったです。

これを速く、安全に行う方法はないか?という問いに対して、expo prebuildの採用が有効でした。

Prebuildの採用

app.js conf 2022のContinuous Native Generationに関するキーノートは、プロジェクトでexpo prebuildを真剣に検討する決め手になりました。ios/とandroid/のネイティブプロジェクトを手動で管理する代わりに自動生成することで、アップグレードは短く予測可能になり、“機能のダウンタイム”が減ります。

DEPOT向けの推奨を検証するため、過去のプロジェクト経験や手作業にかけていた時間、ネイティブ/非ネイティブ依存関係の数、コードベース全体の規模などを元に見積もりを作成しました。その結果、マイグレーション自体は単一のReact Nativeアップグレードとほぼ同等の工数である一方、将来のアップグレードは従来の20%程度の時間で完了でき、数週間かかっていたアップグレードを数日に短縮できる、という結論に達しました。

私たちは複数のプロジェクトでReact Native CLIからExpoへのマイグレーションを完了しており、その詳細に精通しています。Expoチームとコミュニティの継続的な改善もあり、マイグレーションはますます予測可能で効率的になっています。

実務では、初期の工数は単一のRNアップグレードに相当することが多く、投資回収は以後のアップグレードで即座に始まります。DEPOTでは複数バージョンのRNアップグレードを並行して行ったため、その効果はさらに大きく、単一バージョンのアップグレードと同程度の工数で3バージョン分の移行が完了しました。

マイグレーションの準備

まずは依存関係の監査から始めました。package.jsonの各エントリをネイティブ依存か純粋JSかに分類し、unimportedを走らせて未使用ライブラリを特定しました。これにより最初のパスで@react-native-voice/voice、isomorphic-fetch、traverseを削除しました。

長年の技術的負債にも対処し、@react-navigation/compatレイヤーを最終的に削除して、StackActionsやNavigationActionsをuseNavigationフックにリファクタリングすることで、React Navigationの新バージョンへのアップグレードの道を開きました。

参照回数が少ない依存(≤3参照)はスキャンしていくつかは小さなカスタム実装で置き換えました。例: react-native-multi-tap-componentはバニラのRNコンポーネントに置き換えました。依存を刈り込むことでネイティブ統合リスクを大きく減らせ、Prebuild導入準備で最も効果的なステップとなりました。

ビルド設定のセットアップ

整理したpackage.jsonを用いて、残存するネイティブパッケージについてExpo config-pluginsリポジトリを参考にconfig-pluginサポートをチェックしました。多くのネイティブ依存は既にファーストパーティかコミュニティのプラグインがありました。プラグインが無いものはカスタムconfig pluginを実装する必要がありましたが、Expoのドキュメントと既存のプラグインを参照すれば数時間で対応できました。

マイグレーションは段階的に進めました。android/とios/フォルダを.gitignoreに追加し、アプリのエントリポイントを最小のレンダーに簡素化してまずネイティブ統合を復元し、続いてTypeScriptやビジネスロジックの問題に取り組めるようにしました:

export default function App ( ) {
  return (
    <View style={styles.container}>
      <Text>If you can see this the app builds and starts</Text>
    </View>
  );
}

次に最新のExpo SDKをインストールし、expo-dev-clientを追加して、npx expo install expo --fix を実行してネイティブライブラリを更新し、インストールしたSDKバージョンに設定を合わせました。

app.jsonはapp.config.tsへ名前を変更し、APP_VARIANT環境変数に基づいてビルドフレーバーを切り替えるようにしました:

import { ExpoConfig } from "expo/config";
const name = {
  development: "DEPOT (dev)",
  preview: "DEPOT (preview)",
  production: "DEPOT",
}[process.env.APP_VARIANT ?? "development"];

export default (): ExpoConfig => ({
  name: name!,
  version: "6.1.0",
  // ...other properties
});

iOSの初回ビルドは成功しました。🎉

AndroidビルドでいくつかのGradleエラーが発生しました。スタックトレースを掘ると、生成されたネイティブプロジェクトと非互換な古いEmarsys SDKが原因でした。対応は単純で、SDKをアップグレードしてビルドアーティファクトとキャッシュをクリーンにし、再ビルドするだけでした。

アプリ機能の復元

ネイティブ統合を整えた後、アプリの初期コードを戻したところ、ブロッキングな問題に遭遇しました: プロファイルタブへ遷移すると目に見えてトランジションがガクつき、その後クラッシュするというものです。スタックトレースと再現された挙動はアプリケーションロジックではなくナビゲーション層を示していました。

選択肢は2つ: メンテされていないv5にパッチを当てるか、負債に取り組んでサポートされている最新バージョン(v7)へアップグレードするか。長期的なメンテコストを鑑み、私たちはアップグレードの道を選びました(この作業自体も別の記事に値します)。

アップグレードのROI

未使用・もろい依存の削減、ナビゲーションとSDKのアップグレード、Prebuildによるネイティブプロジェクト自動生成の採用により、リスクが高く時間を取られていたワークフローを繰り返し可能で自動化されたプロセスに変換しました。メリットは明白です: TTU(Time‑To‑Upgrade)が速くなり、開発者のベロシティが著しく向上しました。ExpoとReact Nativeのアップグレードは以前の20%の工数で済むようになり、チームはネイティブ問題の対処ではなくプロダクトに集中できるようになりました。

運用面でも、Target API level要件のメールが以前ほどの危機感を呼ばなくなりました。

パフォーマンスボトルネックへの取り組み

ネイティブ依存の整理が終わったら、JS側のパフォーマンス問題に取り組みました。取り組む前に進捗を測るためのベンチマークが必要です。Maestroで典型的なユーザーフローを作成し、Flashlightを使ってJSとネイティブスレッド使用量をカバーするLighthouseベースのパフォーマンススコアを取得しました。

以下は、カテゴリ詳細ページに遷移し、ページングする典型的なMaestroスクリプトの抜粋です:

- launchApp
- assertVisible : "Entdecke dein DEPOT"
- tapOn : "Deko & Wohnen"
- tapOn : "Kerzen & Lichtobjekte"
- tapOn : "Kerzen"
- tapOn : "Stumpenkerzen"
- waitForAnimationToEnd # Title of first product in "Stumpenkerzen" PLP
- assertVisible : ${ PRODUCT_TITLE }
# Imitates a fast scroll to bottom of listing page
- swipe : start : 50%, 75% end : 50%, 25% duration : 40
- assertVisible

(スクリプトはリストページを素早くスクロールし、最初の製品タイトルの可視性を確認するよう設計されています。)


以上が、DEPOTの事例を通じてExpo Prebuildを用いてモバイル小売アプリをモダナイズした流れと得られた効果の概要です。技術的負債の削減と自動化により、アップグレードコストを劇的に下げ、パフォーマンスと開発効率を回復できました。