僕の考えた最強のfirebase monorepoテンプレートを使って開発スピードと品質を爆上げする

こんにちは。[virapture株式会社](https://virapture.com)でCEOしながら[ラグナロク株式会社](https://ragna-rock.com)でもCKOとして働いている[@mogmet](https://twitter.com/mogmet)です。
![IMG_5519.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/d19c4e69-45a4-0c0f-8e91-1eb46ded46dc.jpeg)
最近Splatoon3にハマっていて、ウデマエがようやくSになりました。よかったら一緒に遊んでください。

本日はtypescript環境での**ぼくのかんがえたさいきょうのfirebase monorepoテンプレート**を作ったので是非みなさんにご活用していただきたく筆を取らせていただきました。
是非使ってみてください。

https://github.com/virapture/firebase-monorepo-template

## 対象ユーザ

本テンプレートは下記に当てはまれば非常に有能な逸品になっております。

- cloud functionsを使う
- firestoreを使う
- webでfirestoreを使う
- typescriptを使う

## 効能

本リポジトリからfirebaseを開発するようにすることで下記4点のメリットを得ることができます。

- clud funtionsとfirestoreのsecurity ruleのunit testを書く環境が整っているため品質を高めた開発が可能
- unit testはgithub actionsを使ったCIで品質を担保している
- develop/mainマージされた時に自動でデプロイされるようになっている
- yarn workspaceを用いることで、cloud functionsとwebで同じentityやロジックを使うことができる

## インストール方法

早速**ぼくのかんがえたさいきょうのfirebase monorepoテンプレート**を自分のプロジェクトに持ってくる方法を紹介します。
（リポジトリにも記載あります。）

[virapture/firebase-monorepo-template](https://github.com/virapture/firebase-monorepo-template)にアクセスた後、「Use this template」を押下して自分のプロジェクトにコピーしてきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/16e9e155-b808-ee61-2b09-d5e731e42123.png)

その後クローンして自分のPCで編集をしてきます。

### ソース修正

IDEなどを使ってリポジトリ名を置換します。

```
virapture/firebase-monorepo-template → your-account/your-repository-name
firebase-monorepo-template → your-repository-name
```

次にfirebaseのproject idを置換します。

```
fir-monorepo-template-dev → your-firebase-dev-project-id
fir-monorepo-template-prd → your-firebase-prod-project-id
```

### リポジトリ設定

次にCI/CDで使うsecretを設定します。

リポジトリの「settings」に移動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/83f656b4-770b-3987-cfbb-88468f65d9bb.png)

SecretsのActionsに移動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/67feceb0-5e24-37ac-f31c-ff896318d26f.png)

New repository secretボタンを押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/cbc820be-5a45-39f4-adf0-9cab05e1af32.png)

Nameに開発環境であれば「GOOGLE_APPLICATION_CREDENTIALS_DEV」、本番環境であれば「GOOGLE_APPLICATION_CREDENTIALS_PROD」を入力します。
SecretにはGoogleの[認証のスタートガイド/サービス アカウントを作成する](https://cloud.google.com/docs/authentication/getting-started#creating_a_service_account)の手順で入手できるjsonファイルの中身を貼り付けます。
その後、「Add Secret」を押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/a0e38df7-923e-0c9b-6c0c-111f14608de7.png)


開発と本番環境２つとも用意しておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/702539bd-2dc8-8c08-06c5-34e0198ad095.png)

### cloud functions setup

