Help us understand the problem. What is going on with this article?

【勉強会用資料】Cloud Functions for FirebaseとFirebase Hostingを使い、ベーシック認証付きステージング環境と本番環境を用意する

More than 1 year has passed since last update.

勉強会用に作成した、Cloud Functions for FirebaseとFirebase Hostingを使い、ベーシック認証付きステージング環境と本番環境を用意するまでのフローです。

以下の内容を学ぶことができます。

  • Git(GitHub)入門
  • Firebase Hosting と Cloud Functions for Firebase 入門
    • ほんのりTypeScript

始めるまえに、以下の設定が必要です。

  • GitHubアカウント
  • Googleアカウント
  • ローカル環境にNode.jsのインストール(version 8 以上)

GitHubのリポジトリを作成

  1. 「New repository」でリポジトリを新規作成
  2. 「Clone or download」でURLを取得しクローン
  3. 任意の場所でプロジェクト用ディレクトリを作成
  4. クローンしたディレクトリにターミナルで移動
$ mkdir demo-project
$ git clone <github-url>
$ cd demo-projecy

developブランチの作成

ターミナルでブランチを作成

$ git checkout -b develop

ベーシック認証の環境

Firebaseのプロジェクトを作成

コンソールで新規プロジェクト作成

firebaseの設定

$ firebase login
$ firebase init
  1. Functions: Configure and deploy Cloud Functionsを選択
  2. Firebase Consoleで作成したプロジェクトを選択
  3. せっかくなのでTypeScriptを選択
  4. Do you want to use TSLint to catch probable bugs and enforce style? -> n(TSLintよりも、ESLintが良いかと思うのでここはNoで)
  5. Do you want to install dependencies with npm now? -> [enter](npm installしてくれます)

開発環境の構築

リダイレクト用ホスティングディレクトリ作成

public/
  └ placeholder.html

Webページの本体になるディレクトリを作成
nuxt generate等で出力する場合は、そのディレクトリ)

表示確認ようにダミーのindex.htmlを作成しておく

functions/
  └ dist/
    └ index.html

package.jsonpackage-lock.jsonを移動

functions/
  ├ package.json
  └ package-lock.json

functions/
package.json
package-lock.json

npm scriptを書き換え

  "scripts": {
    "build": "tsc --project functions",
    "preserve": "npm run build && npm run copy-deps && npm run install-deps",
    "serve": "npm run build && firebase serve",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "init-deploy": "firebase deploy",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log",
    "copy-deps": "cpx \"*{package.json,package-lock.json,yarn.lock}\" \"functions\" -C",
    "install-deps": "cd functions && npm install && cd ../"
  }

パッケージの追加

$ npm i express basic-auth-connect && npm i -D @types/express cpx

firebase.jsonの書き換え

{
  "functions": {
    "source": "functions",
    "predeploy": "npm run preserve"
  },
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "function": "stagingApp"
      }
    ]
  }
}

function/src/index.tsに以下を記述

import * as functions from 'firebase-functions';
import * as express from 'express';

// 型定義ファイルを作るのが面倒なので妥協。。。
const basicAuth = require('basic-auth-connect');

const user = 'user';
const pass = 'pass';

const server = express();
server.use(basicAuth(user, pass));
server.use(express.static('./dist'));

export const stagingApp = functions.https.onRequest(server);

function/src/index.tsをビルドしてローカルサーバー立ち上げ

$ npm run serve

機密情報を環境変数に変更

このままだとベーシック認証のアイパスが見えてしまうので環境変数に格納

$ cd functions
$ firebase functions:config:set basicauth.user="<yourUserName>" basicauth.pass="<yourPassword>"

設定した環境変数は以下で確認できる

$ firebase functions:config:get

ローカルサーバーでも使えるように、functions/.runtimeconfig.jsonを作成

$ firebase functions:config:get > .runtimeconfig.json
$ cd ../

.gitignore.runtimeconfig.jsonを追加してgit管理から外す(リモートにプッシュ禁止)

また、functions/配下にもnode_modulespackage.jsonが必要なため、以下のコマンドで複製しインストールしておく

(ローカルサーバー立ち上げ、デプロイ時にも実行されます)

$ npm run copy-deps && npm run install-deps

function/src/index.tsを修正

import * as functions from 'firebase-functions';
import * as express from 'express';

// 型定義ファイルを作るのが面倒なので妥協。。。
const basicAuth = require('basic-auth-connect');

// 環境変数
const user = functions.config().basicauth.user;
const pass = functions.config().basicauth.pass;

const server = express();
server.use(basicAuth(user, pass));
server.use(express.static('./dist'));

export const stagingApp = functions.https.onRequest(server);

ローカルサーバーで確認

$ npm run serve

publicディレクトリをアップするため、以下を実行

$ npm run init-deploy

次回以降は、publicディレクトリをアップしないので、以下でOK

$ npm run deploy

コミットしてGitHubにプッシュ

$ git add .
$ git commit -m "コミットメッセージ"
$ git push origin HEAD

本番環境

firebaseで本番環境も対応する場合は切り替えが必要なので対応

コンソールで新規プロジェクト作成

今回は2種類の本番環境を用意

  • 静的ホスティング
    • 静的なサイトであれば十分
    • Cloud Functions for Firebase を経由しないのでパフォーマンス的には少し有利?
  • Expressをそのまま使用
    • Node.jsが使える
      • よって、ExpressじゃなくてもOK

環境構築(静的ホスティング)

developブランチから新たにブランチを作成

$ git checkout -b static_hosting

