12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

0からFirebase Cloud FunctionsとNode.jsとTypeScriptとVSCode開発環境の構築

Posted at

背景

Cloud Functionsと Node.js, TypeScript をまともにいじったことなかったのですが、ひょんなことから0から始める機会があったので、流れをまとめました。
開発エディタには TypeScript と相性の良い VSCode(Visual Studio Code)を選びました。

読者対象

  • Mac
  • Firebase ちょっと使ったことある
  • Firebase Functions 未経験
  • Node.js 未経験
  • TypeScript 未経験

書いてること

TypeScript で書いたコードが Firebase-Tools で Cloud Functions にデプロイできるようになるまでについてまとめました。

書いていないこと

  • Node.js のイディオムやコードに関すること
  • TypeScript のイディオムやコードに関すること

全体の流れ

  1. :dog: Node.js 用バージョン管理ツール( nvm )のインストール
  2. :cat: nvm で Firebase が推奨するバージョンをインストール
  3. :bee: npm で Firebase-Tools パッケージをインストール
  4. :house: Firebase-Tools でプロジェクト作成
  5. :cow: npm で残りの必要パッケージをインストール
  6. :train: TypeScriptに必要なパッケージやトランスパイル周りについて
  7. :rocket: Firebase-Tools でデプロイ
  8. :tools: VSCodeで開発しやすい環境準備
  9. :notebook_with_decorative_cover: その他(調査中に見つけた情報)

:dog: Node.js 用バージョン管理ツール( nvm )のインストール

nvm, nodenv, n, ndenv と色々ありますが、nvm を選択しました。
理由は Google トレンドの結果をシンプルに受け止めました。
こういったエコシステムは流行りよりも情報量で選んで、ささっと切り抜けないと本来の目的へ辿りつくのに時間がかかるリスクが増すためです。

image.png

Mac なので Homebrew でインストールします。
インストール成功すると追加設定するよう言われるので、言われたとおりやります。

$ brew install nvm

# ↓ インストール成功後
$ mkdir ~/.nvm

$ vim ~/.bash_profile

# ↓の2つを.bash_profileに追記します
export NVM_DIR=~/.nvm
source $(brew --prefix nvm)/nvm.sh

# インストール成功したか確認します
$ nvm --version
0.34.0

最後の確認でうまく動かない人はターミナルを再起動するか $ source ~/.bash_profile でリロードしてみてください。

:cat: nvm で Firebase が推奨するバージョンをインストール

公式ページでは 8.15.0 なのでローカルの Node.js のバージョンも合わせます。

$ nvm install v8.15.0

:bee: npm で Firebase-Tools パッケージをインストール

npm とは Node.js 用パッケージマネージャーです。
他言語のパッケージマネージャー同様に、グローバルとローカルのインストール先を指定できます。

まず必要なパッケージは firebase-tools になります。
これがあれば Firebase に必要な開発環境の雛形を簡単に作ってくれます。

通常の Node.js 開発であれば $ npm init を叩けば Node.js プロジェクトが作られますし、そのときに package.json も一緒に作られます。
しかし $ firebase init を叩けば Node.js ベースの Firebase のプロジェクトを作ってくれます。

firebase-tools パッケージはグローバルにインストールします。
-g を指定することでグローバルパッケージとしてインストールされ、いろんな所で直接呼べるようになります。

$ npm install -g firebase-tools

※ グローバル環境を汚したくない人は後述する方法を参考にしてみてください。

残りの必要パッケージをインストールする前に先に Firebase プロジェクトを作成します。
そうすることで package.json が作成されて、そこにローカルパッケージとして追加できるからです。

:house: Firebase-Tools でプロジェクト作成

firebase-toolsからFirebaseを操作するために認可させる必要があります。

$ firebase login

プロジェクト作成は

$ firebase init

実行すると質問されるので答えていくことで、最後に Firebase 開発に必要なファイル群が作成されます。

例えば

  • Cloud Functions のみ
  • default Firebase プロジェクトの指定
  • TypeScript
  • TSLintあり
  • 依存解決する

とした場合の ファイルツリーと package.json は次のようになります。

$ tree -L 2
.
├── firebase.json
└── functions
    ├── node_modules
    ├── package-lock.json
    ├── package.json
    ├── src
    ├── tsconfig.json
    └── tslint.json

package.json の中身はこうなります。

{
  "name": "functions",
  "scripts": {
    "lint": "tslint --project tsconfig.json",
    "build": "tsc",
    "serve": "npm run build && firebase serve --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "8"
  },
  "main": "lib/index.js",
  "dependencies": {
    "firebase-admin": "^8.0.0",
    "firebase-functions": "^3.0.0"
  },
  "devDependencies": {
    "tslint": "^5.12.0",
    "typescript": "^3.2.2"
  },
  "private": true
}

TypeScriptTSLint と答えたことで依存パッケージが入っています。
また開発中しか使わないので devDependencies スコープになります。

devDependencies とは $ npm install --production のように本番向けだとインストールされません。
--save だと dependencies スコープ
--save-dev だと devDependencies スコープ
に入ります。

残りのパッケージをインストール

例えば typed-rest-client パッケージをインストールすると package.json に追記されます。

$ npm i --save typed-rest-client

↓は package.json の抜粋です。このように先程インストールしたパッケージが追記されます。

{
  "dependencies": {
    "firebase-admin": "^8.0.0",
    "firebase-functions": "^3.0.0",
    "typed-rest-client": "^1.5.0"
  }
}

express パッケージも入れる場合は入れましょう。

グローバル環境を汚染したくない人向け

