AWS Lambda上で実行するNode.jsアプリケーションをTypeScriptで開発しているとき、TypeScriptのトランスパイルをどのように行うかがポイントであるが、AWS SAMを利用しているならば template.yml
ファイル内にesbuildの設定を記述することで sam build
時に自動的にトランスパイルしてくれる。
設定方法は以下のドキュメントを参照する。
このドキュメントには
The BuildProperties object supports the following properties for esbuild. All of the properties are optional. By default, AWS SAM uses your Lambda function handler for the entry point.
とあるが、esbuildのすべての設定項目を網羅しているわけではない。
だが、 template.yml
の書き方次第でどのような項目も設定可能であるためその方法について記す。
SAMでTypeScriptをビルドするときに何が起きているか
本題に入る前にそもそもSAM CLIがどのようにesbuildを叩いているのかという部分を確認。
SAM CLIはAWS Labmda用コードのビルドにaws-lambda-buildersを利用している。
これがpythonで実装されており、 template.yml
の内容に応じて子プロセスとしてesbuildを実行するのである。
その時のesbuldコマンドの実行内容は sam build --debug
でデバッグオプションを付けるとわかる。
template.yml
を空にしてビルドすることで、いくつかのオプションはデフォルト値が決まっているということもわかるはずである。
※ コマンドとオプションを整形して出力する
/{省略}/node_modules/.bin/esbuild app.ts --bundle --platform=node --outdir=/private/tmp/sam-app/.aws-sam/build/HelloWorldFunction --target=es2020 --format=cjs --minify
ここで、 template.yml
に対して設定を追加すると、
デフォルトでesbuildコマンドにオプションがつく設定項目( Format
や Minify
など)はオプションが上書きされ、そうでないものはオプションが付与されるようだ。
以下はFormatとOutExtensionを指定した場合の template.yml
Metadata: BuildMethod: esbuild BuildProperties: Format: esm OutExtention: - .js=.mjs
と、その時のSAM CLIが実行するesbulidコマンド。
--format
オプションの値が esm
に変わり、 --out-extention;.js=.mjs
が追加されている。
/{省略}/node_modules/.bin/esbuild app.ts --bundle --platform=node --outdir=/private/tmp/sam-app/.aws-sam/build/HelloWorldFunction --target=es2020 --minify --format=esm --out-extention:.js=.mjs
細かいesbuildビルド設定の書き方
じゃあSAM CLIのドキュメントに書かれていない設定項目以外は template.yml
に書けないのかというとそうでもなく。
esbuildのコマンドオプションのケバブケースをパスカルケース置き換えてあげればよい
このことに言及しているissue
Boolean値を設定する例: Tree shaking
→ 最終的には --tree-shaking
オプションがesbuildに渡される
Metadata: BuildMethod: esbuild BuildProperties: TreeShaking: true
複数文字列値を設定する例: Main fields
→ 最終的には --main-fields=main,module
オプションがesbuildに渡される
Metadata: BuildMethod: esbuild BuildProperties: MainFields: main,module
だがこれにも例外がある。
esbuildはコマンドに --tsconfig
オプションを渡すと tsconfig.json
ファイルのパスを指定することができるが、 tsconfigの設定項目だがSAM CLIがデフォルトでesbuildコマンドに渡しているオプション(例: Format, Minify) についてはtsconfigの内容が無視される。esbuildコマンド内でtsconfigファイルよりもコマンドラインオプションを優先する事になっているため、tsconfigファイルに書いても設定が効かないのである。
例えばこのような tsconfig.json
と template.yml
があったとすると、以下のようなesbuildコマンドが実行される。
{ "compilerOptions": { "target": "ES2018", "module": "esnext", "moduleResolution": "Node", "esModuleInterop": true, "resolveJsonModule": true, "allowSyntheticDefaultImports": true, "strict": true, "allowJs": true, "sourceMap": true, "rootDir": "src" }, "include": ["src/**/*"], "exclude": ["node_modules"] }
Metadata: BuildMethod: esbuild
ここで、sam build時にtemplate.ymlに書かれていない限りデフォルトでCommonJSで出力することから、 出力されるのはCommonJSなファイルである。
このことはSAMを利用しているかどうかに関係なくesbuildを使っているならば出会う可能性のある仕様だが、SAM経由でesbuildするとデフォルトでオプションがいくつかつくのと実行コマンドが隠匿されるので注意が必要である。
参考
build時にtemplate.ymlに書かれた任意の設定からesbuildのオプションを生成している箇所のPR