作成した本番用プロジェクトのホスティング情報を.firebasercに追加

$ firebase target:apply hosting production <production-project-id>
$ firebase target:apply hosting staging <staging-project-id>

firebase.jsonに環境別のホスティング情報を追記

  {
    "functions": {
      "source": "functions",
      "predeploy": "npm run preserve"
    },
+   "hosting": [{
+     "target": "staging",
+     "public": "public",
+     "ignore": [
+       "firebase.json",
+       "**/.*",
+       "**/node_modules/**"
+     ],
+     "rewrites": [
+       {
+         "source": "**",
+         "function": "stagingApp"
+       }
+     ]
+   },
+   {
+     "target": "production",
+     "public": "functions/dist",
+     "ignore": [
+     "firebase.json",
+       "**/.*",
+       "**/node_modules/**"
+     ]
+   }]
  }

package.jsonの書き換え

  "scripts": {
    "build": "tsc --project functions",
    "preserve": "npm run build && npm run copy-deps && npm run install-deps",
    "serve": "npm run build && firebase serve",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy-init": "firebase deploy",
-   "deploy": "firebase deploy --only functions",
+   "deploy-staging": "firebase deploy --only functions",
+   "deploy-production": "firebase deploy --only hosting:production",
    "logs": "firebase functions:log",
    "copy-deps": "cpx \"*{package.json,package-lock.json,yarn.lock}\" \"functions\" -C",
    "install-deps": "cd functions && npm install && cd ../"
  },

ステージングにデプロイ

$ npm run deploy-staging

本番にデプロイ

$ npm run deploy-production

環境構築(Express環境)

一度、developブランチに戻り、express_hostingブランチを新たに作成

$ git checkout develop
$ git checkout -b express_hosting

作成した本番用プロジェクトを指定し、エイリアスを設定

$ firebase use --add
$ What alias do you want to use for this project? (e.g. staging)

.firebasercにプロジェクトが追加される(今回はproductionというエイリアスで登録)

もともとのdefaultエイリアスはわかりやすい名前に変えてOK(以下はstagingに変更)

{
  "projects": {
-   "default": "<staging-project-id>",
+   "staging": "<staging-project-id>",
+   "production": "<production-project-id>"
  }
}

firebase.jsonも変更

{
  "functions": {
    "source": "functions",
    "predeploy": "npm run preserve"
  },
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
-       "function": "stagingApp"
+       "function": "app"
      }
    ]
  }
}

npm scriptにプロジェクトの切り替えタスクを追加

  "scripts": {
    "build": "tsc --project functions",
    "preserve": "npm run build && npm run copy-deps && npm run install-deps",
    "serve": "npm run build && firebase serve",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "init-deploy": "firebase deploy",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log",
    "copy-deps": "cpx \"*{package.json,package-lock.json,yarn.lock}\" \"functions\" -C",
    "install-deps": "cd functions && npm install && cd ../",
+   "env-staging": "firebase use staging",
+   "env-production": "firebase use production"
  }

プロジェクト切り替えが可能になる

$ npm run env-xxx

本番環境でベーシック認証解除

環境変数をクローンし、問題がないか確認

$ firebase functions:config:clone --from <project-id>
$ firebase functions:config:get

以下のディレクトリとファイルを作成

functions/src
  └ app
    ├ app.ts
    ├ index.ts
    ├ productionApp.ts
    └ stagingApp.ts

functions/src/app/stagingApp.ts

import * as functions from 'firebase-functions';
import * as express from 'express';

// 型定義ファイルを作るのが面倒なので妥協。。。
const basicAuth = require('basic-auth-connect');

const user = functions.config().basicauth.user;
const pass = functions.config().basicauth.pass;

const server = express();
server.use(basicAuth(user, pass));
server.use(express.static('./dist'));

export const stagingApp = functions.https.onRequest(server);

functions/src/app/productionApp.ts

import * as functions from 'firebase-functions';
import * as express from 'express';

const server = express();
server.use(express.static('./dist'));

export const productionApp = functions.https.onRequest(server);

functions/src/app/app.ts

import { productionApp } from './productionApp';
import { stagingApp } from './stagingApp';

const isStaging = process.env.GCLOUD_PROJECT === '<staging-project-id>';
export const app = isStaging ? stagingApp : productionApp;

functions/src/app/index.ts

export { app } from './app';

functions/src/index.tsを書き換え

export { app } from './app';

本番環境用ローカルサーバーを立ち上げ

$ npm run env-production
$ npm run serve

テスト環境用ローカルサーバーを立ち上げ

$ npm run env-staging
$ npm run serve

本番環境にデプロイ

$ npm run env-production
$ npm run init-deploy

次回以降は、以下でOK

$ npm run env-production
$ npm run deploy

テスト環境にデプロイ

$ npm run env-production
$ npm run deploy

コミットしてGitHubにプッシュ

$ git add .
$ git commit -m "コミットメッセージ"
$ git push origin HEAD

最後にGitHubでプルリクエストを作り、developブランチにマージしてみましょう!

otsukayuhi
ゆめみ所属のフロントエンドウェブデベロッパーです。藤子・F・不二雄先生を尊敬する、キーボードマニアでもあります。
https://otsukayuhi.app/
yumemi
みんなが知ってるあのサービス、実はゆめみが作ってます。スマホアプリ/Webサービスの企画・UX/UI設計、開発運用。Swift, Kotlin, PHP, Vue.js, React.js, Node.js, AWS等エンジニア・クリエイターの会社です。Twitterで情報配信中https://twitter.com/yumemiinc
http://www.yumemi.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした