エンジニア夫婦の技術日記

【ReactNative】ExpoSDKv42→46にアップグレード


2022年9月20日
Posted by 

この記事をおすすめしたい方

この記事は以下のような方におすすめです!

  • ExpoSDKのバージョンアップでReactNativeアプリが動かなくなった

記事の作成経緯

以前投稿した記事に記載したかと思いますが、
私たちはReact Nativeを使用してモバイルアプリを開発しています。

そのアプリはExpoを使用しているのですが、ExpoSDKのバージョンが上がったことに伴い、
実機での動作確認が出来なくなりました。

バージョンアップに四苦八苦し、結果、成功したのでその流れを綴ろうと思い、
記事を書こうと思いました。


状況確認

現在のExpoSDKのバージョンは、pacakage.jsonを見たところ42です。

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject",
    "lint": "eslint --ext .tsx --ext .ts src/"
  },
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "^1.2.36",
    "@fortawesome/free-solid-svg-icons": "^5.15.4",
    "@fortawesome/react-fontawesome": "^0.1.15",
    "@react-native-community/datetimepicker": "3.5.2",
    "@react-native-community/masked-view": "0.1.10",
    "@react-navigation/drawer": "^6.3.1",
    "@react-navigation/native": "^6.0.5",
    "@react-navigation/stack": "^6.0.10",
    "@types/moment": "^2.13.0",
    "@types/react-native-calendars": "^1.20.10",
    "@types/react-native-material-ripple": "^0.9.1",
    "@types/react-native-table-component": "^1.2.1",
    "@types/react-native-vector-icons": "^6.4.5",
    "expo": "^42.0.0",
    "expo-cli": "^4.7.3",
    "expo-status-bar": "~1.0.4",
    "firebase": "8.2.3",
    "moment": "^2.27.0",
    "react": "16.13.1",
    "react-dom": "16.13.1",
    "react-native": "https://github.com/expo/react-native/archive/sdk-42.0.0.tar.gz",
    "react-native-calendars": "^1.313.0",
    "react-native-dropdown-picker": "^5.4.2",
    "react-native-elements": "^3.4.2",
    "react-native-gesture-handler": "~1.10.2",
    "react-native-maps": "0.28.0",
    "react-native-material-ripple": "^0.9.1",
    "react-native-paper": "^4.0.1",
    "react-native-reanimated": "~2.2.0",
    "react-native-safe-area-context": "3.2.0",
    "react-native-screens": "~3.4.0",
    "react-native-table-component": "^1.2.1",
    "react-native-tiny-toast": "^1.0.7",
    "react-native-vector-icons": "^7.0.0",
    "react-native-web": "~0.13.12",
    "react-navigation": "^4.4.0",
    "react-navigation-stack": "^2.8.2"
  },
  "devDependencies": {
    "@babel/core": "~7.9.0",
    "@types/react": "~16.9.35",
    "@types/react-native": "~0.63.2",
    "@typescript-eslint/eslint-plugin": "^3.8.0",
    "@typescript-eslint/parser": "^3.8.0",
    "eslint": "^7.6.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-prettier": "^3.1.4",
    "prettier": "^2.0.5",
    "typescript": "~4.0.0"
  },
  "private": true
}

npmでパッケージの最新バージョンを見るには以下のコマンドで見れます。

> npm info expo version
46.0.10

みたところExpoの最新バージョンは46のようです。


ExpoSDKのバージョンアップを試みる

以下のサイト様を参考に試してみます。


35D BLOG
Expo SDK のアップデートのメモ(SDK 37 → 42 / RN 0.61.5 → 0.63.4)

  1. yarn global add expo-cli
  2. expo upgrade
  3. yarn start

エラーが出ました

Android Bundling failed 3519ms
node_modules\react-native-reanimated\src\index.ts: D:\develop\shopping-todo\node_modules\react-native-reanimated\src\index.ts: Unexpected export specifier type
  5 | export * from './reanimated1';
  6 | export * from './reanimated2';
