lernaベースのmonorepoなNext.jsアプリケーションをAWS Amplify ConsoleでSSRホスティングする
環境
Version | |
---|---|
Node | 16.1.0 |
npm | 7.21.0 |
Next.js | 11.1.2 |
lerna | 4.0.0 |
構成
lernaベースのmonorepo構成で、Next.jsアプリケーションであるnext-app-1とnext-app-2に、module-1をlocal packageとして追加しています
my-lerna-repo/
package.json
packages/
module-1/
package.json
next-app-1/
package.json
next-app-2/
package.json
AWS Amplify Console
Amplify CLIでやる場合は、amplify add hosting
の実行後、Hosting with Amplify Console
を選択してリポジトリと連携することになると思います
リポジトリ選択と、ブランチ選択は任意のものを選択し、今回はmonorepo構成なのでConnecting a monorepo? Pick a folder.
にチェックを入れ、ホスティングするNextアプリのパスを入力します
この時点で、以下のSelect an existing service role or create a new one so Amplify Console may access your resources.
の選択項目が表示されていない場合、アプリがNextアプリとして判定されていないため、Nextアプリ配下のpackage.jsonを編集する必要があります
AmplifyはアプリをNextアプリとして判定すると、上記の項目でサービスロールをアタッチすることを要求します。ここで必要な権限を満たすサービスロールをアタッチすることで、S3やCloudFront、LambdaといったNextアプリをホスティングするために必要なリソースを追加で作成してくれるのですが、アプリがNextアプリとして認識されていない場合、選択項目が表示されないので必要な権限をアタッチすることができず、ホスティングも失敗します
AmplifyにアプリをNextアプリとして判定してもらうためには、package.jsonのdependencies
にnext
が含まれている必要があります。なので、Select an existing service role or create a new one so Amplify Console may access your resources.
の選択項目が表示されていない場合、一度AWS Amplify Consoleの設定をキャンセルし、Nextアプリ配下のpackage.jsonのdependencies
としてnext
を追加してから再度設定し直しましょう
lernaの場合、lerna add next --scope next-app-1
ですね
以下のようになっていれば良いはずです
修正版
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"module-1": "^1.0.0",
"next": "^11.1.2"
}
ちなみに、このフレームワークがNextとして判定されない問題、AWS Amplify Consoleでリポジトリ連携後、Connecting a monorepo? Pick a folder.
にチェックを入れず、プロジェクトルートのpackage.jsonを参照させることでNextアプリとして判定させることはできるのですが、アプリをビルドする際にThe module 'react' was not found.
とNextアプリがnode_modules
を参照できずダメでした
さて、Nextアプリ配下のpackage.jsonのdependencies
としてnext
を追加しましたら、サービスロールをアタッチします
Create new role
から、基本デフォルト設定で問題ないはずです
サービスロールのアタッチが済みましたら、続いてビルド設定ですが、
デフォルトの設定ではビルドできないので、下記のamplify.ymlになるように編集します
修正版
version: 1
applications:
- frontend:
phases:
preBuild:
commands:
- npm install -g lerna
- cd ../../
- npm ci
- lerna bootstrap
build:
commands:
- cd packages/next-app-1
- npm run build
artifacts:
baseDirectory: .next
files:
- '**/*'
cache:
paths:
- node_modules/**/*
appRoot: packages/next-app-1
最後にAdvanced settings
です
環境変数のAMPLIFY_MONOREPO_APP_ROOT
とAMPLIFY_DIFF_DEPLOY
は自動で設定されているはずなので変更は加えませんが、staging環境などproduction以外の環境としてホスティングしたい場合は、こちらでAPIのホストやサードパーティのcredentialを設定すると良さそうです
また、バージョン11系のNext.jsを利用している場合は、Live package updates
でNext.js version
を選択し、Version
をlatest
にしましょう
こんな感じでOKなはずです
余談
- エラー周りのトラッカーとしてSentryを入れていたのですが、
@next/sentry
が入っていると、Starting SSR Build...
とログが表示された直後にエラーでビルドが落ちてしまいました。ホスティングを優先したかったので一旦@next/sentry
をdependencies
から消してビルドしましたが、Sentryを利用している場合は注意です。また、何かご存知の方いましたら教えていただけると幸いです
- 途中、試行錯誤の過程でlernaをやめてnpmのworkspacesで試したりもしていましたが、そちらはどうもビルドが上手くいきませんでした。npm workspacesベースのmonorepoでちゃんとSSRビルドできたよって方いましたら設定やamplify.ymlとか知りたいです...(lernaよりnpm workspacesの方がシンプルで良さそうな印象があり)
Discussion
追記
Nextアプリ配下のpackage.jsonの
dependencies
としてnext
を追加することで、next build
コマンドによるproductionビルドは問題なく成功します。しかし、開発環境で
next dev
コマンドによるビルドを行うとブラウザでHooks can only be called inside the body of a function component.
とエラーが表示されました。コンポーネントのトップレベル以外でhooksを呼び出すと見られるエラーではありますが、他の原因でも発現する場合があり、今回は、
のケースに該当しますので、コードを修正します。
next: <version>
の部分をnext: "link:../../node_modules/next"
に変更します。また、amplify.ymlの方も修正が必要です。
lerna bootstrap
コマンドにオプション--no-ci
を追加します。以上です