壁紙アプリの一本を EAS で作り直していた夜のことです。ビルドは緑で終わり、成果物も無事に降りてきました。ところが実機で開いてみると、起動した直後に Firebase の初期化だけが静かに落ちておりました。
手元の開発ビルドでは、同じコードが何事もなく動きます。差分を三十分ほど遡って、ようやく思い当たりました。android/app/google-services.json を .gitignore に入れていたのです。履歴に残したくないという気持ちが先に立って、ビルド機には渡さなければならないことを忘れておりました。
EAS Build は、手元のプロジェクトを固めてクラウドへ送ります。そのとき「何を送らないか」を決めているのが、既定では .gitignore です。git に載せないと決めたファイルは、そのままビルド機にも届きません。当たり前のことなのですが、二つの判断が同じ一枚に相乗りしていると気づいたのは、この夜が初めてでした。
.gitignore は履歴に何を残さないかの表で、.easignore はビルド機に何を渡すかの表です。 書式が同じなので同じ表に見えるのですが、答えている問いのほうが違います。
二つの表は、足し算ではなく置き換えです
先ほどの初期化失敗を直そうとして、私は .easignore を新しく作りました。docs/ と dist/ だけを書き、google-services.json はあえて書きませんでした。これで native の設定ファイルは届くようになる、という読みでおりました。
実際、通りました。Firebase は初期化されるようになりました。
代わりに、次のビルドでアップロードが妙に長くなりました。node_modules が丸ごと上がっていたのです。
.easignore は .gitignore に足されるものではありません。存在した時点で .gitignore の代わりに読まれます。ですから .gitignore に書いていた node_modules/ も .expo/ も、.easignore に書き写さないかぎり効きません。「除外を少し足すためのファイル」だと思って書くと、ここで足をすくわれます。
上げる前に、同梱されるものを手元で数えます
送ってから気づくと、ビルド1本ぶんの待ち時間が消えます。私は送る前に数えるようにしました。git 自身の照合器を借りると、数行で済みます。
#!/bin/sh
# 実際に適用されるルールを1枚だけ選び、同梱されるファイルを数えます
RULES=.gitignore
[ -f .easignore ] && RULES=.easignore
echo "適用されるルール: $RULES"
# -o は未追跡ファイル、--exclude-from は指定した1枚だけを無視ルールとして読みます
git ls-files -o --exclude-from="$RULES" | wc -l
git ls-files -o --exclude-from="$RULES" -z | xargs -0 -r du -cb | tail -1
echo "--- 入っていると困るもの / 欠けると困るもの ---"
git ls-files -o --exclude-from="$RULES" \
| grep -E 'google-services|GoogleService-Info|(^|/)\.env|node_modules/|(^|/)\.expo/'要は --exclude-from です。この指定を付けるとワークツリーの .gitignore を巻き込まないので、「.easignore を置いたあとの世界」をそのまま手元で再現できます。
代表的なプロジェクトの形(src/ と assets/ に加えて、node_modules/・.expo/・dist/・docs/・.env・native の設定ファイル2つを置いた合計18ファイル)で、三つのルールを順に当てて数えました。無視ルールのファイル自身は数から外しています。
| 適用したルール | 同梱 | 合計サイズ | 起きること |
|---|---|---|---|
| A .gitignore のみ | 12 ファイル | 5.20 MiB | google-services.json と GoogleService-Info.plist が届かない |
| B docs/ と dist/ だけ書いた .easignore | 16 ファイル | 6.82 MiB | native 設定は届くが node_modules・.expo・.env まで同梱 |
| C 書き直した .easignore | 13 ファイル | 4.53 MiB | native 設定は届き、重いものと .env は除外 |
B は A より 1.62 MiB 増えています。この規模なら誤差のように見えますが、増えた中身が node_modules と .env であることのほうが問題です。ビルド機はどのみち依存を入れ直しますので、送る意味がありません。むしろ、送っているという自覚がないまま毎回上げていたことのほうが、私には気がかりでした。.env に至っては、送る必要がないどころか送りたくないファイルです。値の渡し方は EAS の secret は「アプリに入れない」設定ではありません のほうに寄せてあります。
C が A より 0.67 MiB 小さいのは、docs/ を落としたぶんです。必要なものを足しながら全体は軽くなりました。
親を除外してから、感嘆符で戻すことはできません
C を書くとき、私は最初にこう書こうとしました。
android/
!android/app/google-services.json
prebuild で作り直される android/ を丸ごと落として、設定ファイルを一枚だけ呼び戻すつもりでした。素直な発想だと感じていたのですが、これは効きません。同じ照合器で確かめた結果が次のとおりです。
| 書き方 | google-services.json は |
|---|---|
android/ と !android/app/google-services.json | 除外されたまま(届かない) |
android/* → !android/app → android/app/* → !android/app/google-services.json | 同梱される |
親ディレクトリを丸ごと除外すると、その中のファイルは感嘆符で呼び戻せません。git がディレクトリの時点で中を見るのをやめてしまうためです。戻したいなら、途中の階層を一段ずつ開け直す必要があります。node_modules/ に対して !node_modules/react/index.js を書いても同じように無視されました。
——ここが、私がいちばん時間を溶かした箇所です。書いたつもりの例外が黙って効かないので、ルールの読み違いに気づくまでが長くなります。
私の .easignore の並べ方
いまは、目的の違う三つの塊に分けて書いております。順番そのものに意味はありませんが、あとで読み返すときに迷わなくなりました。
# 1. 送っても使われないもの(ビルド機が作り直します)
node_modules/
.expo/
ios/Pods/
android/.gradle/
dist/
# 2. 送りたくないもの(値は EAS の環境変数側へ)
.env
.env.*
# 3. 単に重いもの(設計資料・元データ)
docs/
design/
# 4. native の設定ファイルはここに書きません
# .gitignore には入れたままにして、EAS へは通します
四つめは、書かないことを書き残しています。空欄のままだと、半年後の自分が「消し忘れでは」と考えて足してしまうためです。理由を一行だけ添えておくと、その迷いが消えます。
環境変数の側を同じように棚卸ししたときの記録は eas env:list に --json がないと分かってから にまとめました。android/ を丸ごと落として良いかどうかの判断は、Expo SDK 57 に上げる前に、prebuild で消えるネイティブ変更を洗い出す の手順が土台になります。
明日ビルドする前の、ひと手間
やっていただきたいことは一つだけです。上の数行のシェルスクリプトを scripts/ に置いて、eas build を叩く前に走らせてみてください。数字が想定と合っていれば、そのまま送って構いません。
私の場合、最初に走らせた日に node_modules が並んでいるのを見つけました。ビルド1本を待ってから気づくのと、送る前の三秒で気づくのとでは、その日の残りの時間がずいぶん違ってまいります。
最後までお読みくださり、ありがとうございました。