OpenAIExpoFeb 6, 2026, 12:30 AM

How to modernize mobile retail apps with Expo

A condensed section focused on the key takeaways first.

Original Post

Quick Digest

Summary

A condensed section focused on the key takeaways first.

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

How to modernize mobile retail apps with Expo

Key Points

  • Upgrade time cut ~80%
  • Performance score improved 36→90
  • Prebuild enabled predictable native upgrades

Summary

bitglow migrated DEPOT’s legacy React Native app to Expo (Prebuild + cloud services), dramatically reducing upgrade effort and improving runtime performance. The project combined a careful dependency audit and pruning, adoption of Expo Prebuild and config-plugins, targeted native SDK fixes, and JS‑level performance work validated by automated benchmarks. Results: upgrade cycles dropped to ~20% of prior effort (≈80% time saved) and Lighthouse-like performance scores rose from 36 to ~90.

Key Points

  • Start with a full dependency audit: classify packages as native vs pure‑JS and run tools like unimported to remove dead code.
  • Prune low‑usage libraries and remove compatibility layers (e.g. @react-navigation/compat) before migrating to reduce native surface area and integration risk.
  • Migrate to Expo Prebuild so ios/ and android/ are auto‑generated; expect migration cost comparable to a single RN upgrade but large long‑term savings for future upgrades.
  • Verify config‑plugin support for native packages using the Expo config‑plugins list; implement lightweight custom plugins when required.
  • Add generated native folders to .gitignore and simplify the app entrypoint while restoring native integrations iteratively to isolate regressions.
  • Run npx expo install expo --fix, add expo-dev-client, and adopt app.config.ts (with an APP_VARIANT approach) for build flavors and consistent native dependency alignment.
  • Resolve native SDK incompatibilities by upgrading offending SDKs, cleaning build caches, and rebuilding (common Android/Gradle errors are usually fixable this way).
  • Prefer upgrading critical libraries (e.g. navigation to v7) rather than patching deprecated internals to avoid long‑term maintenance costs.
  • Automate QA and performance benchmarking with Maestro and Flashlight to measure JS + native thread performance and iterate until target scores are met.
  • Use Expo Cloud Services (CI/build/submission) and OTA updates to shorten release cycles and recover developer velocity.

Outcomes & Practical Guidance

  • Expect the first migration to take as long as a single RN upgrade; subsequent upgrades should be ~20% of prior effort.
  • Benchmark before and after using user‑flow scripts (Maestro) and Lighthouse metrics (Flashlight) to validate improvements.
  • Treat dependency pruning and config‑plugin checks as the highest ROI tasks for a smooth Prebuild migration.

References

  • Tools mentioned: Expo Prebuild, expo-dev-client, config-plugins, npx expo install --fix, Maestro, Flashlight, unimported.

Full Translation

Translations

A translation section that keeps the flow of the original article.

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を用いてモバイル小売アプリをモダナイズした流れと得られた効果の概要です。技術的負債の削減と自動化により、アップグレードコストを劇的に下げ、パフォーマンスと開発効率を回復できました。