Skip to content

Instantly share code, notes, and snippets.

@yano3nora
Last active August 7, 2023 18:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yano3nora/ed6fd1ef0f75e904f9f0f0d368aa1c1f to your computer and use it in GitHub Desktop.
Save yano3nora/ed6fd1ef0f75e904f9f0f0d368aa1c1f to your computer and use it in GitHub Desktop.
[dev: Amplify + Next.js (SSR)] Deploy Next.js on Amplify hosting. #dev #js #aws

Overview

Deploy and host a hybrid app (SSG and SSR)
Deploy server-side rendered apps with Amplify Hosting

ざっくり、Next.js を S3 + CloudFront 構成上に upload して、バックエンド処理をルーティングに応じた Lambda@Edge でなんとかするっていう思想のよう。

  • amplify の hosting 機能で next.js を SSG + SSR 構成で deploy できる
    • ファイル検査の関係上 Git の CI/CD を利用する必要がある
    • manually deploy は非対応なのかな?
  • 最近 v13 にも対応した
  • サーバサイド (pages/api/*getServerSideProps) は Lambda@Edge
    • backend の諸々制限はすべて Lambda@Edge に依存するので注意
    • Aurora Serverless v2 の Data API や RDS Proxy で RDB 接続イケそう?
  • SSG or SSR は package.json > scripts > build を検査して判別
    • SSR: "build": "next build" & dist dir .next/
    • SSG: "build": "next build & next export" & dist dir .out/

lambda@Edge のログ

Access Lambda Edge Logs

  1. ビルド履歴の「デプロイ」で lambda@edge の id 確認
    • CI の履歴見る画面、URL が https://ap-northeast-1.console.aws.amazon.com/amplify/home?region=ap-northeast-1#/${APP_ID}/${BRNCH}/${NUMBER} のとこ
  2. cloudwatch logs で log group に ↑ id のやつがいるはずなので検索
    • もしいなかったら別 region だとおもう
    • lambda console から id で関数検索 => cloudwatch logs の遷移でも ok

ビルド設定 > パッケージバージョン設定

Next.jsをAmplifyで運用する場合に必ず設定すべき項目

default が latest になっているので、使う nextjs の version を指定しておかないと、将来 latest が変わったときに困る。

環境変数 / amplify.yml / .env ファイル

環境変数はLambda関数に引き継がれません

  • amplify の next.js デプロイ時の SSR では環境変数 (process.env) 参照ができない
  • ので環境変数まわりは .env.local に寄せて、git 管理せずに ↓ のようにするのが一旦の回避策
    • 開発環境では amplify console 参考にしつつ自前で作成
    • 本番環境や sandbox 環境ではデプロイ時の build フェーズで環境変数をバラして .env.local を動的生成
# .env.local
NEXTAUTH_URL=http://localhost:3000
# .env.amplify.example
NEXTAUTH_URL=${NEXTAUTH_URL}

amplify console で環境変数を設定 ... ref. https://zenn.dev/thim/articles/04775c68d796445f3c90

version: 1
backend:
  phases:
    build:
      commands:
        - '# Execute Amplify CLI with the helper script'
        - amplifyPush --simple
frontend:
  phases:
    preBuild:
      commands:
        - npm ci
        # ↑ で設定した環境変数を評価済みの .env を生成して
        # lambda@edge での実行時に参照してもらう
        # .env.local だと動かない? => https://zenn.dev/yano3nora/scraps/2d04df776cf75a
        - cat .env.amplify.example | envsubst > .env.production
    build:
      commands:
        - npm run build
  artifacts:
    baseDirectory: .next
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*

別ブランチを接続したあとの amplify pull

add hosting から ci 組んだあと、別ブランチを接続して新しい backend env が生成される。このとき local の amplify project には生成された新しい env が sync されないので、手動で pull してきてやる必要がある。

$ amplify pull --appId xxx --envName main

public/static 予約フォルダがある

https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/server-side-rendering-amplify.html#amplify-reserved-path

api/ routing が 503 error

nextjs v12 で起きた、対応バージョンは v11.3 が 2022.03 時点の最新だったのでただのミス、down grade するだけ。

SSR with Cookie

Getting Started with Server-Side Rendering (SSR)
Next.js + TypeScript + AWS Amplify でアプリケーション開発

amplify の auth (Cognito) や api (AppSync の GraphQL サーバ) を call するなど、SSR 時点の Web API call に client からの request context (認証情報含む cookie とか) を渡したいときは、↓ のように設定すればおk。

/**
 * pages/_app.js にて aws-exports.js を読み込みつつ
 * Amplify.configure に ssr: true の設定が必要だよ
 *
 * これで cookie を介してサーバ側にクライアントの資格情報が渡るっぽい
 */

import Amplify, { API, Auth, withSSRContext } from 'aws-amplify';
import awsExports from "../src/aws-exports";

Amplify.configure({ ...awsExports, ssr: true });

// ...

export const getServerSideProps = async ({ req }) => {
  const SSR = withSSRContext({ req });
  
  // この graphql server への問い合わせに cookie が乗る
  const response = await SSR.API.graphql({ query: listPosts });

  return {
    props: {
      posts: response.data.listPosts.items,
    },
  };
}

const Home = ({ posts = [] }) => {
  return <p className={styles.grid}>
    {posts.map(post => /* ... */)}
  </p>
}

export default Home
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment