メインコンテンツへスキップ

Gitによるアップグレードの簡素化

·5分で読めます
Nicolas Cuillery
ZenikaのJavaScriptコンサルタント兼トレーナー

React Nativeの新しいバージョンへのアップグレードは困難でした。以前、このような画面を見たことがあるかもしれません。

これらの選択肢はどれも理想的ではありません。ファイルを上書きするとローカルの変更が失われます。上書きしないと最新のアップデートが適用されません。

本日、この問題を解決する新しいツールを紹介できることを誇りに思います。このツールは react-native-git-upgrade と呼ばれ、裏側でGitを使用して、可能な限り自動的にコンフリクトを解決します。

使用方法

要件:Gitが PATH で利用可能である必要があります。プロジェクトがGitで管理されている必要はありません。

react-native-git-upgrade をグローバルにインストールします。

$ npm install -g react-native-git-upgrade

または、Yarn を使用する場合

$ yarn global add react-native-git-upgrade

その後、プロジェクトディレクトリ内で実行します。

$ cd MyProject
$ react-native-git-upgrade 0.38.0

注意:react-native の新しいバージョンをインストールするために 'npm install' を実行しないでください。このツールが正しく動作するためには、古いプロジェクトテンプレートと新しいプロジェクトテンプレートを比較できる必要があります。古いバージョンを使用している状態で、上記のようにアプリのフォルダ内で実行してください。

出力例

引数なしで react-native-git-upgrade を実行して、React Nativeの最新バージョンにアップグレードすることもできます。

AndroidとiOSのビルドファイルにおける変更を保持しようと試みるため、アップグレード後に react-native link を実行する必要はありません。

実装はできるだけ影響が少なくなるように設計されています。一時ディレクトリにその場で作成されるローカルのGitリポジトリに完全に依存しています。プロジェクトのリポジトリ(Git、SVN、MercurialなどのVCSや、VCSを使用していない場合でも)に干渉することはありません。予期せぬエラーが発生した場合は、ソースは復元されます。

仕組み

重要なステップはGitパッチの生成です。このパッチには、アプリが使用しているバージョンと新しいバージョンの間でReact Nativeテンプレートに加えられたすべての変更が含まれています。

このパッチを取得するには、node_modules ディレクトリ内の react-native パッケージに埋め込まれたテンプレートからアプリを生成する必要があります(これらは react-native init コマンドが使用するのと同じテンプレートです)。その後、現在のバージョンと新しいバージョンの両方のテンプレートからネイティブアプリが生成されると、Gitはプロジェクトに適合した(つまりアプリ名を含む)パッチを生成できます。

[...]

diff --git a/ios/MyAwesomeApp/Info.plist b/ios/MyAwesomeApp/Info.plist
index e98ebb0..2fb6a11 100644
--- a/ios/MyAwesomeApp/Info.plist
+++ b/ios/MyAwesomeApp/Info.plist
@@ -45,7 +45,7 @@
<dict>
<key>localhost</key>
<dict>
- <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
+ <key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
[...]

あとはこのパッチをソースファイルに適用するだけです。古い react-native upgrade プロセスでは、わずかな違いでもプロンプトが表示されましたが、Gitは3-wayマージアルゴリズムを使用してほとんどの変更を自動的にマージし、最終的には見慣れたコンフリクト区切り文字を残してくれます。

    13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
<<<<<<< ours
CODE_SIGN_IDENTITY = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/HockeySDK.embeddedframework",
"$(PROJECT_DIR)/HockeySDK-iOS/HockeySDK.embeddedframework",
);
=======
CURRENT_PROJECT_VERSION = 1;
>>>>>>> theirs
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../node_modules/react-native/React/**",
"$(SRCROOT)/../node_modules/react-native-code-push/ios/CodePush/**",
);

これらのコンフリクトは通常、理解しやすいものです。区切り文字 ours は「あなたのチーム」を表し、theirs は「React Nativeチーム」と見なすことができます。

なぜ新しいグローバルパッケージを導入するのか?

React NativeにはグローバルCLI(react-native-cli パッケージ)が付属しており、これは node_modules/react-native/local-cli ディレクトリに埋め込まれたローカルCLIにコマンドを委譲します。

前述の通り、このプロセスは現在のReact Nativeバージョンから開始する必要があります。もし実装がlocal-cliに埋め込まれていたら、古いバージョンのReact Nativeを使用している場合にこの機能を利用できませんでした。例えば、この新しいアップグレードコードが0.38.0でしかリリースされていなかった場合、0.29.2から0.38.0へのアップグレードはできなかったでしょう。

Gitベースのアップグレードは開発者体験の大きな改善であり、すべての人が利用できるようにすることが重要です。グローバルにインストールされる別のパッケージ react-native-git-upgrade を使用することで、プロジェクトがどのバージョンのReact Nativeを使用していても、今日からこの新しいコードを使用できます。

もう一つの理由は、最近のMartin KonicekによるYeomanの廃止です。パッチを作成するために古いテンプレートを評価できるよう、これらのYeomanの依存関係を react-native パッケージに戻したくありませんでした。

試してみてフィードバックをお願いします

結論として、この機能を楽しんでいただき、改善の提案や問題の報告、そして特にプルリクエストの送信を自由に行ってください。それぞれの環境は少しずつ異なり、各React Nativeプロジェクトも異なります。このツールがすべての人にとってうまく機能するように、皆さんのフィードバックが必要です。

謝辞

この実現を可能にしてくださった素晴らしい企業、ZenikaM6 Web (アーカイブ) に感謝します!