React Natvie 版本升級一直是開發上很痛苦的一部分,常常一升級就會有 dependency 壞掉,修了東就壞了西的窘況,在這篇文章中,筆者會分享升級 React Natvie 版本需要注意的什麼?哪時候要升版?最後藉由升級實戰來分享該如何解決升版遇到的每個問題。
雖然以穩定上線的產品角度來說應該要秉持著能動就不升版的精神,但是理想的狀態還是會希望產品的版號還是依 react-native-releases 中所提及的Support level 為主,這邊指的是 React Native 開發團隊所支援的更新的版本,當你的專案版號已經是 Unsupported 的狀態,就要注意了,因為有些 dependency 也會隨著 React Native 版本升級漸漸不支援舊的版本,這時就該考慮是否將整個 React Native 專案升級了。
Version | Type | Support level |
---|---|---|
0.73.x | Next version | Future |
0.72.x | Latest stable | Active |
0.71.x | Previous (-1) minor series | Active |
0.70.x | Previous (-2) minor series | End of Cycle |
<=0.69.x | Old minor series | Unsupported |
以上圖表取自 react-native-releases | ||
不過就筆者經驗來說還是不建議升到 Latest stable 的 0.72 版本,因為有很多套件不一定可以立刻支援到 0.72 版本。 |
以下筆者將實際更新 React Native 的過程與思路紀錄下來。
首先,我們要先瞭解這次要更新的版號的內容是什麼?可以從 React Native 官方的 change log 或是 blog 中查找,或是在 DAY 4 接手 React Native CLI 專案應該知道的事 - React Native 版本 所整理的版本內容得知,以這次要更新的目標版本0.71 幾個重要的更新為例:
預設使用 TypeScript
新增 Flexbox gap 屬性
從上我們可以得知兩件事,那就是 React Native 本身開始支援 TypeScript,這代表可能在專案升級到 0.71 後程式碼會出現型別的錯誤,可能會花一些時間去排除型別錯誤的問題,Flexbox gap 的屬性可以改變過去排版上的不足,雖然升級的過程中不需要用到,但是在未來佈局時可以更方便的排版。
React Native 有推出一個升級版本的工具 React Native Upgrade Helper,選定好專案的版本與目標的升級版本,下方就會顯示兩個版本差異的程式碼。
依照提供需要更新的 dependencies 跟相對應的版本開始一個一個手動升級,如果有些套件的版號已經比文件裡建議的版號高或相同就不用更新了:
yarn add react-native@0.71.13
yarn add --dev eslint@8.19.0
yarn add --dev prettier@2.4.1
yarn add --dev @react-native-community/eslint-config@3.2.0
yarn add --dev @tsconfig/react-native@2.0.2
yarn add --dev @types/react@18.0.24
yarn add --dev metro-react-native-babel-preset@0.73.10
最後,更新 iOS Pod
cd ios && pod install
根據這份文件,我們可以拆分為在 android/
目錄底下的原生程式碼跟 ios/
目錄底下的原生程式碼以及在這兩者之外的非原生程式碼,由於原生程式碼更新的部分是最麻煩而且有可能會噴一堆錯,所以先把非原生的程式碼根據文件提供的內容修改。
接著,我們開始依照文件內容修改 iOS 的部分,會先修改 iOS 的原因在於升級時 iOS 相對 Android 比較不會有太多令人驚喜的錯誤!
文件上的 RnDiffApp 要自己帶入你的專案名稱。
所以依照文件建議修改了
cd ios && pod install
yarn run iOS
看看你的 iOS APP 是否正確的安裝在模擬器上。
Android 也是照著文件進行更新,但是建議使用 Android Studio 進行更新。
在更新完程式碼時,記得點一下右上方的藍色小象圖示,以同步更新專案的 Gradle 檔案。同時在更新的過程中遇到 App Id 的部分一樣要記得帶入自己專案的 App Id。
照著文件更新完成後
yarn run android
開始發生錯誤了~
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.5/userguide/command_line_interface.html#sec:command_line_warnings
145 actionable tasks: 6 executed, 139 up-to-date
ERROR:/Users/ashely/App/android/app/build/ASSETS/createBundleDevelopmentDebugJsAndAssets/CodePushHash /Users/ashely/App/android/app/build/ASSETS/createBundleDevelopmentDebugJsAndAssets/CodePushHash: Resource and asset merger: Duplicate resources
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:mergeDevelopmentDebugAssets'.
> /Users/ashely/App/android/app/build/ASSETS/createBundleDevelopmentDebugJsAndAssets/CodePushHash /Users/ashely/App/android/app/build/ASSETS/createBundleDevelopmentDebugJsAndAssets/CodePushHash: Error: Duplicate resources
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 9s
在這個錯誤訊息中可以找到一個關鍵字 CodePushHash: Error: Duplicate resources
,因此可以推斷說 react-native-code-push 可能有問題,果然在 react-native-code-push 的 issue 中找到也有人有一樣的問題: https://github.com/oblador/react-native-vector-icons/issues/1443 。
將原來 react-native-code-push 的版本從 7.1.0 升級到 8.0.0 。
cd android && ./gradlew clean
同步 Gradle 檔案
yarn run android
warn Package react-native-vector-icons contains invalid configuration: "dependency.assets" is not allowed. Please verify it's properly linked using "react-native config" command and contact the package maintainers about this.
看起來是 react-native-vector-icons 的問題,一樣找 issue 果然也有人遇到:https://github.com/oblador/react-native-vector-icons/issues/1443
將原來 react-native-vector-icons 的版本從 8.1.0 升級到 10.0.0 。
cd android && ./gradlew clean
同步 Gradle 檔案
yarn run android
* What went wrong:
Execution failed for task ':app:mergeDevelopmentDebugAssets'.
> [fonts/Fontisto.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Fontisto.ttf [fonts/Fontisto.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Fontisto.ttf: Error: Duplicate resources
[fonts/Octicons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Octicons.ttf [fonts/Octicons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Octicons.ttf: Error: Duplicate resources
[fonts/Feather.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Feather.ttf [fonts/Feather.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Feather.ttf: Error: Duplicate resources
[fonts/Entypo.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Entypo.ttf [fonts/Entypo.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Entypo.ttf: Error: Duplicate resources
[fonts/FontAwesome5_Brands.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf [fonts/FontAwesome5_Brands.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/FontAwesome5_Brands.ttf: Error: Duplicate resources
[fonts/MaterialCommunityIcons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf [fonts/MaterialCommunityIcons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/MaterialCommunityIcons.ttf: Error: Duplicate resources
[fonts/AntDesign.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/AntDesign.ttf [fonts/AntDesign.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/AntDesign.ttf: Error: Duplicate resources
[fonts/Foundation.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Foundation.ttf [fonts/Foundation.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Foundation.ttf: Error: Duplicate resources
[fonts/Ionicons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Ionicons.ttf [fonts/Ionicons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Ionicons.ttf: Error: Duplicate resources
[fonts/FontAwesome5_Solid.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf [fonts/FontAwesome5_Solid.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/FontAwesome5_Solid.ttf: Error: Duplicate resources
[fonts/FontAwesome5_Regular.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf [fonts/FontAwesome5_Regular.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/FontAwesome5_Regular.ttf: Error: Duplicate resources
[fonts/FontAwesome.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/FontAwesome.ttf [fonts/FontAwesome.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/FontAwesome.ttf: Error: Duplicate resources
[fonts/Zocial.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/Zocial.ttf [fonts/Zocial.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/Zocial.ttf: Error: Duplicate resources
[fonts/EvilIcons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/EvilIcons.ttf [fonts/EvilIcons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/EvilIcons.ttf: Error: Duplicate resources
[fonts/SimpleLineIcons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/SimpleLineIcons.ttf [fonts/SimpleLineIcons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/SimpleLineIcons.ttf: Error: Duplicate resources
[fonts/MaterialIcons.ttf] /Users/ashely/App/android/app/src/main/assets/fonts/MaterialIcons.ttf [fonts/MaterialIcons.ttf] /Users/ashely/App/android/app/build/intermediates/ReactNativeVectorIcons/fonts/MaterialIcons.ttf: Error: Duplicate resources
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 38s
透過錯誤訊息中的 ReactNativeVectorIcons
關鍵字得知又是 react-native-vector-icons 的問題!一樣在 issue 中搜尋發現:https://github.com/oblador/react-native-vector-icons/issues/1490#issuecomment-1457046459
將 \android\app\src\main\assets\fonts\
的字型整個刪掉。
cd android && ./gradlew clean
同步 Gradle 檔案
yarn run android
/Users/ashely/App/android/app/src/debug/java/com/app/ReactNativeFlipper.java:32: error: duplicate class: com.app.ReactNativeFlipper
public class ReactNativeFlipper {
^
Note: /Users/ashely/App/android/app/src/main/java/com/app/MainApplication.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
1 error
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:compileDevelopmentDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 9s
error Failed to install the app.
info Run CLI with --verbose flag for more details.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
截取部分錯誤內容丟 google 得到了:https://github.com/facebook/react-native/issues/36362#issuecomment-1454845471
將 \android\app\src\
底下新增 release 資料夾並且把 new ReactNativeFlipper 檔案搬到這個路徑底下。
cd android && ./gradlew clean
同步 Gradle 檔案
yarn run android
但是因為剛剛有升級了某些套件的版本,所以在 iOS 的部分也要記得更新 pod!
cd ios && pod install
yarn run iOS
沒問題的話就進入最後的測試了。
如果一切都順利的話,那就恭喜你搞定了一大堆的錯誤成功升級!也升級了你的 debug 能力!
有沒有可能升級失敗?
有!
而且機率很高!
之前筆者就有經驗升級到某個版本後,某個套件就壞了,查了一下該套件的 issue ,也有人在遇到同樣的問題,但就是遲遲等不到維護的人進行 hot fix 而這時也沒有能力去提出修正的 PR ,那就只好放棄這次的升級了。
曾經也遇到專案用的套件已經超過 3 年沒人維護了,在打包時錯誤訊息指出該套件的某個 API 已經棄用了,這時也只好硬著頭皮自己寫 patch 去修改,寫 patch 的方式已經在先前分享過了 Day 9 修改 npm 套件的好幫手 - patch-package。
總之,升級 React Native 版本有一定的風險,升級前最好還是一再評估!