Vue.js とCloud Functions for Firebase をFirebase Hostingへデプロイするための環境構築手順


前置き

Qiitaに Vue.jsFirebaseCloud Functions for Firebase などの記事を書いてて、ツールのセットアップや環境構築を都度継ぎ足してきたのですが、一度に構築する方法が整理できてなかったので、メモっておきます。

本記事で説明が足りないところは、適宜下記の記事を見ていただくとよいかもしれません。


コレをやったらできること


  • Vue.jsのコマンドラインツールとFirebaseのコマンドラインツールがインストールできます

  • Vue.jsのプロジェクトをローカルのWEBサーバで動かせます(npm run dev 上で)

  • Vue.jsのプロジェクトをFirebaseのローカルWEBサーバで動かせます

  • Cloud FunctionsをFirebaseのローカルWEBサーバで動かせます

  • Vue.jsのプロジェクトをFirebase Hostingにデプロイできます

  • Cloud FunctionsをFirebaseへデプロイできます

  • Cloud FunctionsをHostingのドメインで呼び出す事ができます


前提環境

$ sw_vers

ProductName: Mac OS X
ProductVersion: 10.14.3
BuildVersion: 18D42

$ node --version
v10.14.2 <-ホントはFunctionsとかのバージョンに合わせるべきなんだけどいったん気にしない :-)


準備

コマンドラインツール達のインストールと、Firebaseへのログインなど。あ、Firebaseはサインアップ済みってことで、、、。


vue コマンドラインツールのインストール

vue-cli というVue.jsのテンプレを生成してくれるコマンドラインツールをインストールします。

$ npm install -g vue-cli

$ source ~/.bash_profile
$ vue --version
2.9.6

よさそうですね。


firebase-toolsのインストール

firebaseのコマンドラインツール。

$ npm install -g firebase-tools

$ source ~/.bash_profile
$ firebase --version
6.3.0


Firebaseにログイン

$ firebase login

? Allow Firebase to collect anonymous CLI usage and error reporting information?
No

Visit this URL on any device to log in:
https://accounts.google.com/o/oauth2/auth?client_id=... // OAuthでアクセスの認可まち

Waiting for authentication...

✔ Success! Logged in as masatomix@example.com


やってみる


まずは プロジェクト全体の作成

メインとなるプロジェクトは Vue.jsのコマンドラインツールで作成します。

$ vue init webpack fb_vue_template

↓とりあえずすべて Yes

? Project name fb_vue_template
? Project description A Vue.js project
? Author Masatomi KINO <kino@example.com>
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests Yes
? Pick a test runner jest
? Setup e2e tests with Nightwatch? Yes
? Should we run `npm install` for you after the project has been created? (recom
mended) npm

vue-cli · Generated "fb_vue_template".

# Installing project dependencies ...
# ========================
...

# Project initialization finished!
# ========================

To get started:

cd fb_vue_template
npm run dev

Documentation can be found at https://vuejs-templates.github.io/webpack

完了しました。


Vue.jsの Hello World を表示

最後にcd fb_vue_template,npm run dev とでてましたので、その通りに。。

$ cd fb_vue_template

$ npm run dev
...
DONE Compiled successfully in 7650ms 15:42:24

I Your application is running here: http://localhost:8080

さて、メッセージ通りにブラウザで http://localhost:8080 をひらいてみます。

image.png

よさそうですね。。問題なければ、プロンプトは Ctrl-c で終了ておきましょう。


Firebase関連情報を設定

さて Firebase関連です。


Firebase Hosting設定

まずはこの Vue.js プロジェクトをサーバへデプロイするためのHosting設定を行います。

$ pwd

/xxx/xxxx/fb_vue_template
$ firebase init hosting

######## #### ######## ######## ######## ### ###### ########
## ## ## ## ## ## ## ## ## ## ##
###### ## ######## ###### ######## ######### ###### ######
## ## ## ## ## ## ## ## ## ## ##
## #### ## ## ######## ######## ## ## ###### ########

You're about to initialize a Firebase project in this directory:

/xxx/xxxx/fb_vue_template

=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add,
but for now we'll just set up a default project.

? Select a default Firebase project for this directory: hoge-xxxx (hoge)
i Using project hoge-xxxx (hoge)

↑ デプロイしたい先のプロジェクトを選びます

=== Hosting Setup

Your public directory is the folder (relative to your project directory) that
will contain Hosting assets to be uploaded with firebase deploy. If you
have a build process for your assets, use your build's output directory.

? What do you want to use as your public directory? dist

↑ public?って聞いてきますが、vue.jsのプロジェクトが出力する先「dist」を選択します。

