Amplifyをmonorepoで構成し、pnpmでワークスペースを管理する
背景
現在開発中のシステムはAmplifyでホスティングしているNext.jsのプロジェクトです。ほとんどのバックエンドはAmplify管理下のLambdaによって処理をしていますが、Lambdaの実行時間制限を回避するためECSでタスク定義が必要なユースケースがありました。
Dockerコンテナイメージを作りますが当初はamplifyディレクトリ下にcustomディレクトリを作り、そこで開発をしていました。しかし、以下の都合が悪い点が判明しました
- プロジェクトルートにpackage.jsonがあるのでDockerコンテナで不要な依存関係がイメージ内に入り込みイメージが無意味に肥大化する
- Dockerコンテナイメージのプロジェクト用にpackage.jsonを用意するとライブラリバージョンの多重管理が発生する
この問題を回避するため、monorepo構成を採用しAmplify管理のパッケージとECSタスク用のパッケージに分離。ECSタスクのパッケージはCDKでConstructを定義してAmplifyのbackend.tsから参照する方法を取りました。
構成
最終的なディレクトリ構成は以下です。
├── amplify.yml
├── docs
├── package.json
├── packages
│ ├── data-client
│ │ └── package.json
│ ├── amplify-project
│ │ ├── amplify
│ │ │ ├── auth
│ │ │ ├── data
│ │ │ ├── functions
│ │ │ ├── lib
│ │ │ ├── package.json
│ │ │ ├── pnpm-lock.yaml
│ │ │ ├── seed
│ │ │ ├── storage
│ │ │ └── tsconfig.json
│ │ ├── amplify_outputs.json
│ │ ├── app
│ │ ├── components
│ │ │ ├── __tests__
│ │ │ └── ui
│ │ ├── components.json
│ │ ├── contexts
│ │ ├── hooks
│ │ │ ├── __mocks__
│ │ │ └── __tests__
│ │ ├── lib
│ │ │ ├── __tests__
│ │ │ └── team
│ │ ├── next.config.js
│ │ ├── package.json
│ │ ├── postcss.config.cjs
│ │ ├── public
│ │ │ ├── amplify.svg
│ │ │ └── next.svg
│ │ └── tsconfig.json
│ └── ecs-project
│ ├── cdk
│ │ ├── lib
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── service
│ └── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── tsconfig.json
また、amplify.ymlは以下です。
version: 1
applications:
- appRoot: packages/amplify-project
backend:
phases:
preBuild:
commands:
- npm install -g pnpm
- pnpm install
build:
commands:
- |
case "${AWS_BRANCH}" in
main)
pnpm exec ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
;;
develop)
pnpm exec ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
;;
*)
pnpm exec ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
;;
esac
frontend:
buildPath: packages/amplify-project
phases:
preBuild:
commands:
# 環境変数を.envファイルに書き出す
- |
echo "Creating .env file with environment variables..."
cat > .env << EOF
NODE_ENV=production
EOF
build:
commands:
- pnpm run build
artifacts:
baseDirectory: .next
files:
- '**/*'
cache:
paths:
- .next/cache/**/*
- node_modules/**/*
またドキュメントにもありますが.npmrcファイルの編集も必要です。
node-linker=hoisted
Amplifyのコンソールで環境変数AMPLIFY_MONOREPO_APP_ROOTをpackages/amplify-projectに設定するとビルドとデプロイが可能となりました。最後にpnpmのcatalog機能を使って依存関係をpnpm-workspace.yamlで管理してECS用のコンテナを作成するパッケージとAmplify管理のパッケージで依存関係のバージョンを揃えることができました。
ハマったこと
CustomerError: Cannot read 'next' version in package.json.
package.jsonでnextの依存関係をcatalog:としていると発生したエラーです。エラーの全文は以下。
!!! CustomerError: Cannot read 'next' version in package.json.
If you are using monorepo, please ensure that AMPLIFY_MONOREPO_APP_ROOT is set correctly.
Learn More: https://docs.aws.amazon.com/amplify/latest/userguide/monorepo-configuration.html#setting-monorepo-environment-variable
環境変数AMPLIFY_MONOREPO_APP_ROOTも設定しているのに何故?と思いましたが、結局nextに関してはcatalogを利用せず直接package.jsonで依存関係を設定するべきでした。
devDependencies {
- "next": "catalog:"
+ "next": "15.5.2"
}
Zod Error
デプロイには成功するのにamplify_outputs.jsonの作成に失敗しました。エラーはZod ErrorでZod実行時エラーが発生していました。これはZodのバージョンによるものでAmplify backend cliが使っているZodが3.xに対し最新版の4.xがカタログで定義されていたためampx実行時にZod 4が利用されてエラーとなっていたようです。
これはカタログのバージョン修正で対応できました。
zod: ^3.25.17
リポジトリを見に行っても特にアップデート無いし、このままZod 3で進むのかな?
まとめ
Amplifyでmonorepo構成を実施してリポジトリ内で複数のパッケージを管理可能にしました。
Discussion