cloud functionsでエラーをキャッチして[sentry](https://sentry.io/)に送るようにしています。 sentry用のDSN値を下記コマンドでセットしておきます。

```shell
$ firebase functions:secrets:set SENTRY_DSN
```

### web setup

envディレクトリにあるファイルを使ってwebは初期化を行うようにしています。 dev.env / prod.env とファイルを準備しているのでそれぞれの環境ごとにclient側のfirebaseの値を入力してください。

## 使い方

最初にパッケージをインストールします。

```shell
$ yarn install
```

次に共通パッケージをビルドします。

```shell
$ yarn build:common
```

CloudFunctionsの開発であればemulatorを使ったunit testを実施します。
```shell
$ yarn test:functions 
```

security ruleやwebのunit testは下記で実施できます。

```shell
$ yarn test:functions 
```

## packageの内容

packagesには役割ごとに4つのパッケージが配置されています。
それぞれについて紹介します。

### common

全プロジェクトで共通で使いたいentityやロジックなどを配置します。
テンプレートとしてUser entityを配置しています。

このcommon配下の内容は下記のように別パッケージで呼び出すことができます。

```ts
import { User } from '@firebase-monorepo-template/common'
```

新しいファイルを追加した場合はindex.tsにそのファイルを追記するようにお願いします。

```packages/common/src/index.ts
export * from './entities/user'
```

common配下のソースは編集したら必ず下記コマンドでビルドしてください。でないと他packageで呼び出しができません。

```shell
$ yarn build:common
```

### common-test

テストで使う共通処理を配置しています。
common packageと同様に編集したら`yarn build:common`を実行するの忘れないようにしてください。

よく使うファイルだけ解説しておきます。

#### [testAdminRepository.ts](https://github.com/virapture/firebase-monorepo-template/blob/main/packages/common-test/src/testAdminRepository.ts)
firebase-adminを使った初期化処理をまとめています。
テスト用のUserの初期化など、よく使うと思うのでここに書いたりしています。
cloud functionsでのunit testや、security ruleの初期化処理で使っています。

#### [testClientRepository.ts](https://github.com/virapture/firebase-monorepo-template/blob/main/packages/common-test/src/testClientRepository.ts)
クライアントで初期化したりアクセスしたりするときの処理をまとめています。
security ruleやwebでのunit testで使います。

#### [testProvider.ts](https://github.com/virapture/firebase-monorepo-template/blob/main/packages/common-test/src/testProvider.ts)

testAdminRepositoryとtestClientRepositoryの初期化と、jestでの初期化処理で使う処理をまとめてます。


### functions

cloud functionsを配置します。

unit testはcommon-testのものを使ってテストを行っています。
[jest.setup.ts](https://github.com/virapture/firebase-monorepo-template/blob/main/packages/functions/tests/jest.setup.ts)を全テストでコールしているので初期化処理を省略化しています。

ちなみにデプロイの際にcommonパッケージをデプロイするためにpredeployとして[commonパッケージを圧縮してデプロイ](https://github.com/virapture/firebase-monorepo-template/blob/main/firebase.json#L20-L21)するようにしています。

```firebase.json
        "cd packages/common && yarn pack --filename ../functions/common.tgz",
        "cd packages/functions && yarn add ./common.tgz"
```

デプロイ中はpackage.jsonが少し書き換わるのでコミットしないように気をつけてください。

### web

webプロジェクトを配置します。
reactでもvueでもおけるように素のtypescriptだけ置いてます。
また、[security ruleのテスト](https://github.com/virapture/firebase-monorepo-template/blob/main/packages/web/tests/rules/firestore/user.test.ts)はこのpackageに記載しております。

## まとめ

テンプレートから作るだけでunit testも完備してCI/CDまでできちゃう**ぼくのかんがえたさいきょうのfirebase monorepoテンプレート**ができちゃいました！
ただ、testの書き方はちょっと自我流な感じがあるので、もしこっちの書き方のほうがいんじゃね？！みたいなのがあれば是非PR待ってます！


最後に、[ワンナイト人狼オンライン](https://online.1nite-jinro.com/link/blog)というゲームを作ってます！よかったら遊んでね！

https://online.1nite-jinro.com/link/blog

他にも[Camecon](https://camecon.me/)や[Offcha](https://offcha.com/)、問い合わせ対応が簡単にできる[CSmart](https://csmart.jp/lp)、フリーランスのコミュニティの[NextFreelance](https://next-freelance.net/)といったサービスも作ってるのでよかったら使ってね！

https://camecon.me/

https://offcha.com/

https://csmart.jp/lp

Next Freelanceというフリーランス

また、チームビルディングや技術顧問、Firebaseの設計やアドバイスといったお話も受け付けてますので御用の方は弊社までお問い合わせください。

https://virapture.com/

ラグナロクでもエンジニアやデザイナーのメンバーを募集しています！！楽しくぶち上げたい人はぜひお話ししましょう！！

https://ragna-rock.com