一人十郷 - takuminasuno.com一人十郷
takuminasuno.com
ビジネス
2020/05/27

Firebaseで2個目のWebアプリ開発、Cloud Firestoreベースで本格的に開発挑戦するときの勘所について

前回は『【Webアプリ作成】Firebaseを使ってリアルタイムでデータを可視化する要点【最短ルート】』という記事でFirebaseを使ったWebアプリの作り方をざっと書いてみましたが、勢いに乗って2個目のWebアプリを開発しようとすると、1個目とは少し違った流れをくまないといけない場合があることに気付きました。

また、2個目というと1個目では使わなかった機能に手を出そうとしてそこでも別のエラーが・・・ということは往々にしてあるわけで、今回はデータベースにはRealtime DatabaseではなくCloud Firestoreを選び、Cloud Functionsの言語はJavaScriptではなくTypeScriptを選び、また比較的長期的な開発を見込んで本番環境と開発環境を分けて作ることにしたため、備忘録がてら作業の流れと注意点をメモすることにしました。

 

それでは本題に入ります。

1.最初にフォルダ整理

前回と同様にまずは新規プロジェクトの作成を・・・となりそうですが、ここで踏みとどまって、まずはローカルにあるホスティング用のFirebaseフォルダを確認してみます。

初めてアプリを作ったときに(私のように)特に深く考えていなければ、Firebaseフォルダ(=『firebase init』コマンドを実行したフォルダ)は固有アプリ用のパスというよりはFirebase共通のパスになっているかもしれません。その場合、複数のアプリを並行して管理することが難しいため、フォルダ構造を少し書き換えます。

before C:\USERS\{USERNAME}┗Firebase

┗1個目のアプリファイル群

after C:\USERS\{USERNAME}┗Firebase

┗{1st_app_name}

┗1個目のアプリファイル群

┗{2nd_app_name}

┗2個目のアプリファイル群

 

2.初回に倣ってデプロイ編

フォルダの整理をした後は、1回目と同じ作業に・・・と言いたいところですが、今回はCloud FirestoreとStorageを利用するので、アプリ追加時にエラーが起きないように、前回にはない作業①~②を先に実行します。

作業①:左タブの『Database』を押してCloud Firestoreのページを開き、『データベースの作成』ボタンを押して作業に入ります。データベースの作成は初期設定のままでもよいですが、Cloud Firestoreのロケーションは利用地に近い方がよいので、初期設定の『nam5(us-central)』から東京である『asia-northeast1』に変更します。

作業②:左タブの『Storage』を押して『始める』ボタンを押して、初期設定のままで『完了』ボタンを押すと、デフォルトバケットが設定されて完了します。

 

ということで作業①~②が完了したら、1回目のときの作業をなぞるように進んでいきます。

  1. ウェブアプリにFirebaseを追加します。『①アプリの登録』から『②Firebase SDKの追加』までは初回と同じですが、『③Firebase CLIのインストール』は初回時にインストール済みなので必要ありません。『④Firebase Hostingへのデプロイ』では、先ほど作成した2個目のアプリフォルダにて『firebase login』コマンドからの『firebase init』コマンドを実行して初期設定ファイルを自動設置します。初期設定は基本的には初回と同じ設定ですが、Cloud Functionsは冒頭で書いたようにTypeScriptにします。
  2. 続いて『firebase deploy』コマンドにてデプロイしようとするわけですが、今回のようにCloud FunctionsをTypeScriptにしていると、

    src/index.ts:1:1 - error TS6133: 'functions' is declared but its value is never read.

    というエラーが発生します。初期設定のままなのになぜ・・・と思ってしまうところですが、Cloud Functionsを書いていない状態(作ったばかりだから当然)なのに読み込もうとするのが初期設定になっているらしく、早速チェック機能でエラーを吐いているようです。取り急ぎは当該ファイルの1行目にある

    import * as functions from 'firebase-functions';

    をコメントアウトしてからデプロイすると、そのままスムーズに進み、
    https://{YOUR_PROJECT_ID}.firebaseapp.com
    https://{YOUR_PROJECT_ID}.web.app
    どちらのURLからでもデフォルトページが確認できるようになります。これにて『2.初回に倣ってデプロイ編』は完了です。懐かしのデフォルトページが閲覧できました。

 

