🐥

Vercelを使わずにAWSだけでNext.jsのISR対応!【serverless-next.js】

5 min read

追加の記事を作成しました。

https://zenn.dev/makumattun/articles/c091602d3060d3

※ 混乱させるかもしれないので一応、ところどころamplifyって出てきますが、apiの作成にamplify使っているだけで、デプロイとかにはホスティングにはamplify使ってないので。わかりにくくてすみません。

※現状では、bucketRegionを指定すると、エラーになってしまいます。
https://github.com/serverless-nextjs/serverless-next.js/issues/1111

解決済み

serverless-next.jsでISRに対応したNext.jsをデプロイのサポートが!ついに!

つい先日こちらのプルリクがマージされてました。

https://github.com/serverless-nextjs/serverless-next.js/pull/1028

まだα版ではありますが。

ということで、やってみました!

結論躓くことなくうまくいきました!
Vercel使わずにも生きていけるかも!

実際に試した構成

  • serverless-next.js 1.20.0-alpha4
  • Next.js
  • next-auth
  • aws-appsync
  • next-auth-dynamodb
package.json
{
  "name": "client",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "aws-appsync": "^4.0.3",
    "aws-sdk": "^2.907.0",
    "graphql-tag": "^2.12.4",
    "next": "10.2.0",
    "next-auth": "^3.23.0",
    "next-auth-dynamodb": "^0.3.3",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  },
  "devDependencies": {
    "@types/node": "^15.0.2",
    "@types/react": "^17.0.5",
    "typescript": "^4.2.4"
  }
}

すでにserverless-next.jsを使っている前提です。

変更点はこれだけ。

serverless.yml
next-serverless:
-  component: "@sls-next/serverless-component@1.18.0"
+  component: "@sls-next/serverless-component@1.20.0-alpha.4" 

serverless-next.jsを使ってない人向けに少しだけ補足

Serverless Frameworkというのがありまして、
それは主にawsのlambdaで何かしらサービスを作るときによく使われていて、似たようなサービスとしてはAWS samというサービスがあります。こちらはAWS公式です。

で、そのServerless Frameworkを作っているところが、結局Serverless Frameworkだけ作っていても、CloudFormationをゴリゴリ書いて関連するサービスを作る必要があるのでインフラまとめてよく使うものを提供できるようにServerless Componentというのを去年くらいにリリースしました。

ここにServerless Componentがまとまっています。
その中の一つで有志の方がserverless-next.jsというコンポーネントを作ってくれている感じです。

実際に使う際はclassmethodさんの記事など参考にして見てください。

確認したコード

こんな感じにstaticなページを生成しています。

todos/[id].tsx
// [id].tsx
import Head from "next/head";
import { useRouter } from "next/router";
import { DeleteTodoInput, GetTodoQuery, Todo, ListTodosQuery } from "../../API";
import { deleteTodo } from "../../graphql/mutations";
import { getTodo, listTodos } from "../../graphql/queries";
import { GetStaticProps, GetStaticPaths } from "next";
import styles from "../../../styles/Home.module.css";
import { SsrAppSyncApiKey, SsrAppSync } from "../../shared/ssr-graphqlclient";
import gql from "graphql-tag";
import { signIn, signOut, getSession, useSession } from "next-auth/client";

export const getStaticPaths: GetStaticPaths = async () => {
  const todosQuery = await SsrAppSyncApiKey().query({
    query: gql`
      ${listTodos}
    `,
  });

  // @ts-ignore
  const paths = todosQuery.data.listTodos.items.map((todo: Todo) => ({
    params: { id: todo.id },
  }));

  return {
    fallback: true,
    paths,
  };
};

export const getStaticProps: GetStaticProps = async ({ params }) => {
  console.log(params)
  const response = await SsrAppSyncApiKey().query({
    query: gql`
      ${getTodo}
    `,
    variables: {
      id: params.id
    }
  });
  console.log(getTodo)

  return {
    props: {
      // @ts-ignore
      todo: response.data.getTodo,
      date: new Date().toLocaleString(),
    },
    revalidate: 5,
  };
};

propsで渡したdateを表示してみて5秒間隔で更新されていることが確認できたのでISRはしっかり動作しているようです。画像なのでわからないと思いますが、リロードで変わる場合と変わらない場合はしっかり5sec間隔でした。

時刻が5secごとに変わる

まとめ

既存のソースコードを一切変えずに、ISRの動作が確認できました!
ただ、それまでと設定するIAM Roleの権限は修正する必要がありました。
実際に使っている権限はこんな感じです。いままではedgelambdaをstsのサービスの中身に入れる必要はなかったと思うけど。デプロイするときに怒られます。

信頼されたエンティティ
ID プロバイダー edgelambda.amazonaws.com
ID プロバイダー lambda.amazonaws.com
{
    "Statement": [
        {
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Action": [
                "s3:*"
            ],
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Action": [
                "dynamodb:Query",
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:Scan"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ],
    "Version": "2012-10-17"
}

権限ガバガバですみません。

Discussion

ログインするとコメントできます