> 7 | export * as default from './Animated';
    |        ^^^^^^^^^^^^
  8 |
SyntaxError: D:\develop\shopping-todo\node_modules\react-native-reanimated\src\index.ts: Unexpected export specifier type
  5 | export * from './reanimated1';
  6 | export * from './reanimated2';
> 7 | export * as default from './Animated';
    |        ^^^^^^^^^^^^
  8 |
    at File.buildCodeFrameError (D:\develop\shopping-todo\node_modules\@babel\core\lib\transformation\file\file.js:249:12)
    at NodePath.buildCodeFrameError (D:\develop\shopping-todo\node_modules\@babel\core\node_modules\@babel\traverse\lib\path\index.js:145:21)
    at D:\develop\shopping-todo\node_modules\@babel\plugin-transform-modules-commonjs\node_modules\@babel\helper-module-transforms\lib\normalize-and-load-metadata.js:150:22
    at Array.forEach (<anonymous>)
    at D:\develop\shopping-todo\node_modules\@babel\plugin-transform-modules-commonjs\node_modules\@babel\helper-module-transforms\lib\normalize-and-load-metadata.js:148:31
    at Array.forEach (<anonymous>)
    at getModuleMetadata (D:\develop\shopping-todo\node_modules\@babel\plugin-transform-modules-commonjs\node_modules\@babel\helper-module-transforms\lib\normalize-and-load-metadata.js:96:27)
    at normalizeModuleAndLoadMetadata (D:\develop\shopping-todo\node_modules\@babel\plugin-transform-modules-commonjs\node_modules\@babel\helper-module-transforms\lib\normalize-and-load-metadata.js:39:7)
    at rewriteModuleStatementsAndPrepareHeader (D:\develop\shopping-todo\node_modules\@babel\plugin-transform-modules-commonjs\node_modules\@babel\helper-module-transforms\lib\index.js:77:54)

次は以下のGtiHubに記載のissuecommentを参考に、babel.config.jsに設定を追加します。

https://github.com/software-mansion/react-native-reanimated/issues/3359#issuecomment-1217305377

キャッシュを削除してアプリをビルドしてみます。

npm start –clear-cache

Invariant Violation: ViewPropTypes has been removed from React Native. Migrate to ViewPropTypes exported from 'deprecated-react-native-prop-types'.
at node_modules\expo\build\environment\react-native-logs.fx.js:null in error
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:null in reportException
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:null in handleException
at node_modules\react-native\Libraries\Core\setUpErrorHandling.js:null in handleError
at node_modules\expo\build\errors\ExpoErrorManager.js:null in errorHandler
at node_modules\expo\build\errors\ExpoErrorManager.js:null in <anonymous>
at node_modules\@react-native\polyfills\error-guard.js:null in ErrorUtils.reportFatalError
at node_modules\metro-runtime\src\polyfills\require.js:null in guardedLoadModule
at http://192.168.0.12:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&strict=false&minify=false:null in global code

Invariant Violation: "main" has not been registered. This can happen if:
* Metro (the local dev server) is run from the wrong folder. Check if Metro is running, stop it and restart it in the current project. 
* A module failed to load due to an error and `AppRegistry.registerComponent` wasn't called.
at node_modules\expo\build\environment\react-native-logs.fx.js:null in error
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:null in reportException
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:null in handleException
at node_modules\react-native\Libraries\Core\setUpErrorHandling.js:null in handleError
at node_modules\expo\build\errors\ExpoErrorManager.js:null in errorHandler
at node_modules\expo\build\errors\ExpoErrorManager.js:null in <anonymous>
at node_modules\@react-native\polyfills\error-guard.js:null in ErrorUtils.reportFatalError
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:null in __guard
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:null in callFunctionReturnFlushedQueue

う~ん…。分からん!

とりあえず全パッケージを最新のバージョンにしてみる

