React Nativeのアプリの結合テスト環境を作りたいのですが、そのためには開発用・テスト用・本番用など、複数のFirebaseプロジェクトを容易に切り替えられるような仕組みが欲しいところです。
そこで、
[webpackでfirebaseのconfigファイルをプロジェクト毎に動的に生成する(環境切り替えに使える)]
(https://qiita.com/zaburo/items/25e32e33943581b38ad9)
こちらの記事を参考にしながら、Firebaseの設定ファイルを動的に生成してみたいと思います。
上記の記事ではWebpackの独自loaderを作って設定ファイルを差し替えていますが、Expoで作成しているアプリなど、モジュールバンドラの設定を変更できない場合もありますので、loaderで直接Webpack等に渡すのではなく、設定ファイル自体を生成してしまって、.gitignore
に追加するという方針でやってみます。
切り替えるプロジェクトの情報を用意
$ firebase login
$ firebase init
は、すでに済んでいるでしょうから、.firebaserc
にプロジェクトエイリアスの情報があるはずです。
{
"projects": {
"default": "some-default-project",
"test": "some-test-project"
}
}
なんでもいいですが、こんな感じでデフォルトはこのプロジェクト、テスト用はこのプロジェクト、というエイリアスを登録します。これは直接.firebaserc
を編集するでもいいし、
$ firebase use --add
で追加するのでもいいです。
.firebaserc
をリポジトリ上に公開するかどうかは場合によるでしょうが、公開しない場合、かつ必要なエイリアスを明示したい場合は.firebaserc-example
などを置いてもいいかと思います。
設定ファイルを取得するスクリプトを作成
ローカルにfirebase-tools
をインストールします。
$ npm install --save-dev firebase-tools
これをコマンドを直接叩くのではなくJSファイルで使います。
コマンドの挙動はnode_modules/firebase-tools/lib/commands
を直接見るか、
公式の簡易的なリファレンスで確認してください。
では、ここで元の記事で使用しているsetup:web
を使いたいのですが、どうやら公式リファレンスを見るとこのコマンドは非推奨とされているようです。
なのでリファレンスに書いてある通り、apps:sdkconfig
を使用してみます。
このコマンドで生成できる設定ファイルはJSONではなくglobal変数にfirebase
がある前提のJSファイルという面倒な代物なので(後ほど記載)、正直なところsetup:web
を使ってしまった方がいいと思いますが、我慢します。
まず、そもそもReact NativeアプリはFirebaseにとってはWebアプリということでいいのかという疑問もあります。
少なくともExpoで開発しているときはWebアプリとして扱い、ejectしたりした後はiOS/Androidそれぞれという感じかと思っています。
さて、scriptsディレクトリを作り、Node.jsの世界で動く以下のようなJSを書きます。
const fs = require('fs');
const firebaseTools = require('firebase-tools');
(async () => {
try {
const firebaseRC = JSON.parse(fs.readFileSync('./.firebaserc'));
const projectId = firebaseRC.projects[process.argv[2]];
await firebaseTools.use(projectId, {});
const apps = await firebaseTools.apps.list('WEB', {});
const currentApp = apps[0];
const config = await firebaseTools.apps.sdkconfig('WEB', currentApp.appId, {});
fs.writeFileSync('./js/firebaseConfig.js', config.fileContents);
console.log(`Current firebase project is ${currentApp.projectId}`);
} catch (e) {
console.log(e);
}
})();
- 先ほどの
.firebaserc
を読み込み - 実行時の引数(
process.argv[2]
)からプロジェクトを特定。 -
use
コマンドで使用するプロジェクトを宣言 - プロジェクト内のWebアプリ一覧を取得
- とりあえず0番目のアプリを現在のアプリだとする。Webアプリが複数ある場合はここでさらに特定が必要です。
- 設定ファイルの内容を取得
- 設定ファイルをwrite
このような流れで、js/firebaseConfig.js
が生成されます。
後々整形するかもと思ったのでfsモジュールを使ってwriteしていますが、このように
await firebaseTools.apps.sdkconfig(
'WEB',
currentApp.appId,
{ out: './js/firebaseConfig.js' }
);
3番目の引数にファイルの作成先を直接指定しても書き込んでくれます。
.firebaserc
で設定したプロジェクトエイリアスを引数にして、コマンドを叩いてみてください。
$ node scripts/setFirebaseConfig.js default
生成される設定ファイルは、
// Copy and paste this into your JavaScript code to initialize the Firebase SDK.
// You will also need to load the Firebase SDK.
// See https://firebase.google.com/docs/web/setup for more details.
firebase.initializeApp({
"projectId": "project-id",
"appId": "1:000000000000:web:xxxxxxxxxxxxxxxxxx",
"databaseURL": "https://project-id.firebaseio.com",
"storageBucket": "project-id.appspot.com",
"locationId": "location-id",
"apiKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"authDomain": "project-id.firebaseapp.com",
"messagingSenderId": "0000000000000000",
"measurementId": "G-XXXXXXXXXXX"
});
このようなフォーマットになっています。
これをそのままExpoなどで使うには,
import firebase from 'firebase';
import "firebase/firestore";
import "firebase/functions";
global.firebase = firebase;
このようにあらかじめグローバル変数にfirebase
をセットしておけばOKです。
あとは
.gitignore
にjs/firebaseConfig.js
を追加して、
"scripts": {
"fb:config": "node scripts/setFirebaseConfig.js",
"start": "npm run fb:config default && expo start",
"android": "npm run fb:config default && expo start --android",
"ios": "npm run fb:config default && expo start --ios",
"web": "npm run fb:config default && expo start --web",
"eject": "expo eject",
"test": "npm run fb:config test && jest --coverage"
},
package.json
で適宜スクリプトを実行するよう定義しておきます。