懐かしのデフォルトページ

 

しかし残念ながら、今回は明示的にエラーが出たので気付いてしまいました。Cloud FunctionsでTypeScriptを選んだときに宛がわれる静的コード解析ツール(リントツール)はTSLintなのですが、TSLintは2019年中に非推奨になることが決まっている古いツールなのですよね。まだまだ現役とは言っても、何とも言い難い気持ちに・・・

天下のGoogle謹製のFirebaseなのに何故対応が遅いのか・・・と嘆いてもしょうがないので、ESLintを個別に手動インストールすることにしました。

なお、TSLintが入っている状態からの作業は面倒なので、TSLintなしで再インストールした段階からの再開ということで次章に移ります。

 

3.ESLintの手動インストール

ということで、FirebaseにESLintを手動インストールしてみます。

(Firebase、楽々環境構築のはずだったのに細かいことを気にしようとすると、やっぱり手間がかかるようです。むむむ・・・という感じです。。)

  1. まず、コマンドラインで『functions』フォルダに移動し、以下のコマンドを実行してESLint関連のモジュールを追加します。設定はrecommended頼みでいきたいので、prettierももちろん使います。
  2. 続いて、ESLintの設定ファイルである『.eslintrc.json』を『functions』フォルダ直下に作ります。色々鑑みた結果、以下のようなスクリプトにしました。
  3. 続いて『functions』フォルダ直下にあるパッケージ設定自身である『package.json』を開き、"scripts"のところにLint設定とLint:fix設定を追加します。
  4. 続いてFirebaseフォルダ直下にある『firebase.json』ファイルを開き、"functions"の"predeloy"のところにLint設定を追加します。

 

これにてESLintの設定が完了です。

ESLintは個別設定をしだすとキリがないというか沼に嵌ってしまいそうなのでrecommended頼みの姿勢を全面に押し出したつもりですが、「そうはいってもprettierは必須だよなあ」とか「envやparseOptionsはそれなりに設定しないとなあ」とか悩み始めて難しさの一端を感じたところで最後のステップに移ります。

 

4.開発環境の構築

さて、これだけでも十分に2個目のアプリを作ることはできるのですが、比較的長期的な開発を見込んで本番環境と開発環境を分けて作ることにします。環境構築のイメージはこちらの通りです。

要は、「Firebaseのプロジェクトを2つ作って片方を本番環境、もう片方を開発環境として用意し、『.firebaserc』ファイル上で両方のプロジェクトを定義すると、コマンドラインでどちらの環境にデプロイするかを切り替えることができる」というのがFirebaseの開発環境の考え方です。

 

具体的な作業としてはシンプルに、

  1. まずは開発環境用にFirebaseプロジェクトを作ります。設定は本番環境と全て同じとします。
  2. Firebaseフォルダ直下にある『.firebaserc』ファイルを開くと、初期設定のままであれば"projects"配下に"default"キーと紐づいて本番環境のプロジェクトIDが書いてあります。そこに本番環境として"production"キーに対して本番環境のプロジェクトID、"development"キーに対して開発環境のプロジェクトIDをセットして保存します。これで準備は完了です。
  3. コマンドラインで『firebase use development』コマンドを打つとデプロイ先が開発環境に切り替わり、続いて『firebase deploy』コマンドを打つと開発環境にデプロイされます。同様に『firebase use production』コマンドを打つと本番環境に切り替わり、本番環境にデプロイできるようになります。

もしステージング環境も作りたい場合は、ステージング環境用のプロジェクトを作り、"staging"キーに対してプロジェクトIDをセットすれば対応可能です。

開発環境の構築は、ESLintの対応と比べると作業が段違いにシンプルで良かったです。

 

5.Cloud Firestoreによるデータ処理実装

準備ができたので、いざ開発に入ります。

今回は初回と違ってCloud Firestoreを使うので、Cloud Firestoreの準備の流れを確認しつつ、データ処理の基本をCRUDごとに確認します。

 

Create(新規作成)

シンプルな1本のツリーだったRealtime Databaseと比較すると、コレクションの単位がツリーの単位という感じで複数のツリーが存在できるイメージで、コレクション配下にぶら下げる複数の枝としてドキュメントが存在するイメージです。