yarnは以下のコマンドで、pacakage.jsonに記載されているパッケージを一括で最新化出来ます。

yarn upgrade –latest

すると以下のメッセージが出ました。

info "fsevents@2.3.2" is an optional dependency and failed compatibility check. Excluding it from installation.
error @typescript-eslint/eslint-plugin@5.37.0: The engine "node" is incompatible with this module. Expected version "^12.22.0 || ^14.17.0 || >=16.0.0". Got "14.16.1"
error Found incompatible module.
info Visit https://yarnpkg.com/en/docs/cli/upgrade for documentation about this command.

Nodeのバージョンが合っていないという内容です。
Node.jsの公式サイトから最新版をダウンロードし、最新化してみます。

https://nodejs.org/ja/download/

Node.jsを最新化するとyarnが使えなくなるため再インストールします。

npm install -g yarn

再度、アプリをビルドしてみます。

Some dependencies are incompatible with the installed expo package version:
 - @react-native-community/datetimepicker - expected version: 6.2.0 - actual version instal
 - react - expected version: 18.0.0 - actual version installed: 18.2.0
 - react-dom - expected version: 18.0.0 - actual version installed: 18.2.0
 - react-native - expected version: 0.69.5 - actual version installed: 0.70.0
 - react-native-gesture-handler - expected version: ~2.5.0 - actual version installed: 2.6.
 - react-native-maps - expected version: 0.31.1 - actual version installed: 1.3.1
 - react-native-reanimated - expected version: ~2.9.1 - actual version installed: 2.10.0
 - react-native-safe-area-context - expected version: 4.3.1 - actual version installed: 4.3
 - react-native-screens - expected version: ~3.15.0 - actual version installed: 3.17.0
Your project may not work correctly until you install the correct versions of the packages.
To install the correct versions of these packages, please run: expo doctor --fix-dependenci
or install individual packages by running expo install [package-name ...]

expoとreact-nativeの互換性が合っていないというwarningが出てきました。
解消しておいた方がよさそうなので書いているコマンドを実行してみます。

expo doctor –fix-dependencies

再度アプリをビルドしてみます。
するとまたエラーが出ました。

Invariant Violation: ViewPropTypes has been removed from React Native. Migrate to ViewPropTypes exported from 'deprecatct-native-prop-types'.
at node_modules\expo\build\environment\react-native-logs.fx.js:null in error
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:null in reportException
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:null in handleException
at node_modules\react-native\Libraries\Core\setUpErrorHandling.js:null in handleError
at node_modules\expo\build\errors\ExpoErrorManager.js:null in errorHandler
at node_modules\expo\build\errors\ExpoErrorManager.js:null in <anonymous>
at node_modules\@react-native\polyfills\error-guard.js:null in ErrorUtils.reportFatalError
at node_modules\metro-runtime\src\polyfills\require.js:null in guardedLoadModule
at http://192.168.0.12:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&strict=false&minlse:null in global code

また貴様か

調べたところ、ReactNativeのバージョンが上がることに伴い、ReactNative自体から廃止されたプロパティ等があるようです。
上記エラーは「旧ReactNativeで使用していたViewPropTypesは、’deprecatct-native-prop-types’のものに移行してください」と出ているようです。

yarnでバージョンアップする際、依存関係のあるパッケージは自動でインストールされるため、
‘deprecatct-native-prop-types’自体は既にインストールされています。

ですが、ライブラリの中には更新が滞り、旧バージョンのReactNativeにしか対応出来ていないものがあるようです。

で、今回はそういったライブラリがありました。

通常はnode_modulesの中身を編集するということはしないですが、
今回のような場合は該当箇所を差し替えたり、
コメントアウトしたりすることで対応するようです。

node_modulesディレクトリ配下を「ViewPropTypes」で検索するといくつかあったため、
‘deprecatct-native-prop-types’のものをimportするように修正しました。

するとエラー内容が変わりました。

