先日、Amplify ConsoleでNext.jsのSSRアプリがホスティングできる機能が発表された。
公式ブログ
Host a Next.js SSR app with real-time data on AWS Amplify
実際はSSR, SSGのどちらかをpackage.jsonから判断するらしい。
Deploy and host server-side rendered apps with Amplify
When you deploy a Next.js app, Amplify inspects the app's build script in the package.json file to detect whether the app is SSR or SSG.
Next.jsを触ったことがなかったので、サンプルアプリをAmplify Consoleで動かしてみた。基本的に上記のブログに沿ってやってみて、時折上記の公式ドキュメントを参照する。自分が再度試したくなった時にコピペでできるのが理想。
注意点
いずれも上記のドキュメントに書いてある。
- SSRはマニュアルデプロイには対応していないのでレポジトリ連携が必要
- Next.js10には対応していないので、version9に落とした方がいい。10もできはするらしいがフルサポートではないとのこと。
ローカルでサンプルアプリを動かす〜CodeCommitへのpushまで
- Amazon Linux 2のEC2インスタンスを起動。接続はVSCodeのRemote Developmentで。便利。
- CodeCommitのロール作成とかの準備
- Nodeを入れる
- ここから公式ブログの内容に入っていく。
npx create-next-app
をするとサンプルアプリが出来上がる。 ただし、Next.jsのバージョンが10なので9に落とさないといけない。公式ではないがこちらの記事も参考になり、バージョンを真似させてもらった。サンプルアプリのpackage.json
を一部以下のように書き換える。
"dependencies": {
"next": "9.5.5",
"react": "16.12.0",
"react-dom": "16.12.0"
}
この状態でnpm install
してダウングレード -> npm start
。
pages/index.js
のImage
という機能がバージョン10からの機能らしくエラーを吐いたので、関連する行を安直に消して再度npm start
したら動いた。
5. push
git init
git add .
git commit -m "comment"
git push --set-upstream レポジトリのURL master
ホスティング
上記のブランチをAmplify Consoleに接続する。コンソールから新しいアプリを作って上記のブランチを選択するとビルドの設定などが自動生成される。
デプロイに使用するロールを選択する必要があり、今まで使っていた既存のロールを選択したところAccess Deniedのエラーが出てビルドに失敗した。
2021-06-05T04:43:22.686Z [INFO]: Starting SSR Build...
2021-06-05T04:44:29.259Z [INFO]: AccessDenied
AdministratorAccessの権限でロールを新規作成してそっちを使ったら成功した。
できたものを確認。
大きな特徴は以下。
- CloudFrontが自分のアカウントにできる
- Lambda@Edgeがサーバーの役割を果たして処理を行う。ドキュメントにも記載あり。そのため、
console.log()
はLambda@Edgeのログとして出力される - (これはLambda@Edgeの特徴) Lambda@Edgeはus-east-1にできるが、CloudWatchログはアクセスされたエッジロケーションがあるリージョンにできる。日本からの場合には大体ap-northeast-1をみとけば良さそう。公式ではないがこの記事に救われた。全く知らなかった。
ちょっと処理足した
処理をどこに書けばいいかわからないので、とりあえずテンプレート化したい。先程の外部記事も参考にして、npx create-next-app
でできたコードを以下のようにちょこっと編集すると好きな処理をかけるようになる。
import Head from 'next/head'
import styles from '../styles/Home.module.css'
import Link from "next/link";
export default function Home() {
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>
Welcome to <a href="https://nextjs.org">Next.js!</a>
</h1>
<p>
<Link href="/handler">
<a>処理するボタン</a>
</Link>{" "}
</p>
</main>
</div>
)
}
以下を新規作成。getServerSideProps()
は文字列を返す決まりなのか?とりあえず試してうまくいったのは以下だけど、JSONをそのまま返した場合にList側でどういういじり方ができるのかはわからない。
// import AWS from "aws-sdk";
const List = ({data}) => {
return(
<>
list: {data}
</>
)
}
export const getServerSideProps = async () => {
const res = // 何かしらJSONが返ってくる処理
const data = JSON.stringify(res);
return {props:{data}};
}
export default List;
まとめ
- Lambda@Edgeで処理していた
- Next.jsのサンプルアプリをホスティングして、適当な処理がかけるボタンを置きました。
おまけ: 認証に関して
僕は今回試していないが、withSSRContext()
を使えばCognitoの認証情報をサーバー側で使える。これはAmplifyのドキュメントに書いてあり、普通のReactアプリをホスティングするときとほぼ同様の操作で認証情報を使えそう。