Realtime Databaseと同じでNoSQL形式(多重連想配列チック)なので、ドキュメントには常に固有のIDと値がセットされます。連想配列としてIDを意識したい場合はIDを明示的に設定すると良いですし、そうでなくただの配列として扱いたい場合はIDを明示せずランダムに任せてドキュメント追加すればよいと思います。

 

Read(参照)

基本の型としては、

①1つのドキュメントを取得するか/全てのドキュメントを(コレクションごと)取得するか

②1度だけ取得するか/リアルタイムアップデート(リッスン)するか

の2軸で変わってくるイメージです。特に②については、『.get().then』,『.onSnapchat』と関数レベルで変わってくるので、ここは明確に使い分けられるようにしたいところです。コレクションとドキュメントの階層構造を理解すれば、Realtime Databaseとさほど変わらない印象です。なお、他にもリッスンの場合には変更種別(added/modified/removed)ごとの取得などのテクニカルな実装もありますが、ここでは割愛します。

 

Update(更新)

シンプルに全上書きする場合は『set』でよいですが、キー単位で更新したい場合は『update』を使います。

 

Delete(削除)

ウェブクライアントからは、コレクションの削除や複数ドキュメントの一括削除はできず、ID指定で1個ずつ消すだけとなっています。クライアント側からの処理はセキュリティリスクが高いので、まあしょうがないところだと思います。どうしても無理矢理やらないといけない場合は、ドキュメントをループして1個1個IDを取得して削除処理を繰り返す方法を覚えておきます。

 

ということでCRUDごとに主要な処理を確認してみました。Cloud Firestoreは他にもQueryやOrderByやSubCollectionなどの機能があったり言語ごとに使える機能(や表記)が変わっていたりなどするので、詳しくは公式のドキュメントを参照しましょう。

 

まとめ

ということで、このあたりのデータ基本操作を理解しておけば、Cloud Firestoreを使った最低限のウェブアプリを実装できると思います。

ただ、最低限と言うのは、これだけだとセキュアなデータ処理には程遠い状態だからです。

クライアントサイドで動くJavaScript頼みのデータ処理は対策なしだとセキュリティホールだらけになるので、『firestore.rules』の適切な設定が必要です。また、重たいデータ処理や多彩なトリガーを実装する場合はサーバーサイドで動く『Cloud Functions』が適切かもかもしれません。また、実際にデータ構造を考えるときに、NoSQLならではの処理しやすい設計を考えるのが大きな課題です。あと、デザインを整えるうえでは適切なフレームワークの導入と選定が求められるケースが多いでしょう。

さくっとアプリが作れそうなFirebaseでも、ちゃんと作ろうとすると色々と考えないといけないというのは同じなのだなという印象でした。

同じカテゴリーの投稿もどうぞ!
ConoHaのVPSを使うこのブログが突如使えなくなった後に復旧した話
ビジネス
2021/07/04
ConoHaのVPSを使うこのブログが突如使えなくなった後に復旧した話
業務のためにSaaSを選定するテックリサーチの思考の流れを言語化してみた
ビジネス
2021/05/01
業務のためにSaaSを選定するテックリサーチの思考の流れを言語化してみた
Pythonによるデータ処理の基本まとめ【pandas, json, datetime, gzipなど】
ビジネス
2021/04/11
Pythonによるデータ処理の基本まとめ【pandas, json, datetime, gzipなど】
アジャイルとスクラムについて、原理原則と基本を押さえる【2020年12月版】
ビジネス
2020/12/10
アジャイルとスクラムについて、原理原則と基本を押さえる【2020年12月版】
IT&マーケティング界隈でプロジェクトマネージャーとして生き残るためのサバイバルハック【2020年9月版】
ビジネス
2020/09/16
IT&マーケティング界隈でプロジェクトマネージャーとして生き残るためのサバイバルハック【2020年9月版】
ブログ著者について
那須野 拓実(なすの たくみ)。たなぐら応援大使(福島県棚倉町)。トリプレッソを勝手に応援する人。ネイチャーフォト中心の多言語ブログを書いてます。本業はIT&マーケティング界隈でナレッジマネジメントとかデータ分析とかの何でも屋。半年間の育休明けで、家事育児と外働きのバランスを模索中。