Cloud Functions+ TypescriptでJSONファイルをimportしたらどハマりした話

(※)Coud Functions公式ドキュメントはこちら
https://firebase.google.com/docs/functions/typescript?hl=ja


先日、初めてFirebaseのCloud Functions(いわゆるサーバーレスというもの。AWSでいうLambda)をTypescriptで書きました。

公式ドキュメントを見てみても割と分かりやすく、(JSでなら書いた事あるので) 同じように問題無く書けるかなあと思っていたのですが、ある時を境に幾らtscコマンドでbuildし直してもコンパイル後のコードが変わらないという自体に陥り、4時間くらい溶かしました…

その原因が、jsonファイルのimportの仕方に問題があったというお話です。



基本となるTypescript + Coud Functionsのディレクトリ構成は下記の通りです。
src/配下にTypescriptのコードを配置します。コンパイルされると、lib/配下にJSファイルが生成されます。

```基本となるディレクトリ構成.
 +- functions/     # Directory containing all your functions code
      |
      +- package.json  # npm package file describing your Cloud Functions code
      |
      +- tsconfig.json
      |
      +- tslint.json # Optional file
      |
      +- src/     # Directory containing TypeScript source
      |   |
      |   +- index.ts  # main source file for your Cloud Functions code
      |
      +- lib/
          |
          +- index.js  # Built/transpiled JavaScript code
          |
          +- index.js.map # Source map for debugging
```


また、TSでjsonファイルをimportするためには、tsconfig.jsonに次の記載をします。

```tsconfig.json
"compilerOptions": {
    ...
    "resolveJsonModule": true
  }
```

更に今回はfirebase-adminの機能を使う必要があり、シークレットファイル(firebase-admin.json) を/functionsの一段上の階層に配置しておりました。下記のような構造です。
シークレットファイルは、アプリ(Nuxt.js)側でも使うので、一番ルートの部分に配置しておりました。

```自分が実装した構成.
 +- _secrets
      |
      +- firebase-admin.json  #シークレット情報を管理
 +- functions/
      |
      +- package.json 
      |
      +- tsconfig.json
      |
      +- tslint.json 
      |
      +- src/
      |   |
      |   +- index.ts  # main source file for your Cloud Functions code
      |
      +- lib/
          |
          +- index.js  
          |
          +- index.js.map
```

そして、index.tsからは、下記の通りにしてimportしおりました。

```index.ts
import serviceAccount from '../../_secrets/firebase-admin.json'
```



これで上手く自分の意図通りにコンパイルされると思っていたのですが、実際は下記の通りになりました。



```コンパイル後.
 +- _secrets
      |
      +- firebase-admin.json  #シークレット情報を管理
 +- functions/
      |
      +- package.json 
      |
      +- tsconfig.json
      |
      +- tslint.json 
      |
      +- src/
      |   |
      |   +- index.ts  # main source file for your Cloud Functions code
      |
      +- lib/
          |
          +- index.js  # 幾らコンパイルしても変更されない！！かつ、deployするとこのファイルがアップされる
          |
          +- index.js.map　  # 幾らコンパイルしても変更されない！！かつ、deployするとこのファイルがアップされる
          +- src/
               +- secrets
               +- firebase-admin.json  #シークレット情報を管理
               +- lib
                   +- index.js  # コンパイル後のファイル！
                   +- index.js.map　  # コンパイル後のファイル！
```



そうです、幾らコンパイル→ビルド→デプロイをしても、(永遠に変更されない)lib/index.jsのみがアップされ、
正しいファイル(/lib/src/index.js)はアップされませんでした。


結局は、_secretsファイルを下記の通りに配置する事で解決しました。


```解決後

 +- functions/
      |
      +- package.json 
      |
      +- tsconfig.json
      |
      +- tslint.json 
      |
      +- src/
      |   |
      |   +- index.ts  # main source file for your Cloud Functions code
          +- _secrets
               |
               +- firebase-admin.json  #シークレット情報を管理
      |
      +- lib/
          |
          +- index.js　#ちゃんとコンパイルすれば変更される！
          |
          +- index.js.map　#ちゃんとコンパイルすれば変更される！
```


firebase-admin.jsonを、アプリ側でも使うんだと/functionsより上のディレクトリに配置するとこのような事が起こるんだという事を認識しました。
結局は、アプリ側のディレクトリとfunctions側のディレクトリ、2箇所で持つ必要があるようです。(もしくは、functionsをビルドする時のみ一時的にfirebase-admin.jsonをfunctinos側にコピーし、ビルドが終わったら破棄するようにpackage.json内のコマンドを設定するか)



今回の時間の浪費は、コンパイル後のjsファイルをチェックする癖があれば防げました。
Cloud Functions + Typescriptは、まだそこまで情報がネット上に無い印象です。
この記事が、他の誰かの助けになればよいと思っています。