Amplify のユースケースを意識したmonorepoリポジトリ運用
Amplify の魅力
Amplify を本格的に使い始めて2年ぐらい立ちました。
アップデートも多く入り新しい開発体験を提供し続けてくれます。
興味を持ち始めた当時、私はフロントエンドのアーキテクト的な動きをしていました。バックエンド周りはできれば作りたくないぐらいの感覚で、Amplifyを軽く触り始めました。
実際に触ってみると、完全にお任せするツールというより、さまざまな AWS のマネージドサービスや自動構築手法をまとめたものだと感じるようになりました。
一つ一つ何が構築されたのかを読み解くうちにAWSが生み出すバックエンドの知識がより深まっていきました。
Amplifyは、AWSのさまざまなサービスを知るきっかけでした。
Amplify を使うユースケース
Ampfliy は使い方の自由度が高いです。
ざっくり、ユースケースは大きく分けて3つと思います。
リポジトリ管理の話をする前に、その前提をまず合わせたく、説明させてください。
ホスティング SPA / SSR
Amplify は SPAや SSR アプリのホスティングを簡単かつ高品質に行うことができます。
リポジトリを連携するだけで完了し、かつ cloudfront, route53 の設定まで行ってくれます。
構築されたものは、コンソールや cli を通してアップデートをかけていくことができます。
ホスティングだけで使うというメリットがあります。
バックエンド GraphQL(AppSync) / Lambda / DynamoDB / Fargate の構築
Amplify はサーバレスのバックエンド環境を構築したい、というユースケースにも使うことができます。
バックエンドの構築に関しては、Serverless Framework とよく似ていると感じます。
scheme.graqhql に記述するだけで、DynamoDB 環境が構築されます。
アクセスするためのGraphQLまで自動生成してくれます。
自動生成された GraphQL をそのまま使っても良いですし、自身で書いて良い、という自由さです。
(ちなみにデータベースは、DynamoDBに限定されません、自動構築はされませんが、MySQLなどでも対応可能です。)
同様に lambda 環境も自由に構築することができます。
API Gateway と lambda を同時に作ることもできますし、lambdaだけを構築することもできます。
それらを deploy する cli も継続的に deploy することもできます。
フルスタック
最後は、最初に書いたホスティング、次に書いたバックエンドの二つを組み合わせたフルスタック環境を作るというユースケースです。
Amplify はフロントエンドとバックエンドの環境構築、Deployまでを1リポジトリ、1ツールで構築、開発、運用することができます。
こちらのユースケースが説明されることが多く、最も王道かと思います。
ただ実際サービスを作るとなると、バックエンドとフロントエンドが 1:1 ではないケースが多います。
そういったケースではなく、どちらかだけでも全然使えることをお伝えしたく、最後のユースケースとしました。
リポジトリ構成
前置きが長くなりましたが、それらの三つのユースケースに対応するリポジトリ構成について検討したことを書いてみたいと思います。
他の方の記事などをユースケースに応じて上記三つの構成を自由に選択できるような構成を考えました。
前提
- ホスティングは Next.js
- lambda は JavaScript、できればTypescriptを使いたい
- 将来的に複数のフロントエンド、バックエンドを作りたい
monorepo
大雑把な構成な構成としては下記のように作るようにしています。
apps/
backend
# amplify 本体
amplify
frontEnd1App
next.confing.js
...
frontEnd2App
next.confing.js
...
# lambda のファイル
functions/
lambda1Src
lambda2Src
lambda3Src
packege.json
バックエンドとフロントエンドはアプリケーションを分離する
バックエンドはバックエンドだけ、フロントはフロントだけでアプリケーションを作るようにしています。
Amplify は標準的に monorepo に対応しており、構築時にディレクトリを指定することで対応できます。
得られるメリット
- バックエンドを参照する複数のアプリケーションを構築が可能
- ビルド時間が短縮できる
lambda のコードとバックエンドは分離する
- backend は、データベースの構築に特化せたい。
- lambda のコードは再利用性を考えて別ディレクトリにしたい。
backend の package.json で amplify push に合わせて lambda のビルドが可能です。
{
...
"scripts": {
"amplify:art2ddfa2d42ddfa2d4CustomMessage": "cd ../../functions/art-web-custom-message-cognito-trigger && yarn && tsc -p ./tsconfig.json && cd -",
}
...
}
このようにすることで、一つの lambda コードを複数のバックエンドに対応させることができるようになります。
フロントエンドからバックエンドの参照
通常フルスタック前提の場合、動的に生成される aws-export.js をみて接続先が選択されます。
aws-export.jsは大変便利で、amplify env checkout することで動的に書きかわり接続先を変更することができ亜mす。
その場合、フロントエンドとバックエンドを分離する場合は amplify 環境を pull する必要がでてきます。
フロントエンドにバックエンド関連のファイルが入ってしまい、せっかく分離した意味が薄くなると思い、
これらはフロントエンドの環境変数で運用することにしました。
具体的には下記のように、configs ファイルを作成し、aws-export.js と同様の内容のファイルを置いておきます。
frontendApp
configs/
dev.json
local.json
これらを next.config.js で読み分けることで環境切り替えを行うようにしました。
具体的には下記のようにしています。
console.log("APP_ENV", process.env.APP_ENV);
const moduleExports = withTM({
env: {
...require(`./configs/${process.env.APP_ENV || "local"}.json`),
APP_ENV は amplify console から環境変数で指定することもできますし、
ローカル開発の場合は、node 変数にセットすれば自由に環境を切り替えることができます。
分離した場合のフロントエンドの graqphql の自動生成
フルスタックの場合、amplify codegen を行うことでgraphqlやその型などを src 直下に生成することができます。
分離した場合ですが、amplify コマンドを使い、バックエンドから schema.json のみ pullしてくることが可能です。
schema.jsonがあると、apollo codegen:generate を使って graphql のコマンドや型を生成することができるようになります。
もちろん、自動生成はそもそも使わず、型やクエリは、フロントエンド側で書くという運用も可能です。
自動生成は参考程度で graqhql はフロントエンドサイドで書く場合はそういったことはさらに意識する必要がなくなります。(私の所感としては、全てにこだわりたい訳ではないので自動生成はすごく便利です。)
まとめ
- Amplify は フルスタックアプリケーションランタイムではなく、AWS のインフラ自動構築ツールに近いと感じる。インフラ構築の設計フェーズを飛ばしたり、学習時間を短縮したりすることができる。
- Amplifyはフルスタックソリューションではあるが、それぞれ別に作ることが可能。
- monorepo 運用は、システムスケールまでシナリオに入れると考えても良い。
- 多少の運用を手を入れることで自動生成や環境自動切り替えの仕組みを生かしつつ、分離することができる。
今回は運用方法をお伝えしたかったので具体的なライブラリの説明はしなかったので、
また機会があればそれぞれのはまりどころや問題点についても書いてみたいと思います。
最後に
Amplify 知見を生かした MVP / PoC 開発を行うラボを今年立ち上げました。
フロント、バックエンドのスピード開発を強みにさまざまなチャレンジを行っています。
採用ページはまだ作れていませんが、一緒に新しいスピード感を生み出してくれる仲間を探しています。
もし興味がありましたらお気軽にお問合せください。
Discussion