TypeError: undefined is not an object (evaluating '_reactNative.Text.propTypes.style')
at node_modules\expo\build\environment\react-native-logs.fx.js:null in error
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:null in reportException
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:null in handleException
at node_modules\react-native\Libraries\Core\setUpErrorHandling.js:null in handleError
at node_modules\expo\build\errors\ExpoErrorManager.js:null in errorHandler
at node_modules\expo\build\errors\ExpoErrorManager.js:null in <anonymous>
at node_modules\@react-native\polyfills\error-guard.js:null in ErrorUtils.reportFatalError
at node_modules\metro-runtime\src\polyfills\require.js:null in guardedLoadModule
at http://192.168.0.12:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&strict=false&minlse:null in global code
lled.
at node_modules\expo\build\environment\react-native-logs.fx.js:null in error
n                                                                                       stop it and restart it in the c
at node_modules\expo\build\errors\ExpoErrorManager.js:null in errorHandler
at node_modules\expo\build\errors\ExpoErrorManager.js:null in <anonymous>
at node_modules\@react-native\polyfills\error-guard.js:null in ErrorUtils.reportFatalError
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:null in __guard
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:null in callFunctionReturnFlushedQueue

これも調べたところ旧バージョンのReactNativeでは存在したプロパティを参照しようとしてエラーになっているようでした。

とりあえず使用箇所をコメントアウトしたところ、似たようなエラーが出ました。

TypeError: undefined is not an object (evaluating '_reactNative.Image.propTypes.style')
at node_modules\expo\build\environment\react-native-logs.fx.js:null in error
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:null in reportException
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:null in handleException
at node_modules\react-native\Libraries\Core\setUpErrorHandling.js:null in handleError
at node_modules\expo\build\errors\ExpoErrorManager.js:null in errorHandler
at node_modules\expo\build\errors\ExpoErrorManager.js:null in <anonymous>
at node_modules\@react-native\polyfills\error-guard.js:null in ErrorUtils.reportFatalError
at node_modules\metro-runtime\src\polyfills\require.js:null in guardedLoadModule
at http://192.168.0.12:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&strict=false&minify=false:null in global code

はい、これも同様の理由でエラーが出ているようなのでコメントアウトします。

何度かコメントアウトしてはビルドを繰り返すうちに

ようやくビルドが通った!

androidの実機でもビルド出来ることを確認出来ました。

iosの方はmac mini を起動するのが億劫だったのでまた後日に確認します…。

と、思ったのですが

少し動作確認したところ、ビルドが通ったのは良いのですが、
今度はFirebase周りの処理がエラー吐きまくりでログインすら出来ないことが判明しました。

どうやらFireabaseがv8→9に移行する際に書き方が変わったようです。


Firebase使用箇所を修正する

以下のサイト様を参考にFirebase v8→9に移行してみます。

kata

https://zenn.dev/kata_n/articles/c4c05033c70555

するとログイン処理はうまくいきました。

ですが、ログイン後の画面を表示するとアプリがクラッシュしました。

アプリがクラッシュする原因を調査する

必ず再現するのでおかしいのは分かるのですが、エラーログが出ません。

エラーログが出ないため地道にどのコンポーネントで落ちているのかを調査します。

ReactNativeはコンポーネント指向なので、
使用しているコンポーネントを1つ1つコメントアウトすることである程度究明することが可能です。

地道にコメントアウトしていった結果、
以下のライブラリのコンポーネントを使用しなければ落ちないことが判明しました。

@react-navigation/drawer

こちらのライブラリはアプリ内の「ハンバーガーメニュー」を実現するために利用しているため、
使用を止めるとなると影響が多きすぎます。

そこで同じ現象に出会っている人がいないか調べました。

@react-navigation/drawerの不具合

日本語で検索しても全く引っ掛からなかったため以下のワードで検索したところ、
割と最近かつ「react-navigation」のgithubのissuesが出てきました。

Drawer.Navigator crash

https://github.com/react-navigation/react-navigation/issues/10560

