LoginSignup
3
10

More than 1 year has passed since last update.

Firebase+Vue.js 覚書

Last updated at Posted at 2019-03-06

まえがき

"テイキョウドットコム"の裏側のCMSをFirebaseで作った話.
しばらくフレームワークとしてNuxt.jsを使っていたものの,lang="ts"にしようとしていろいろ躓いたりして面倒だったので,流行り(?)の@vue/cliに全部任せることにした.もうSSRはいいかな.
でもクライアントもサーバ(Firebase Functions)もTypeScriptで書けたらいいじゃん.良いじゃん(断定)

そのうちNuxt.js+TypeScriptちゃんと研究しよ.
Nuxt.jsすき.

Firebase

まずfirebase-toolsで

~/
$ firebase init

今回はHosting, Functions, Firestore, Authenticationを使う

ディレクトリ構造はこう

~/
|- functions/ --- Functionsのコード
| |- src/ --- .tsファイル群
| |- lib/ --- コンパイル済み.jsファイル群
| |- package.json
| ...
|- src/ --- クライアント側のコード
| |- common/
| |- site_name/ --- vue cliで作るディレクトリ
| | |- package.json
| | ...
| `- site_name_2/ --- vue cliで作るディレクトリ
| |- package.json
| ...
|- public/ --- クライアント側ビルド済みファイル
| |- site_name/
| `- site_name_2/
|- .firebaserc
|- firebase.json
|- package.json
 ...

Hosting

表側と裏側の2サイトを用意するので従量プランにアップグレード.
その上で"複数のサイトでプロジェクトのリソースを共有する"の通りに,Hostingサイトと~/public/site_nameを関連付ける.
また,SPAの場合すべてのURLリクエストをindex.htmlに飛ばす必要がある."Hosting 動作をカスタマイズする"の"リライト"の項など参考に各target毎に設定を行う.
こんな感じ.

firebase.json
 "hosting": [ {
 "target": "target_name",
 "public": "public/site_name",
 "rewrites": [ {
 "source": "**",
 "destination": "/index.html"
 } ]
 } ],

vue cliの項に続く.

Authentication

方式はとりあえずメール+パスワード認証にした.あとでGoogleアカウントにしよ.
Firebase Consoleからユーザを作成(CMSを利用するのは限定人数なので)
実際に使えるメールアドレスと,仮の適当なパスワードで作る.
パスワード再設定用メール送信で実際のパスワードを設定させると同時にメール認証が完了する.

Firestore

Firebase Consoleから作成しておく.ロックモードでよい.
Firestoreのreadは全員許可,writeを前項で作ったユーザのみに限定する.
ルールを以下のようにする.uidはユーザを作った時に発行されるやつ.
複数許可したり,emailで絞ることもできる.詳しくはドキュメント参照されたし.

~/firestore.rules
...
allow read;
allow write:
 if request.auth.token.email_verified
 && request.auth.uid in [
 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX',
 'YYYYYYYYYYYYYYYYYYYYYYYYYYYY'
 ];
...

複数fieldを使ったソートのクエリを使う必要があったので,indexを作成しておく.

Functions

functionいっぱい作ってREST APIみたいにするとそれぞれのfunctionの起動に時間がかかるっぽいので、1つのfunctionにexpressを載せる構成にした。
expressのようなFunctionsだけの依存ライブラリは~/functions/package.jsonにインストールしよう.

Vue

~/src
$ vue create site_name

TypeScriptを使う設定にした.その他お好み.
これをサイト数ぶん作る.
pugを使う場合は追加で

~/src/site_name
$ npm i -D pug pug-plain-loader

Firebase Consoleのoverviewにある"アプリにFirebaseを追加して利用を開始しましょう"から,initializaAppするために必要な値を確認し,.envを以下のように設定.
.envの仕様の詳細はドキュメント参照されたし

