Remote Containersシリーズです。
はじめに
自分はいつも開発環境としてRemote Containersを使った環境を用意しています。多くの場合、各言語のランタイムなどを普段作業している手元のマシン(Macbook Pro)に直接インストールするのではなくてDockerコンテナとして用意をしてその中で作業をしています。こういうとちょっと面倒くさそうに感じる人もいるかもしれませんが、そのあたりの手間はVS CodeのRemote Containersが吸収してくれます。
詳細はこちらに書いてます。
DockerとRemote Containersでの開発環境が最高過ぎる - Sweet Escape
さて、今回はReact Nativeの開発環境をRemote Containersでセットアップしていきます。最初は無理かと思ってたがiOSは一応できた!Androidは今のところちょっと妥協しないとできてない。というわけで一勝一敗です。
全体の流れ
実際のところReact Nativeの環境そのものはRemote Containersでやるのにそんなに難しくはないです。
今回はモバイルアプリってことでどちらかというとReact Nativeを使って開発したモバイルアプリをビルドしたりシミュレータでどう実行するのかってのが主眼になります。
結論から言うと、ここに関してはどう頑張ってもコンテナを使ってやるのは難しそうでした。手元の端末に標準で入っているランタイム以外は入れたくない自分にとっては残念かつ悔しいところですが仕方ない。
というわけで、React Nativeでコードを書くのはVS Code + Remote Containers、ビルドとシミュレータでの実行はXcodeとAndroid Studioを手元の端末にインストールしておく必要があります。つまり、ビルドとシミュレータ実行はコンテナではなく手元の端末上で実行する必要があります。
まあ、そんなに頑張らなくてもいいじゃないって話もあるかもしれませんが僕のこだわりですね。
コンテナのセットアップ
まずはRemote Containersで使うためのコンテナの環境を用意します。今回はReact NativeなのでNode.jsの環境を用意します。適当にプロジェクトフォルダを作って作業していきます。まずはここに以下のようなシンプルなDockerfileを用意しています。
FROM node:15.3.0 RUN apt-get update && apt-get install vim -y && apt-get clean
なんてことはない内容ですね。必要に応じて追加パッケージを入れておくといいです。Remote Containersの設定ファイルである.devcontainer/devcontainer.jsonもこんな感じで至って普通の普段使っているものを用意しました。
{
"name": "Existing Dockerfile",
"context": "..",
"dockerFile": "../Dockerfile",
"build": {
"target": "dev"
},
"settings": {
"terminal.integrated.shell.linux": null
},
"extensions": [
"visualstudioexptteam.vscodeintellicode",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"hookyqr.beautify",
"alefragnani.bookmarks",
"lacroixdavid1.vscode-format-context-menu",
"eamodio.gitlens",
"oderwat.indent-rainbow",
"ionutvmi.path-autocomplete",
"chrmarti.regex",
"humao.rest-client",
"wayou.vscode-icons-mac"
]
}
いくつかExtensionをインストールするようにしていますがここは好みでお願いします。
このフォルダをVSCodeで開いてこのリモートコンテナに接続してターミナル開くのですがこのあたりは以前の投稿を参考にしてください。
さて、このプロジェクトフォルダをVS Codeで開いてコンテナで開きなおしたらターミナルを起動します。
ひとまず今回はサンプルとしてReact Nativeのテンプレートプロジェクトを用意していきます。
VS Code上のターミナルで以下を実行するだけです。
$ npx react-native init MyNewProject
これを実行すると必要な関連パッケージなどがインストールされた上でひな形となるアプリが作成されます。なお、Remote Containersで作業しているとVS Codeで開いたフォルダの中にできあがってしまうのですが、プロジェクトフォルダ直下に展開したい場合は中身をmvでまるごと移動するといいと思います。僕は普段そうやることが多いです。
あとは普通に開発していくだけですね。
iOSのシミュレータで実行
さて、ここからはiOSのシミュレータでアプリを実行したり、ビルドしたりするときの話です。
まずは手元のMacにXcodeをインストールしてください。コンテナでやれないかとかいろいろ調べたり試したんですがこれは難しそうだったので悔しいけど諦めます。
そして、XcodeでMyNewProject/ios/MyNewProject.xcworkspaceというファイルを開くことでプロジェクトを開きます。が、ただ開くだけではReact Native関連のヘッダファイルなどがないとかってことでエラーになります。というわけでこのあたりをインストールするのですが、それにはCocoaPodsをインストールする必要があります。
というわけでインストールするのですがこれはMacにあらかじめ同梱されているRubyを使えばいいです。
$ sudo gem install cocoapods
※ ちなみに自分のMacは事情によりCatalinaのままなんですが、そうすると最新のXcodeではYou have to install development tools first.と言われてCocoaPodsのインストールに失敗しました。なので少し古いバージョンをインストールしています。どんなバージョンが必要かはgem installしたときのエラーメッセージで表示されているファイルパスに含まれてます
さて、ここまで来たらあとはpod installするだけです。と思いきや僕のようにすべてをコンテナで動かしている場合は手元のMacにNode.jsが入ってないんですね。そうするとnodeコマンドが見つからないと言われてしまうんですね。なのでPodfileを以下のように少しだけ変更します。
target 'MyNewProject' do
config = {:reactNativePath=>"../node_modules/react-native"}
元々、use_native_modules!が実行されているんですがこれがNode.jsの実行ファイルがないと動作しないんですね。で、手元の端末にはもちろんNode.jsも入っていないのでこれが実行できないんです。なのでハードコードしてしまいます。
さらにもう一箇所、Podfile内の以下の箇所をコメントにしてしまいます。
use_flipper!
post_install do |installer|
flipper_post_install(installer)
end
これは現状だとFlipperがエラーになってしまうんですよね。
というわけで外してしまいます。そして改めて、
pod install
そうするともろもろのパッケージがイントールされますので完了したら改めてXcodeでMyNewProject/ios/MyNewProject.xcworkspaceを開きます。そしておもむろにビルドするとシミュレータが起動されアプリが実行できることが確認できるかと思います。