? Configure as a single-page app (rewrite all urls to /index.html)? Yes
✔ Wrote dist/index.html

SPAで作成するので、Yesを選択します。
サーバにデプロイした際、どのURLを叩いてもindex.html を表示するよっていう設定になります。

i Writing configuration info to firebase.json...
i Writing project information to .firebaserc...

✔ Firebase initialization complete!
$

$ cat firebase.json
{
"hosting": {
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
# サーバにデプロイした際、どのURLを叩いてもindex.html を
# 表示するよっていう設定。
}
]
}
}
$

サーバにデプロイするための設定が追加されました。


Cloud Functions 設定

つづいてバックエンド機能となる、Cloud Functions の設定を行います。

$ pwd

/xxx/xxxx/fb_vue_template
$ firebase init functions

######## #### ######## ######## ######## ### ###### ########
## ## ## ## ## ## ## ## ## ## ##
###### ## ######## ###### ######## ######### ###### ######
## ## ## ## ## ## ## ## ## ## ##
## #### ## ## ######## ######## ## ## ###### ########

You're about to initialize a Firebase project in this directory:
/xxx/xxxx/fb_vue_template
=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add,
but for now we'll just set up a default project.

? Select a default Firebase project for this directory: hoge-xxxx (hoge) ← 使用するプロジェクト選択
? What language would you like to use to write Cloud Functions? TypeScript ← TypeScriptをえらんでみた
? Do you want to use TSLint to catch probable bugs and enforce style? Yes ← Yesをえらぶ
? Do you want to install dependencies with npm now? Yes

✔ Firebase initialization complete!
$

$ cat firebase.json

{
"hosting": {
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
},
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint",
"npm --prefix \"$RESOURCE_DIR\" run build"
]
}
}

Functionsの設定が追加されましたね。よさそうです。

最終的に、ディレクトリ構成は以下のようになりました。

$ tree -a

.
├── README.md
├── firebase.json
├── index.html
├── package-lock.json
├── package.json
├── src
│   ├── App.vue
│   ├── components
│   │   └── HelloWorld.vue
│   ├── main.js
│   └── router
│   └── index.js
├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .firebaserc
├── .gitignore
├── .postcssrc.js

├── functions
│   ├── .gitignore
│   ├── package-lock.json
│   ├── package.json
│   ├── src
│   │   └── index.ts
│   ├── tsconfig.json
│   └── tslint.json
├── build
│   └── 割愛
├── config
│   ├── dev.env.js
│   ├── index.js
│   ├── prod.env.js
│   └── test.env.js
├── static
│   └── .gitkeep
└── test
├── e2e
│   └── 割愛
└── unit
└── 割愛
(適度に整形)


ビルド

初回のセットアップである程度ビルドや 外部ライブラリのインストールなどは済んでるんですが、一応 ライブラリのインストールとビルドまでの手順を書きます。


Firebase Hosting 側

$ pwd

/xxx/xxxx/fb_vue_template
$ npm install ← こちらは外部ライブラリを再度入れるときだけ実施
$ npm run build ← こちらはVue.js側のコードをいじったら毎回実施
$ ls -lrt dist
total 8
-rw-r--r-- 1 xx staff 517 3 5 13:34 index.html
drwxr-xr-x 4 xx staff 128 3 5 13:34 static

distディレクトリに ビルドされたファイル群ができました。


Cloud Functions 側

$ pwd

/xxx/xxxx/fb_vue_template
$ cd functions

ビルドするとき、プロジェクト初期状態の index.ts だと、関数がないためにエラーとなってしまうので、下記の通りコメントを外しておきます。

$ cat src/index.ts

import * as functions from 'firebase-functions';

// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
export const helloWorld = functions.https.onRequest((request, response) => {
response.send("Hello from Firebase!");
});

$ npm install ← こちらは外部ライブラリを再度入れるときだけ実施
$ npm run build ← こちらはfunctionsのtsコードをいじったら毎回実施
$ ls -lrt lib/
total 16
-rw-r--r-- 1 xxx staff 296 3 5 13:39 index.js.map
-rw-r--r-- 1 xxx staff 380 3 5 13:39 index.js
$
$ cd ../

こちらは「lib」のディレクトリに ビルドされたファイル群ができました。


ローカルのWEBサーバ起動

以下のコマンドで、ローカルのWEBサーバ上で起動します。

$ pwd

/xxx/xxxx/fb_vue_template
$ firebase serve --only hosting,functions

=== Serving from '/xxx/xxxx/fb_vue_template'...