~/src/site_name/.env.production
VUE_APP_FIREBASE_FUNCTIONS_URL=https://region-name-project-id.cloudfunctions.net/
VUE_APP_FIREBASE_API_KEY=xxx
VUE_APP_FIREBASE_AUTH_DOMAIN=project-id.firebaseapp.com
VUE_APP_FIREBASE_DATABASE_URL=https://project-id.firebaseio.com
VUE_APP_FIREBASE_PROJECT_ID=project-id
VUE_APP_FIREBASE_STORAGE_BUCKET=project-id.appspot.com
VUE_APP_FIREBASE_MESSAGING_SENDER_ID=xxx
...
~/src/site_name/.env.development
VUE_APP_FIREBASE_FUNCTIONS_URL=http://localhost:5001/project-id/us-central1/
おなじ
...

$ firebase serveでローカルで動かすとき,Firestoreだけはローカルで立たないので,.env.developmentでは予め用意したstaging用のFirebaseプロジェクトを使うようにすると◎.(その場合Firestoreだけ使うのでstaging用プロジェクトの料金プランアップグレードは不要)
.envで設定したもののうちVUE_APP_で始まるものは以下のようにクライアントサイドのコードで呼び出せるのでそうなっている.
headのmetaでcanonical urlが欲しいときはVUE_APP_PUBLIC_PATHなど設定しておくと◎.
そして最後にこう

firebase.ts
const config = {
 apiKey: process.env.VUE_APP_FIREBASE_API_KEY,
 authDomain: process.env.VUE_APP_FIREBASE_AUTH_DOMAIN,
 databaseURL: process.env.VUE_APP_FIREBASE_DATABASE_URL,
 projectId: process.env.VUE_APP_FIREBASE_PROJECT_ID,
 storageBucket: process.env.VUE_APP_FIREBASE_STORAGE_BUCKET,
 messagingSenderId: process.env.VUE_APP_FIREBASE_MESSAGING_SENDER_ID,
};
firebase.initializeApp(config);
axios.ts
import axios from 'axios';
export default axios.create({
 baseURL: process.env.VUE_APP_FIREBASE_FUNCTIONS_URL,
});

Build, Serve, Deploy

npm scriptだけ列挙する

~/functions/package.json
 "build": "tsc",
 "watch": "tsc -w",
~/src/site_name/package.json
 "build": "vue-cli-service build --dest=../../public/site_name --mode=development",
 "watch": "vue-cli-service build --dest=../../public/site_name --mode=development --watch",
 "prod": "vue-cli-service build --dest=../../public/site_name --mode=production",
~/package.json
 "build": "run-s build:*",
 "build:functions": "npm --prefix=functions run build",
 "build:site_name": "npm --prefix=src/site_name run build",
 "build:site_name_2": "npm --prefix=src/site_name_2 run build",
 "serve": "firebase serve --project project-id-staging",
 "prod:site_name": "npm --prefix=src/site_name run prod",
 "prod:site_name_2": "npm --prefix=src/site_name_2 run prod",
 "predeploy": "run-s clean prod:*",
 "deploy": "firebase deploy --project project-id",
 "clean": "rm -r public || true",

開発中はnpm run watchを各package.jsonの位置で実行する.またはルートでnpm run build
その後ルートでnpm run serveでFirebase Hostingがローカルで動く.
npm run deployで全部productionビルドしてデプロイする.Functionsはfirebase-toolsが勝手にビルドします.
npm run deploy -- --only functionsとかも可能.詳しくはfirebase-toolsのドキュメント参照されたし
run-snpm-run-allパッケージ

蛇足

alias vs symlink

複数サイト間やVue・Functions間でinterfaceの定義を共有したかったりする.
tsconfig.jsonのpathsで"@common/*": ["../../comon/*"]とするか,
シンボリックリンクln -s ../../common ./commonとするか,
どっちがいいんだろうか?
どちらにせよ実体がtsconfig.jsonやtslint.json/eslint.jsonの外側ディレクトリにあるので,
lintはかからないしwatchしてくれない・・・?

VSCode

プロジェクトルートから見てtsconfigが複数あるので,paths解決やインテリセンス等々を上手にやってくれない.
tsconfigの位置毎にVSCodeを複窓して書いてるけどめんどくさいぞ!
いい方法教えてください.

type safeなstore

Vuex+TypeScript問題に足突っ込む

3
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
10