TermuxでFirebaseを使いたい

# 背景

※執筆時点のfirebase-toolsは8.12.0です。

[Termux](https://termux.com/)で[Firebase](https://firebase.google.com/)のエミュレータを起動したかった。

Termuxでもfirebase-toolsが入れられるので、firebase emulatorsも当然使えると思ったがそうはいかなかった。
firestoreとdatabaseのエミュレータはJavaで実装されているが、TermuxにはJavaが用意されていないため起動できない。

そこで、Javaのインストールから`firebase emulators:start --only firestore`を起動できるまでの手順を紹介する。

# 手順

## 0. 準備

既に一通り済んでいる場合は飛ばす。

### Termux

PlayストアからTermuxをインストールする。

### Termuxパッケージ

最低限以下のパッケージが必要になるので、Termux上でインストールする。

- proot
- wget
- vimなどのテキストエディタ
- nodejsまたはnodejs-lts
    - firebase-tools

## 1. Javaのインストール

前述の通り、Javaが用意されておらずパッケージもない。
しかし、[Termux-Java](https://github.com/MasterDevX/Termux-Java)と言うスクリプトを使えば一応Javaが使えるようになる（一応とした理由は後述する）。

```shell
$ wget https://raw.githubusercontent.com/MasterDevX/java/master/installjava && bash installjava
```

これでJavaが使えるようになる…はずだが、筆者の環境では`Bad system call`と言うログとともにJavaがkillされた。
[Issue](https://github.com/MasterDevX/Termux-Java/issues/7)によればroot権限が必要なようなので、`proot`を併用して起動するか確認する[^1]。

[^1]: 本用途の他にもjavaコマンドを直接使う用があるなら、aliasを設定しておくと便利。

```shell
$ proot java
```

## 2. firebase-tools(firestoreエミュレータ)の修正

firestore及びdatabaseのエミュレータはjarファイルで提供されており、javaコマンドで実行するようになっている。
この時、javaコマンドは`childProcess.spawn()`を使って実行しているが、`PATH`からjavaコマンドを探して実行するため、仮にaliasで`proot java`に設定していたとしても関係なく素のjavaコマンドを実行し、`Bad system call`で起動に失敗する。

なので、ここは少し強引だがfirebase-toolsのソースコードを直接編集して対応する。

編集対象となるファイルは[downloadableEmulators.ts](https://github.com/firebase/firebase-tools/blob/master/src/emulator/downloadableEmulators.ts)なので、ローカル環境でこのファイルを捜索してテキストエディタで開く。

firebase-toolsをグローバルにインストールしている場合は、デフォルトでは

```
/data/data/com.termux/files/usr/lib/node_modules/firebase-tools/lib/emulator/downloadableEmulators.js
```

として存在している（はず）。

118行目、124行目あたりを以下の通りに修正する。

```diff
Line: 118
      database: {
-         binary: "java",
-         args: ["-Duser.laungage=en", "-jar", getExecPath(types_1.Emulators.DATABASE)],
+         binary: "proot",
+         args: ["java", "-Duser.laungage=en", "-jar", getExecPath(types_1.Emulators.DATABASE)],

Line: 124
      firestore: {
-         binary: "java",
-         args: ["-Duser.laungage=en", "-jar", getExecPath(types_1.Emulators.FIRESTORE)],
+         binary: "proot",
+         args: ["java", "-Duser.laungage=en", "-jar", getExecPath(types_1.Emulators.FIRESTORE)],
```

要するに、**javaではなくprootを実行し、引数としてjavaを渡す**ように変更する。

## 3. 確認

これでエミュレータが動作するはずなので、プロジェクトディレクトリに戻ってエミュレータを起動する。

```shell
$ firebase emulators:start --only firestore
```

# 問題点

## エミュレータ終了時にjavaのプロセスが残る

エミュレータの終了に失敗し、firebaseプロセスの子プロセスであるはずのjavaが残り続けてしまう。
このjavaプロセスは8080ポートを占有しており、続けてエミュレータを起動しようとすると8080ポートが空いていないことによってエミュレータが起動できなくなってしまう。

現時点では原因がわかっていないため、都度プロセスをkillして対応する[^2]。

[^2]: prootだけがSIGINTを受け取り、javaは受け取っていない？

```shell
$ lsof -i:8080
# -> 8080を占有するjavaプロセスのpidがわかるはずである。プロセスがない場合は問題が発生していないので、そのままエミュレータを起動できる。
$ kill javaプロセスのpid
```

## firebase-toolsのコードを編集している

編集せずにうまいことやる方法があったら教えてください。

## ブラウザの開発ツールがない

この記事の主題とは直接関係ないが、hostingエミュレータを使えば作ったソースコードをlocalhostで閲覧できる。
しかし、閲覧に使用するブラウザはAndroidアプリなので開発ツールがなく、デバッグできない。

# 参考

解決に時間がかかったので、残っていたタブから抜粋。実際にはもっとたくさんのページを閲覧した。

- https://termux.com/
- https://firebase.google.com/
- https://github.com/firebase/firebase-tools
- https://github.com/MasterDevX/Termux-Java/issues/7
- https://qiita.com/shintarogit-on-qiita/items/70f193829f4360dca771
    - javaコマンドをどのようにして起動しているかを調べた。
- https://swfz.hatenablog.com/entry/2019/10/07/001242
    - patch-packageでうまいことしたかったが、グローバルインストールだったので断念した。ローカルならいけるかもしれない。
- https://qiita.com/tacchi/items/a532aafd9c05fdf7be45
    - Termuxのセットアップの参考にした。
    - Ubuntu(LXDE, TermuxとUserLAndの両環境)も試したが動作が重く、Firefoxに何も表示されなかったので断念した。デスクトップが快適に動く環境ならLinux版のブラウザが使えるので開発ツールも使えるはず。
- https://knowledge.sakura.ad.jp/21687/
    - 筆者はそもそもvimmerではない。しかし、恐れていたほどではなかった（傲慢）。