素の React Native のバージョンアップの苦痛と、解決策としての Expo

Published: 2023/9/13


素の React Native を用いて開発する場合、 ios ディレクトリと android ディレクトリがそれぞれのスマホ端末での開発プロジェクトとして作成され、それぞれのプロジェクト設定の中で、上位の React を利用する形でビルドを行う、という構成でプロジェクト全体がセットアップされる。 つまり、素の React Native 開発とは、 Android アプリプロジェクトと iOS アプリプロジェクト、その共通で利用される React プロジェクトの3つを管理しながら開発を行っていることに相当する。

フレームワークとしての React Native は、このセットアップを実現するため、特に iOS / Android のプロジェクト設定については、フレームワーク内部で init する際に生成するテンプレートのようなものを持っていて、 React Native プロジェクトを作成するタイミングで、このテンプレートが実体化され、開発者はこの実態化されたコードを使って、 iOS / Android としての開発を行うことになる。

この構成は、初期の開発においてはそこまで問題にならないが、特に、 React Native のバージョンを上げようとすると問題になる。 というのも、フレームワークが提供するライブラリ的な機能とテンプレートのベースの両方がバージョンアップによって変更されていくため、既に実体化してしまった既存の React Native のバージョンアップについては、利用しているライブラリのアップデートに加えて、 iOS / Android プロジェクトとして React Native というフレームワークが期待する構成についてのバージョン間の変化を、手動で適用してフレームワークに追随する、という行為が必要になる。

React Native Upgrade Helper などのツールはあったりするが、これは、各バージョン毎に仮想的なプロジェクトを生成してみて、その結果発生している差分を表示したり、パッチとして適用していったりをできるようにするツールである。 素の React Native で開発している以上、 iOS / Android プロジェクトとして何かしらのカスタマイズを行いたくなるものであり、そして実際にそれが行われていたような場合に、 React Native のテンプレート部分の差分が自分の行ったカスタマイズ部分とぶつかっていたりすると、 3 way merge のコンフリクトの解消ゲームが発生して、基本的に辛い作業になる。 特に、 iOS の XCode のプロジェクトファイルは、ファイル形式としてはあまり綺麗な構造をしている訳ではないので、アップグレードのためのツールが出力する差分ファイルも同様にあまり綺麗なものにはならず、結果、いろいろ気合を入れて比較していかないと、何が変わったのか、ないし変わっていないのかの判定がつきづらい、みたいな事態が発生する。

解決策としての Expo

Expo はその登場当初から、 React Native の開発者が iosandroid のディレクトリを管理していかなくても開発ができることを、プラットフォームとしての目的としている。 当初の Expo は、 iOS と Android において必要になる設定群をすべて吸収し、 Expo Runtime (Expo Go) のような expo の設定を読み取りながら Metro によってバンドリングされた Javascript さえ読み込めればアプリとして動作するような形で提供していた。 これはしかし、モバイル開発において欲しい native 機能を全部網羅はできないので、ある程度最大公約数的な機能のみを Expo Runtime / SDK に詰め込んでいくことになり、そこでサポートされない機能の開発を行いたかったら、素の React Native としての開発フロー(aka. bare workflow)を行ってくれ、という感じになってしまっていた。

その後機能が拡充され、 Expo Runtime 部分に組込みたいネイティブ機能などを Expo Module として定義し、その設定を用いて各プロジェクト用の Expo Runtime のビルド、みたいなことができるようになった。 これは、 Expo の資料上では Prebuild と呼ばる機能である。 それに限らず、 Expo Module としてできることのノリとしては、どのような ios / android のプロジェクト構成になるべきかの設定を、各 Expo Module から Project Structure as Code のようなノリで、設定していくことが可能となっている。

Expo プロジェクトにおいては、なので、「どのように iOS / Android プロジェクトを生成するべきか」についてが各 expo module のライブラリをすべて読み込んだ結果によって、定義されることになる。 最早、 ios / android のディレクトリ(プロジェクト)はソースコードの管理対象ではなく、その ios / android プロジェクトの生成コードがバージョン管理されて expo module として定義されるだけとなる。 結果、バージョンアップを行いたかったら、各 module をアップグレードしていき、結果として生成される virtual な ios / android プロジェクトを変化させていく、という開発フローとなる。

これにより、バージョンアップごとの ios / android ディレクトリの、フレームワーク側での差分と、自分のプロジェクトでテンプレートから生成されたコードに対するカスタマイズ部分のマージ、という苦行から開発者は開放される。 これから React Native で開発していくならば、 Expo を使っていくのが良い、というのが素直な感想になる。(なった。)


Tags: react-nativeexpo

関連記事