まだ全然最強感がないけど、やり始めたら1日過ぎたのでまとめる。
% tree -L 2 -I node_modules functions functions ├── index.js # メインのやつ ├── package-lock.json ├── package.json ├── src │ ├── blog-rss-to-json.js # 呼び出すやつ │ ├── globals.js # グローバル変数のやつ │ ├── libs.js # 共有で使う関数とか │ ├── not-found.js # 呼び出すやつ │ ├── reply-postcard-to-yagish.js # 呼び出すやつ │ ├── send-postcard-to-chat.js # 呼び出すやつ │ └── update-omikuji-statistics.js # 呼び出すやつ └── yarn.lock
1関数1ファイルに分割
この記事に詳しく書いたけど1関数1ファイルに分割する。
一覧のオブジェクトを見れば、どんな名前でどの関数を読んでるか分かるようになる。
index.js
const funcs = { blogRssToJson: './src/blog-rss-to-json', sendPostCard2Chat: './src/send-postcard-to-chat', replyPostCard2Yagish: './src/reply-postcard-to-yagish', notFound: './src/not-found', updateOmikujiStatistics: './src/update-omikuji-statistics' } const loadFunctions = (funcsObj) => { for(let name in funcsObj){ if(! process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === name) { exports[name] = require(funcsObj[name]) } } } loadFunctions(funcs)
とりあえずindex.js以外のjsファイルはsrc以下にぶちこんでる。
関数のファイルと後述のglobalsとかlibs的なファイルは増えてきたら別に分けた方がいいかもしれない。
これでindex.jsがめっちゃ長くなったり、無駄なモジュールを読み込むことが減る・・はず。
環境変数は.env的なファイルにする
firebase functionの環境変数の扱いはちょっと変わってる。
process.envではなく、funtions.config()を使えとなってる。
呼び出しは
funtions.config().foo.bar
みたいな感じでいいとしても、セットがめんどい。
デプロイする前に、以下の slack.url 環境構成変数を設定します。
firebase functions:config:set slack.url=https://hooks.slack.com/services/XXX
CLIのコマンドでセットしないといけない。
JSONファイルも読ませられるけど、トップレベルのキーは指定しなきゃいけないので、1ファイルにすべてとまとめるのができない。
qiita.com
そのため環境ごとに下記のようなファイルを作り、デプロイのシェルスクリプトに追加することにした。
よくある.env.*にしなかったのは、コマンドがconfigだから。
.config.production
chat.webhook_url=https://chat.googleapis.com/v1/spaces/YAGIYAGIYAGIYAGISH site.id=yagish_production blog.rss_url=https://blog.yagish.jp/rss blog.access_control_allow_origin= https://rirekisho.yagish.jp
そのままcatしただけだと改行が値に入ってしまうので、 tr "\n\r" " "をいれて改行をスペースに変換する
(Windowsで書いたから改行がCRLFになってたのが原因、LFだったら大丈夫)
値を""で囲いたかったけど、どうしてもエスケープされて入ってしまうので諦めた
(printfとかcat、echoのオプションとか2時間ぐらい闘った)
もっとbashを理解したい
firebase functions:config:set `cat ./app/functions/.config.production| tr "\n\r" " "`
セットしたらちゃんとできてるか確認した方がいい。
firebase functions:config:get
実際のdeploy.shはこんな感じ(一部抜粋)
全部Dockerコンテナ内でやっているのでこんなになってしまう。一つのexecで&で繋げてもいいかな
sudo docker exec \ ${CONTAINER_ID} \ yarn build-production sudo docker exec \ ${CONTAINER_ID} \ firebase -P ${PROJECT_ID} functions:config:set `cat ./app/functions/.config.production| tr "\n\r" " "` sudo docker exec \ ${CONTAINER_ID} \ firebase -P ${PROJECT_ID} functions:config:get sudo docker exec \ ${CONTAINER_ID} \ firebase deploy -P ${PROJECT_ID} -p dist-production
よく使う大きいオブジェクトはglobal変数にぶち込んで再利用&遅延評価
詳しくはここを参照
ヒントとアドバイス | Firebase
とりえあずよく使う大きいオブジェクトは、firebase-admin、firestoreのオブジェクトなのでこれをglobal化しておく。
ほぼ絶対使うfirebase-functionsもglobalにいれるけど、絶対使うので遅延評価はしない。
./src/globals.js
global.functions = require('firebase-functions') global.admin = null global.adminInit = function () { console.log('adminInit') global.admin = require('firebase-admin') global.admin.initializeApp() return global.admin } global.firestore = null global.firestoreInit = function () { console.log('firestoreInit') const admin = global.admin || global.adminInit() global.firestore = admin.firestore() global.firestore.settings({ timestampsInSnapshots: true }) return global.firestore }
とりえあず変数名+Initという命名規則で読み込む関数を作る。
冗長で最強感ない。
これをindex.jsの冒頭で読ませておく
index.js
require('./src/globals') // 省略
あとそれぞれファイルの冒頭に使うものを書いておく。
久しぶりにグローバル変数使った(WordPressぶり?)けど、改めて「こいつどこから来たんだ?」感が半端ないので、明示するという意味もある。
グローバル変数なのでglobalをつけずにも呼べるんだけど、あえてglobalを付けて使ってる。
ちなみにnodeのglobalオブジェクトは今回知った。
globalsにglobalオブジェクトがあるのでglobalも当然globalなオブジェクトなんだね(不明)。
global.firestore = global.firestore || global.firestoreInit() global.admin = global.admin || global.adminInit()
関数の数も実行回数も少ないので、圧倒的に早すぎる最適化感がある。
今後問題を感じたら都度改善して最強を目指すか、もっといいのを見つけたらそっちにしようと思う。