i functions: Preparing to emulate functions.
i hosting: Serving hosting files from: dist
✔ hosting: Local server: http://localhost:5000
Warning: You're using Node.js v10.14.2 but Google Cloud Functions only supports v6.11.5.
✔ functions: helloWorld: http://localhost:5001/hoge-xxxx/us-central1/helloWorld

ブラウザで、http://localhost:5000 へアクセスすると、先ほどのVue.jsの画面が表示されると思います。またcurlで curl http://localhost:5001/hoge-xxxx/us-central1/helloWorld とアクセスしてfunctionsを呼び出してみましょう。

$ curl http://localhost:5001/hoge-xxxx/us-central1/helloWorld

Hello from Firebase!
$

OKそうですね。。Ctrl-c で終了しておきましょう


Functionsの関数達を Hosting のドメイン経由で処理できるようにする

サーバにデプロイしたときのFirebase Hostingのドメイン(URL)と、Cloud Functions が使用するドメインは異なっています。具体的には、

Firebase Hosting: https://hoge-xxxx.firebaseapp.com/

Cloud Functions: https://us-central1-hoge-xxxx.cloudfunctions.net/

とかになったりします。HostingしたWEBアプリからCloud Functions の関数を呼び出すときにドメインが異なっていると、CORSの考慮やURLをフルパス指定しないといけないなど何かとメンドウなので、HostingのURLでアクセス出来るようHostingのリバースプロキシを有効にします。

具体的には以下の通り firebase.json に設定を追加します。


firebase.json

{

"hosting": {
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "/hello", # /hello にきたら、
"function": "helloWorld" #functionsの helloWorld 関数へ転送
},
{
"source": "**",
"destination": "/index.html"
}
]
},
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint",
"npm --prefix \"$RESOURCE_DIR\" run build"
]
}
}

rewrites にリバースプロキシの設定を追加しました。 "source":"**" の設定よりも先に書いてるのがポイントです(後に書くと、**が優先されちゃう)。

さて、ローカルのWEBサーバをもいちど起動します。

$ firebase serve --only hosting,functions

疎通します。

$ curl  http://localhost:5000/hello

Hello from Firebase
$

これでHostingとCloud Functionsがおなじドメインとなりました。

"source": "/hello" の箇所は "source": "/hello/**" などとかけるので、必要なパラメタに応じて適宜工夫するのがよさそうです。


サーバにデプロイする

ココまでできていれば、サーバへのデプロイも簡単です

$ pwd

/xxx/xxxx/fb_vue_template
$ firebase deploy --only hosting,functions

... 割愛

✔ functions[helloWorld(us-central1)]: Successful create operation.
Function URL (helloWorld): https://us-central1-hoge-xxxx.cloudfunctions.net/helloWorld
i hosting[hoge-xxxx]: finalizing version...
✔ hosting[hoge-xxxx]: version finalized
i hosting[hoge-xxxx]: releasing new version...
✔ hosting[hoge-xxxx]: release complete

✔ Deploy complete!

Please note that it can take up to 30 seconds for your updated functions to propagate.
Project Console: https://console.firebase.google.com/project/hoge-xxxx/overview
Hosting URL: https://hoge-xxxx.firebaseapp.com
$

表示されたサーバに アクセスしてみましょう。

ブラウザで: https://hoge-xxxx.firebaseapp.com

curlで: https://us-central1-hoge-xxxx.cloudfunctions.net/helloWorld

curlで: https://hoge-xxxx.firebaseapp.com/hello

いままでおなじ結果が得られればOKです。


ビルド手順まとめ

$ pwd

/xxx/xxxx/fb_vue_template

プロジェクトがココに展開されている想定で、コマンドを整理しておきます。


Hosting側(Vue.jsのWEBアプリ)

ビルド

$ cd /xxx/xxxx/fb_vue_template

$ npm run build

ローカルWEBサーバ起動(事前にビルド要)

$ cd /xxx/xxxx/fb_vue_template

$ firebase serve --only hosting
カンマ区切りで、functionsもならべられる

デプロイ(事前にビルド要)

$ cd /xxx/xxxx/fb_vue_template

$ firebase deploy --only hosting
カンマ区切りで、functionsもならべられる


Cloud Functions

ビルド

$ cd /xxx/xxxx/fb_vue_template

$ cd functions && npm run build && cd ../

ローカルWEBサーバ起動(事前にビルド要)

$ cd /xxx/xxxx/fb_vue_template

$ firebase serve --only functions

デプロイ

$ cd /xxx/xxxx/fb_vue_template

$ firebase deploy --only functions
ちなみにfunctionsは、再ビルドが走るので、事前にビルドは不要

おつかれさまでした。


関連リンク

公式

いままで書いたVue.js/Firebase関連記事