こちらを参考にしたところ
「現状は現状はverを6.3.0にしたら解決する」
とのことでしてみたところ…

動きました!ちゃんとログイン以降の処理も可能です!


古いライブラリを差し替える

本アプリには先述した通り「更新が滞り、旧バージョンのReactNativeにしか対応出来ていないライブラリ」が存在します。
こちらについて、yarnでライブラリを入れる度にjsファイルを修正する必要があるため、
思い切って使用するライブラリを変えることにしました。

問題になっているライブラリは以下です。

react-native-tiny-toast

こちらは通信処理の成功や失敗を一時的に表示する「トースト」に利用していました。
代わりになりそうなライブラリを探したところ以下のライブラリを見つけました。

react-native-toast-message

こちらのライブラリを代わりに使用することで、
最新のReactNativeに合致したトーストを安心して使用できるようになりました。


最終的なpackage.json

以下のようになりました。

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject",
    "lint": "eslint --ext .tsx --ext .ts src/",
    "postinstall": "patch-package"
  },
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "^6.2.0",
    "@fortawesome/free-solid-svg-icons": "^6.2.0",
    "@fortawesome/react-fontawesome": "^0.2.0",
    "@react-native-async-storage/async-storage": "^1.17.10",
    "@react-native-community/datetimepicker": "6.2.0",
    "@react-native-community/masked-view": "0.1.11",
    "@react-native-firebase/app": "^15.4.0",
    "@react-navigation/drawer": "6.3.0",
    "@react-navigation/native": "^6.0.12",
    "@react-navigation/stack": "^6.2.3",
    "@types/moment": "^2.13.0",
    "@types/react-native-calendars": "^1.1264.3",
    "@types/react-native-material-ripple": "^0.9.2",
    "@types/react-native-table-component": "^1.2.4",
    "@types/react-native-vector-icons": "^6.4.12",
    "deprecated-react-native-prop-types": "^2.3.0",
    "expo": "^46.0.0",
    "expo-cli": "^6.0.5",
    "expo-status-bar": "~1.4.0",
    "firebase": "9.9.4",
    "moment": "^2.29.4",
    "patch-package": "^6.4.7",
    "postinstall-postinstall": "^2.1.0",
    "react": "18.0.0",
    "react-dom": "18.0.0",
    "react-native": "0.69.5",
    "react-native-calendars": "^1.1289.0",
    "react-native-dropdown-picker": "^5.4.2",
    "react-native-elements": "^3.4.2",
    "react-native-gesture-handler": "~2.5.0",
    "react-native-maps": "0.31.1",
    "react-native-material-ripple": "^0.9.1",
    "react-native-paper": "^4.12.4",
    "react-native-reanimated": "~2.9.1",
    "react-native-safe-area-context": "4.3.1",
    "react-native-screens": "~3.15.0",
    "react-native-table-component": "^1.2.2",
    "react-native-toast-message": "^2.1.5",
    "react-native-vector-icons": "^9.2.0",
    "react-native-web": "~0.18.7",
    "react-navigation": "^4.4.4",
    "react-navigation-stack": "^2.10.4"
  },
  "devDependencies": {
    "@babel/core": "^7.19.1",
    "@types/react": "~18.0.0",
    "@types/react-native": "~0.70.0",
    "@typescript-eslint/eslint-plugin": "^5.37.0",
    "@typescript-eslint/parser": "^5.37.0",
    "eslint": "^8.23.1",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-prettier": "^4.2.1",
    "prettier": "^2.7.1",
    "typescript": "^4.6.3"
  },
  "private": true
}

今回のまとめ

ExpoSDK42→46成功!

ライブラリのバージョンアップには気を付ける!

不用意にライブラリのバージョンを最新化しない!

情報収集時には英語でも検索してみる!


あとがき

いつになるかは分かりませんが、アプリの紹介記事も書く予定ですので宜しくお願い致します。

コメントを書く