ClaudeExpoFeb 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.

claudeenmodel: claude-sonnet-4-20250514

Modernizing Mobile Retail Apps with Expo: DEPOT's 80% Upgrade Time Reduction

Key Points

  • React Native upgrade time reduced by 80% using Expo Prebuild
  • Performance scores improved from 36 to 90 through systematic optimization
  • Migration effort equivalent to single RN upgrade with long-term time savings

Summary

bitglow successfully modernized DEPOT's React Native retail app using Expo Prebuild, transforming an outdated codebase with significant technical debt into a future-proof solution. The project reduced React Native upgrade time by 80% and improved performance scores from 36 to 90.

Key Points

  • Legacy Codebase Challenges: Started with ejected Expo app on React Native 0.63, React Navigation v5 with deprecated compatibility layer, and outdated dependencies
  • Expo Prebuild Migration: Adopted Continuous Native Generation to auto-generate native code instead of manual ios/android project management
  • Dependency Optimization: Conducted thorough package.json audit, removed unused libraries, and replaced low-usage dependencies with custom implementations
  • Performance Improvements: Used Maestro and Flashlight for benchmarking, achieving dramatic performance score increases through systematic bottleneck resolution
  • Operational Benefits: Upgrade cycles reduced from weeks to days, freeing developers to focus on features rather than native maintenance
  • Migration Strategy: Staged approach with build configuration setup, custom config plugins for unsupported packages, and gradual restoration of app functionality

Full Translation

Translations

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

claudejamodel: claude-sonnet-4-20250514

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

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

ユーザー • 開発 • React Native • 2026年2月6日 • 21分で読める

Jonathan Bones ゲスト著者

bitglowがExpo Prebuildを使用してDEPOTのReact Nativeアプリをモダン化し、アップグレード時間を80%短縮し、パフォーマンススコアを36から90に向上させた方法を学びましょう。

これは、アップグレード、最適化、デバッグなどの詳細を愛するbitglowのシニアフロントエンド開発者Jonathan Bonesからのゲスト投稿です。彼はGitHubとBlueskyで見つけることができます。

はじめに

ExpoとReact Nativeは、開発者が高速で美しいアプリを構築することを可能にします。しかし、特にローエンドデバイスでの細部への注意を怠ると、その約束は急速に色褪せ、開発者のフラストレーションと顧客の不満につながる可能性があります。

聞き覚えがありませんか?これは、ドイツの著名なホームデコール小売業者であるDEPOTが直面していた課題でした。

ExpoとExpoのクラウドサービスの最新機能と、bitglowチームの深いReact Native専門知識を武器に、私たちはDEPOTの古いReact Nativeセットアップを完全に見直し、長年の技術的負債を取り除いて将来性のあるコードベースを構築するのを支援しました。

なぜこれがあなたにとって重要なのでしょうか?技術的負債が開発チームを遅らせると、最高のアイデアでさえ顧客に十分な速さで届かないからです。

私の言葉を鵜呑みにしないでください。開始前にユーザーが言っていたことは次のとおりです:

★☆☆☆☆ "アプリがクラッシュし続けなければ、とても素晴らしいアプリになるでしょう。すべての読み込みに永遠に時間がかかるか、まったく読み込まれないため、常に待たなければなりません。"

過去1年間、アプリを段階的に改良する中で、フィードバックが変化し始めました。一部のユーザーの懸念は特定の機能やバグに焦点を当てていますが、会話は明らかにパフォーマンスのフラストレーションから離れています:

★★★★★ "優秀なアプリです。ユーザーが近くの店舗をブックマークでき、アプリがその商品がその支店で利用可能かどうかを表示してくれれば、さらに良くなるでしょう。"

変革への道のり

この変革は一夜にして起こったものではありません。既存のコードベースの監査から始まり、痛点を理解し、ベースラインを確立しました。私たちがどこに立っているかを明確に把握することが、前進への道筋を定義する最初のステップでした。

コードベースの監査

プロジェクトに参加したとき、監査により作業対象の全体像が明らかになりました:

  • EjectedされたExpoアプリ - React Native 0.63
  • React Navigation v5(非推奨のv4互換レイヤーを多用)
  • 状態管理にRedux + API呼び出しなどの副作用にSagas
  • TypeScript v4.4

最も現代的なセットアップではありませんでしたが、構築するには十分堅実な基盤でした。TypeScriptの力を活用することで、新しい問題の発生率をほぼゼロに保ちながら、コードベースの大部分をリファクタリングすることに自信を持てました。

分析により、対処すべき4つの主要領域があることが分かりました:

  1. Prebuildの採用によるReact Nativeメンテナンスオーバーヘッドの削減
  2. アプリパフォーマンスの最適化
  3. ExpoのサービスによるビルドとSubmissionの自動化
  4. OTAデプロイメントによる迅速な更新の実現

数週間から数日へ:Expo Prebuildによるアップグレードサイクルの加速

主な課題は、古くてメンテナンスされていないバージョンのReact Nativeの維持と更新でした。アプリはReact Native 0.63で動作しており、最新の安定版から数メジャーリリース遅れていました。

Google PlayとApple App Storeがターゲット SDK更新をより頻繁に強制する中、ポリシーの期限に追いつくことは困難な挑戦となるでしょう。