これが正しい方法か自信そんなにないですが、

  1. $ npm initpackage.json 作成
  2. $ npm install --save-dev firebase-toolspackage.json に追記
  3. $ npm installfirebase-tools をインストール
  4. $ npx firebase init で Firebase のプロジェクト作成
  5. 作成されたpackage.jsonファイルがあるディレクトリ上で $ npm install --save-dev firebase-tools をインストール

npx とは ローカルパッケージを実行するコマンドです。

他メンバーが入ってきたら

nvm のインストールは必要ですが、 npm のパッケージに関しては

$ npm install

と叩くだけで package.json 内に記述されたパッケージ一覧をインストールしてくれます。

:train: TypeScriptに必要なパッケージやトランスパイル周りについて

トランスパイル

TypeScriptはご存知の通り型あり言語です。
そのままでは動かないので JavaScript にトランスパイルする必要があります。
トランスパイルには tsc というパッケージを使います。
$ tsc src/ts/app.ts --outDir dist/ts とすることで JavaScript ファイルに変換されます。
変換後の JavaScript を Firebase にデプロイします。
つまりデプロイ前にトランスパイルが必須となります。
firebase-tools によって TypeScript を指定して作成したプロジェクトはそこらへんの細かいファイル設定を全て作成してくれます。 :innocent:

tsconfig.json だけでなく package.jsonscript にも反映されています。

  "scripts": {
    "lint": "tslint --project tsconfig.json",
    "build": "tsc",
    "serve": "npm run build && firebase serve --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  }

script とは $ npm run で実行できるコマンド一覧を指します。
新しく作ることもできます。
$ firebase init で TypeScript を指定してあると、ここで事前に npm run build でトランスパイルされてから
それぞれのデプロイやローカル実行などが動きます。

型情報

JavaScriptのパッケージを使うには型情報(DefinitelyTyped) が必要です。
過去に TypeScript 1系などでは、 tsdTypings というツールを使って
型情報管理を行っていましたが、 TypeScript 2系になってからはそれらツールは不要で
npm 内で完結できるようになりました。

例えば Cloud Functions や Express, Node といった型情報をインストールしたい場合

$ npm install --save-dev @firebase/functions-types
$ npm install --save-dev @types/express
$ npm install --save-dev @types/node

のように @types/[型情報] とすることで型情報をインストールできます。
型情報が用意されているかどうかは、http://definitelytyped.org/ で調べることができます。
パッケージによっては始めから型情報が入っている場合もあります。

コーディングスタイル

コーディングスタイルはここを参考にしました。

:rocket: Firebase-Tools でデプロイ

書いてみる

functions/src/index.ts に書いてみましょう。
エディタにはこだわりなければ VSCode をおすすめします。

import * as functions from 'firebase-functions'

export const helloWorld = functions.https.onRequest( (request, response) => {
  console.log('Hello world')
  response.status(200).send('Hello world')
}

デプロイ

$ firebase deploy --only functions

$ firebase init で Firebase プロジェクトを選択済みであれば、このコマンドだけでデプロイが完了します。

async/awaitを使う

下のコードは POSTリクエストを投げると Firestore にデータを書き込むサンプルです。
このサンプルは Firestore を使うため、 プロジェクトに Firestoreに関する情報が配置されている必要があります。
振り返りとして、もう一度 $ firebase init でプロジェクトを作り Firestore も選択したプロジェクトで試してみるといいです。

import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
admin.initializeApp(functions.config().firebase);

export const helloWorld = functions.https.onRequest( async (request, response) => {
  if (request.method !== 'POST') {
      const json = {
          error_list: {
              error_code: '4000',
              message: 'This is not post request'
          }
      }
      response.status(400).send(json)
      return
  }

  await admin.firestore().collection('products').doc('1').set({
      first: "hanako",
      last: "yamada"
  })

  response.status(200).send({first: "hanako", last: "yamada"})
}

:tools: VSCodeで開発しやすい環境準備

ローカル開発

$ firebase serve

でエミュレーターによるローカルで立ち上がり http://localhost~ などでアクセスできるようになります。

また npm script に↓が用意されているので, VSCode上で npm serve を実行するとトランスパイルして立ち上げてくれます。
"serve": "npm run build && firebase serve --only functions,firestore"

:notebook_with_decorative_cover: その他(調査中に見つけた情報)

  • npm watch を実行しながら npm serve を実行すると、コード変更がすぐに反映される
  • $ firebase deploy--project で Firebaseプロジェクトを指定できる.
  • --project で指定をエイリアスに出来る $ firebase use --add を使う
  • --project を未指定でどのエイリアスが使われるのかは $ firebase use で分かる
  • Functionsだけのデプロイは $ firebase deploy --only functions
  • 関数だけのデプロイは $ firebase deploy --only functinos:helloWorld
  • 関数以外のデプロイは $ firebase deploy --except functions
  • 関数の削除は $ firebase functions:delete helloWorld
  • 関数リネームは $ firebase deploy --only functions:newHelloWorld$ firebase functions:delete helloWorld
  • リージョン変更も同様の流れ
  • npm のインストールパッケージ一覧は $ npm lsで確認できる
  • ルートパッケージだけの確認は $ npm ls --depth=0
  • グローバルパッケージは $ npm -g ls
  • Firestore エミュレータは $ firebase setup:emulators:firestore が必要
  • エミュレーターがどのサービスをたちあげるかはfirebase.jsonの中身に依存する

認証エラーはこちらを参考にしました

最後に

  • 駆け足で調査したので情報漏れなどがあるかもしれません。
  • Google公式漁るときは、ノートに情報を抜粋しながらまとめないと、GCP側とFirebase側とで資料と用語がぶつかり、点と点の間の線がやばいことになる
12
8
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
12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?