[アップデート] AWS SAM CLI の sam build で、npm workspaces モノレポの依存インストールが1回で済むようになりました
いわさです。
npm workspaces は、1つのルートパッケージの下で複数のパッケージをまとめて管理する npm の機能です。
依存はルートの node_modules にまとめて置かれ、各パッケージはそこを共有して参照します。
この npm workspaces で組んだモノレポを sam build --build-in-source でビルドすると、これまでは関数ごとに npm のインストールが走っていました。各関数のインストールは npm がルートまで解決するためです。
AWS SAM CLI 1.171.0 で、このインストールをモノレポ全体で1回にまとめる機能が追加されました。
この機能はまだ実験的な扱い(ベータ)で、有効にしないと使えません。デフォルトでは従来どおり関数ごとにインストールが走ります。
実際に有効にする前後で挙動を比べてみます。
実際に試してみる
npm workspaces のモノレポを用意しました。
esbuild でビルドする Lambda 関数を8個(func-a 〜 func-h)と、全関数から参照する共有パッケージ @mono/shared を1つ置いています。
各関数は共有パッケージと、それぞれ別の依存(lodash や AWS SDK など)を使います。
SAM CLI のバージョンは 1.171.0 です。
$ sam --version
SAM CLI, version 1.171.0
まず今までどおり、ベータ機能を有効にせずに sam build --build-in-source を実行しました。ビルドは成功します。
ログを見ると、関数ごとに NodejsNpmEsbuildBuilder:NpmUpdate(依存のインストール)と NodejsNpmEsbuildBuilder:EsbuildBundle(バンドル)が繰り返されていました。
Building codeuri: .../functions/func-a runtime: nodejs22.x architecture: x86_64 functions: FuncA
Running NodejsNpmEsbuildBuilder:NpmUpdate
Running NodejsNpmEsbuildBuilder:EsbuildBundle
Building codeuri: .../functions/func-b runtime: nodejs22.x architecture: x86_64 functions: FuncB
Running NodejsNpmEsbuildBuilder:NpmUpdate
Running NodejsNpmEsbuildBuilder:EsbuildBundle
:
NpmUpdate が関数それぞれで走っています。
前述のとおり、同じモノレポ全体のツリーに対するインストールを関数の数だけ繰り返していますね。
次に、今回のベータ機能を有効にして同じモノレポをビルドしました。
有効化方法ですが、環境変数 SAM_CLI_BETA_NODEJS_MONOREPO=1 と --beta-features を付けて実行する感じです。
$ SAM_CLI_BETA_NODEJS_MONOREPO=1 sam build --build-in-source --beta-features
ベータ機能を有効にしているのと、実行時冒頭にその案内が出ます。そういえばこんなん前もあったな。
Experimental features are enabled for this session.
Visit the docs page to learn more about the AWS Beta terms https://aws.amazon.com/service-terms/.
実行結果は以下です。変わりましたね。
Installing dependencies once for workspace root .../sam-monorepo, shared by (FuncA, FuncB, FuncC, FuncD, FuncE, FuncF, FuncG, FuncH)
Building codeuri: .../functions/func-a runtime: nodejs22.x architecture: x86_64 functions: FuncA
Running NodejsNpmEsbuildBuilder:EsbuildBundle
Building codeuri: .../functions/func-b runtime: nodejs22.x architecture: x86_64 functions: FuncB
Running NodejsNpmEsbuildBuilder:EsbuildBundle
:
先頭に Installing dependencies once for workspace root ..., shared by (...) という行が出て、依存のインストールがここで1回だけ実行されたのがわかりますかね。
その後は各関数とも EsbuildBundle だけで、さっきと違って関数ごとに NpmUpdate は実行されていないですね。
ビルド時間も比べました。何回か試してみましたが結果は以下のようになりました。
| 回 | ベータ機能なし | ベータ機能あり |
|---|---|---|
| 1 | 12.9秒 | 5.9秒 |
| 2 | 12.8秒 | 5.9秒 |
| 3 | 13.1秒 | 6.0秒 |
毎回安定して半分くらいの時間になってますね。
GitHub の該当機能の PR には、8個の関数 / 約300パッケージのモノレポで 21.9秒 → 1.5秒、20個の関数で 57.8秒 → 3.0秒に改善されたと記載されていました、なかなかすごい。
私の場合は半分くらいでしたけど関数の数と依存の規模が大きいほど、重複していたインストールを減らせる分だけ差が大きくなる感じです。
なお、今回の機能が有効になるのは、次の条件をすべて満たすときです。
- Zip 形式の Node.js 関数
- npm または esbuild ワークフロー
--build-in-sourceを指定している--cachedを使っていない--use-container(コンテナビルド)を使っていない- その関数が npm workspaces のメンバーである(npm が解決するプロジェクトルートが、関数のコードディレクトリの外側にある)
これ以外のケースや、まとめてのインストールが失敗したときは、従来どおり関数ごとのインストールに戻ります。
もしうまくいかなかった時は上記を確認してみてください。
さいごに
本日は AWS SAM CLI に追加された、npm workspaces モノレポの依存インストールをまとめる機能を確認してみました。
関数の数だけ走っていたインストールがモノレポ全体で1回にまとまって、今回の構成では半分くらいになりました。
ベータ扱いなので有効化は必要ですが、npm workspaces でビルド時間に困っている方はぜひ試してみてください。