Androidのエミュレータで実行(失敗)
Androidも基本的に同じ流れだろうというわけでこちらも手元の端末にAndroid Studioを事前にインストールしておきます。その上で必要なAndroid SDKをダウンロードしておき、AVD Managerで仮想デバイスを作成しておきます。
この状態でXcodeのときと同様にAndroid Studioを起動してMyNewProject/androidフォルダを開いてみます。
buildが走り…………ダメでした。
Caused by: java.io.IOException: Cannot run program "node"というエラーが出てビルドに失敗してるようです。
Node.jsを端末にはインストールしていないからだと思われるのでRemote Containersで使ってるDockerコンテナのnodeを使うべくaliasを張ってみます。こんな感じで。
$ alias node='docker exec -it <イメージID> node' $ node -v v15.3.0
といけそうなのでもう一回Android Studioでチャレンジ。でもダメ…。
Android Studioがこのエイリアスを認識できてないのかなと思って色々試してみたりしたものの、そもそもAndroid Studio自体に不慣れなこともあってなかなかうまくいかない。
誘惑に屈してMacにNode.jsを入れて試してみるとあっさりビルドできるではないか。この時点でもはやMacにランタイム入れてるし目的を見失ってる感はあるが、nodeさえ実行できればビルド問題なくできることがわかった。
ついでにエミュレータを起動してアプリを実行してみる。もちろん先にnpx react-native startしておく。

だがなぜか画面が真っ白だ。Metroサーバにはちゃんと接続できてるっぽいんだけどなー。
Android難しい。というわけでいったんここまで。ビルドだけならSDKやらも全部コンテナに突っ込んでしまって実行することは可能っぽいけど開発するときっはエミュレータで実行できないと辛すぎる。
追記1
画面が真っ白だったのはどうやらパフォーマンスの問題だったようだ。
エミュレータの設定でEmulated PerformanceのGraphicsをHardwareに明示的に設定したらちゃんと表示されるようにはなった。

というわけであとはMacにNode.jsを入れずになんとかする方法を探すだけだ。Android Studioで実行されるgradlewで呼び出されるnodeがaliasのものを使ってくれるといいんだが。.bash_profileとかに設定してもダメみたい。
まとめ
というわけでReact NativeをVS Code + Remote Containersの環境だけで開発するのはなかなか大変なことがわかりました。開発というよりはビルドとシミュレータ/エミュレータでの実行が大変ですね。
とりあえずiOSのほうはできたもののAndroidはまだちゃんとうまくいってないので知見ある人いたらぜひTwitterのDMとかで教えてください。
ていうか、ここまで大変だとReact NativeはVS Code + Remote Containersにこだわらないほうが吉な気もしてる。わかってる。