さらに、一時的な解決策としてのみ意図されていた互換レイヤーを持つReact Navigation v5への依存は、コア依存関係のアップグレード中に微妙なバグが忍び込む可能性を高めました。

最初の数回のReact Nativeアップグレードは手動で実行され、React Native開発者コミュニティがState of React Native surveyの過去の版でこれを痛点として強調していたにもかかわらず、Upgrade Helperの登場以来、このプロセスは過去数年間でかなり管理しやすくなりました。

注意: Expoは最近、アプリのアップグレード用の新しいClaude Codeスキルを導入しました。まだ試していませんが、非常に役立つと聞いています。

しかし、これらの改善があっても、技術的変更の実行、ビルドのQA、厄介なバグの修正、リリースの準備には、チームで数週間かかりました。これは、フレームワークが必要とするネイティブコードの管理に本質的に費やされる貴重な開発時間でした。

また、ビジネス目標と期限に悪影響を与えることを避けるために、しばしば追加の調整とリスク管理が必要だったため、アップグレードに集中するために機能開発を停止するスプリントでのダウンタイムとしてしばしば見なされました。

手抜きをすることなくプロセスを高速化する方法はあるでしょうか?

より高速なバージョンアップグレードのためのPrebuildの採用

app.js conf 2022でのContinuous Native Generationに関するExpoの基調講演により、クライアントのプロジェクトでexpo prebuildを真剣に検討するようになりました。ios/とandroid/のネイティブプロジェクトを手動で管理するのではなく、ネイティブフレームワークコードを自動生成することで、より短く、より予測可能なアップグレードと「機能ダウンタイム」の削減が約束されました。

DEPOTへの推奨を検証するために、以前のプロジェクトからの経験を活用し、手動更新に費やした時間、ネイティブおよび非ネイティブ依存関係の数、コードベースの全体的なサイズなどの要因に基づいて推定しました。

これにより、2つの見積もりを作成できました:移行作業自体の見積もりと、将来のアップグレードで節約される時間の見積もりです。

結論として、移行には単一のReact Nativeアップグレードとほぼ同じ時間が必要でした。その見返りとして、将来のアップグレードは以前に必要だった時間のわずか20%で完了でき、アップグレードサイクルを数週間からわずか数日に短縮できました。

時間の経過とともに、React Native CLIからExpoへの複数の移行を完了し、そのプロセスを成功させるために必要な詳細に非常に精通するようになりました。Expoチームとコミュニティからの継続的な改善と組み合わせることで、移行はますます予測可能で効率的になりました。

実際には、多くのプロジェクトで、初期の努力は本当に単一のReact Nativeアップグレードに匹敵し、投資収益率はその後のすべてのアップグレードから始まります。

DEPOTの場合のように、移行に複数のReact Nativeバージョンアップグレードが並行して含まれる場合、これはさらに魅力的になります。従来単一のReact Nativeバージョンをアップグレードするのにかかる時間とほぼ同じ時間を費やすことで、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コンポーネントになりました。

このような依存関係フットプリントの削減により、ネイティブ統合リスクが大幅に削減され、DEPOTアプリがPrebuildを採用する準備において最も影響力のあるステップでした。

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

削減されたpackage.jsonを手に、Expo config-pluginsリポジトリをガイドとして使用して、残りのネイティブパッケージでのconfig-pluginサポートを確認しました。ほとんどのネイティブ依存関係には、すでにファーストパーティまたはコミュニティプラグインが利用可能でした。これは素晴らしい兆候でした。

そうでないものについては、カスタムconfig pluginを実装する必要がありました。しかし、これは驚くほど簡単であることが判明しました。Expoのドキュメントは非常に明確で、既存のconfig pluginを参考にして、数時間以内に残りのネイティブSDKのサポートを実現できました。

大きな障害となる可能性があったものが簡単に解決され、進行する自信を与えてくれました。

移行は意図的な段階で進みました。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_VARIANT環境変数をキーとするビルドフレーバーを有効にするため、app.jsonをapp.config.tsに名前変更しました:

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をアップグレードし、ビルドアーティファクトとキャッシュをクリーンアップして、リビルドすることでした。

アプリ機能の復元

ネイティブ統合のセットアップが完了すると、次のステップは初期アプリコードを追加し直すことでした。そこで、ブロッキング問題を発見しました:プロファイルタブへのナビゲーションで目に見えてぎこちない遷移が発生し、その後クラッシュしました。

スタックトレースと再現された動作は、アプリケーションロジックではなくナビゲーション層を指していたため、選択に直面しました:メンテナンスされていないv5で問題を修正する時間を投資するか、負債に取り組んで最新のサポートされているバージョン(v7)にアップグレードするかです。

非推奨の内部を修正する長期的なメンテナンスコストを考慮して、アップグレードパスを選択しました。これはそれ自体でブログ投稿に値します。

アプリアップグレードのROI

未使用で脆弱な依存関係を削除し、ナビゲーションとSDKバージョンをアップグレードし、Prebuildを採用してネイティブプロジェクトファイルを自動生成することで、高リスクで時間のかかるワークフローを反復可能で自動化されたプロセスに変換しました。

利点はすでに見えています:より高速なTime-To-Upgrade(TTU)と明らかに高い開発者の生産性です。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