created: 2021-12-22T03:03:30.000Z

Cloud Function (非Firebase) に TypeScript のコードをデプロイする

デプロイの要件はひととおりドキュメントに書いてあるので、それを満たすように tsconfig やデプロイスクリプトを作ることになる。

デプロイの要件

要件上では、最低限この2つのファイルがあればデプロイができる。

  • index.js
  • package.json

index.js に関数を実装して、それが module.exports なり export されていれば、その処理がイベント発生時に実行される。

export const myFunc = () => {...};

依存パッケージ

package.json に書いてある依存パッケージはGCP側がインストールしてくれる。

関数の依存関係を指定するには、package.json ファイルにその依存関係を追加します。

ファイル名の規約

gloud function コマンドは指定されたディレクトリの index.jsfunction.js という名前のファイルを探して、それをデプロイしてくれるようになっている。

Cloud Functions will look for files with specific names for deployable functions. For Node.js, these filenames are index.js or function.js.

すべてを1ファイルにバンドルする必要はないが、エントリポイントとして最初に読み込まれるファイル名は規約どおりindex.js などにしておくか、--source オプションで指定することになる。

ESM

ESM で記述されたコードをデプロイしたい場合は package.json に "type": "module" と記述すればよいようだ。

Cloud Functions の関数内で ESM を使用するには、package.json 内で "type": "module" を宣言する必要があります。

TypeScript で書いているので今回はあんまり気にする必要はない。

最小限のデプロイをするためのコード例

./src/index.ts

  • httpエンドポイントをつくるときは functions-framework の型定義が便利。
  • export const {{関数名}} とすれば、それを gcloud が拾ってくれる。
import type { HttpFunction } from '@google-cloud/functions-framework/build/src/functions';
export const sendSlack: HttpFunction = (req, res) => {...};

./package.json

  • 先述のESMの設定などはここに。他には依存パッケージが書いてあればよい。
{
  "type": "module",
  "dependencies": {
    "nodemailer": "^6.7.2"
  }
}

tsconfig.json

必要そうなところだけ抜粋。

{
  "compilerOptions": {
    // ESMでハマるのが面倒だったのでjsはcommonjsで出力
    "module": "commonjs",  
    // ここで指定した ディレクトリの中身を Cloud Function にアップロードする
    "outDir": "./dist",
  },
}

./deploy.sh

#!/usr/bin/env bash
set -euxo pipefail
cd $(dirname $0)

# デプロイされるディレクトリを掃除
rm -rf ./dist/*
# ./src に書かれたコードを ./dist 配下に出力
npx tsc
# デプロイディレクトリに package.json が必要なのでコピー
cp ./package.json ./dist/

# デプロイ先の環境があっているように念の為設定 (以前に手痛い失敗があった)
export CLOUDSDK_ACTIVE_CONFIG_NAME=xxxxxx

gcloud functions deploy \
    # デプロイする CloudFunction の名前を定義
    sendSlack \
    # デプロイディレクトリの指定
    --source=./dist \
    # デフォルトだとusにできてしまうのでregionを設定
    --region=asia-northeast1 \
    # デプロイされる関数名 (index.js 内に定義されているもの)
    --entry-point=sendSlack \
    # http エンドポイントを作るためのオプション
    --trigger-http \
    # http エンドポイントに認証をかけない(オープンにする)ためのオプション
    --allow-unauthenticated \
    # ランタイムを指定
    --runtime=nodejs14 \

その他

package.json に以下のような定義がはいっているとCloudBuild上でビルドができなくてハマる。

  "main": "dist/index.js",

ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Build failed: dist/index.js does not exist; Error ID: 9e84f42e

この定義があると、CloudBuild は dist/dist/index.js を探してしまうことになるため。 定義を削除して「index.js または function.js を探す」というデフォルトの挙動に戻してやる必要がある。

Interface(インターフェース) 2023年 07 月号
[ad] Interface(インターフェース) 2023年 07 月号
Interface編集部 (雑誌)