Firebase Functions + TypeScript を VSCode でデバッグする

[Debugging with Visual Studio Code · GoogleCloudPlatform/cloud-functions-emulator Wiki](https://github.com/GoogleCloudPlatform/cloud-functions-emulator/wiki/Debugging-with-Visual-Studio-Code)

の内容を少しアレンジして。

## 試した環境

* macOS
* node - v6.11.5
* VSCode - 1.24.1
* Google Cloud Platform の任意のアカウント(ログインのみが必要で何もデプロイされません)

``firebase-tools`` と ``@google-cloud/functions-emulator`` をインストールします。

```bash
npm install -g firebase-tools
npm install -g @google-cloud/functions-emulator
```

## サンプルプロジェクトの作成

```bash
mkdir fb01
cd fb01
firebase login
```

ブラウザでログインして cli のアクセスを許可すると、コンソール側もログイン完了になります。


```bash
firebase init functions
```

* ? Select a default Firebase... -> create a new project
* ? What language would you like... -> TypeScript
* ? Do you want to use TSLint... -> Y
* ? Do you want to install dependencies with npm now? -> Y 

## サンプルの helloWorld 関数の作成

```bash
code .
```

で ``fb01`` ディレクトリを VSCode で開きます（普通にフォルダを開くでもok）。

``/functions/src/index.ts`` を開いて、 ``helloWorld`` のコメントアウトを外します。

```typescript
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!");
});
```

次に、 ``/.vscode/launch.json`` を作り、次のように記述します。
(VSCode のメニュー -> デバッグ -> 構成の追加 でもok)

```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Inspect Function",
            "type": "node",
            "protocol": "inspector",
            "request": "attach",
            "port": 9229
        }
    ]
}
```

VSCode で メニュー -> タスク -> ビルドタスクの実行 -> npm build - function を実行（ターミナルで ``npm run build`` でもok）。

``/functions/lib`` ディレクトリに ``index.js`` が ``index.js.map`` ができます。

## Functions エミュレータへ関数をデプロイ

```bash
cd functions
functions start
```

で Functions Emulator を起動し、

```bash
functions deploy helloWorld --trigger-http
```

で、エミュレータに ``helloWorld`` 関数をデプロイします。
デプロイできれば次のような出力になります。

```bash
Copying file:///var/folders/lv/5j48kqb146xdtt0dn65h_2480000gn/T/tmp-69998WgYjI25qtJ59.zip...
Waiting for operation to finish...done.
Deploying function.......done.
Function helloWorld deployed.
┌────────────┬───────────────────────────────────────────────────────────────────────────────────┐
│ Property   │ Value                                                                             │
├────────────┼───────────────────────────────────────────────────────────────────────────────────┤
│ Name       │ helloWorld                                                                        │
├────────────┼───────────────────────────────────────────────────────────────────────────────────┤
│ Trigger    │ HTTP                                                                              │
├────────────┼───────────────────────────────────────────────────────────────────────────────────┤
│ Resource   │ http://localhost:8010/fb01/us-central1/helloWorld                             │
├────────────┼───────────────────────────────────────────────────────────────────────────────────┤
│ Timeout    │ 60 seconds                                                                        │
├────────────┼───────────────────────────────────────────────────────────────────────────────────┤
│ Local path │ /Users/xxx/dev/playground/fb01/functions                             │
├────────────┼───────────────────────────────────────────────────────────────────────────────────┤
│ Archive    │ file:///var/folders/lv/xxxxx_2480000gn/T/tmp-69998WgYjI25qtJ59.zip │
└────────────┴───────────────────────────────────────────────────────────────────────────────────┘
```

## デバッグの実行

ターミナル側で次のコマンドを実行します。

```bash
functions inspect helloWorld
```

``Debugger for helloWorld listening on port 9229`` のような出力が得られます。
ポート番号がもし 9229 以外なら、 ``/.vscode/launch.json`` の ``port:`` を書き換えてください。

VScode で、メニュー -> デバッグ -> デバッグの開始 を実行します(サイドメニューの虫みたいなアイコンから実行してもok)。

次に ``/functions/src/index.ts`` を開いて 9行目 も行番号の左側あたりをクリックしてブレークポイントを追加します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8227/6dfef1f5-5429-5a05-123c-87ce88f904d6.png)

ターミナルに戻って、次のコマンドを実行します。

```bash
functions call helloWorld
```

すると、VSCode 側では、ブレークポイントを置いたところで処理が停止するのが確認できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8227/0c1ef1fc-f2dc-54b6-1364-5e37fb9c7236.png)

前の手順 ``functions deploy`` で出力された Resource に記述された URL にアクセスしても、ブレークポイントで止まることが確認できます。

めでたしめでたし。

## 後片付け

```bash
functions delete helloWorld
```

で deploy した関数を削除。

```bash
functions kill
```

で start した Functions エミュレータをシャットダウンできます。

## あとがき

* [Debugging with Visual Studio Code](https://github.com/GoogleCloudPlatform/cloud-functions-emulator/wiki/Debugging-with-Visual-Studio-Code#v8-inspector-integration) には、２つのデバッグ手法（"Standard Node.js Debugger" と "V8 Inspector Integration"）が紹介されていますが、前者はうまく機能させられませんでした。なのでこの記事は後者の内容です。
* [V8 Inspector Integration](https://github.com/GoogleCloudPlatform/cloud-functions-emulator/wiki/Debugging-with-Visual-Studio-Code#v8-inspector-integration) で紹介されている ``launch.json`` は古いらしく ``"type": "node2"`` で警告が出ます。それを修正したのが上記で示した ``"type": "node", "protocol": "inspector"`` を使ったものです。