🦔

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から参照する方法を取りました。

https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/monorepo-configuration.html

構成

最終的なディレクトリ構成は以下です。

├── 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は以下です。

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ファイルの編集も必要です。

.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で依存関係を設定するべきでした。

packages/amplify-project/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が利用されてエラーとなっていたようです。

これはカタログのバージョン修正で対応できました。

pnpm-workspace.yaml
  zod: ^3.25.17

リポジトリを見に行っても特にアップデート無いし、このままZod 3で進むのかな?

https://github.com/aws-amplify/amplify-category-api/blob/bdc2c2d2778234b0b85be5ad3c5774af2774f31e/packages/amplify-data-construct/package.json#L290

まとめ

Amplifyでmonorepo構成を実施してリポジトリ内で複数のパッケージを管理可能にしました。

Discussion