🎣

Serverless Next.js Component のISR実装を読み解く

2021/08/03に公開

AWS Amplify ConsoleでNext.jsのプロジェクトをデプロイすると Serverless Next.js Component のインテグレーションによってAWS Lambda リソースが最大4つ作成される(ソースコードはエクスポートできる)

  • Default Lambda@Edge for Next CloudFront distribution
  • API Lambda@Edge for Next CloudFront distribution
  • Image Lambda@Edge for Next CloudFront distribution
  • Next.js Regeneration Lambda

それぞれのAWS Lambdaが行っていることを読み解くとVercelが自社で構成しているシステムの外観が分かるのではないかと思って眺めてみた


(CloudFrontのコンソールでどのパスで呼び出されているのかわかる)

Default Lambda@Edge

serverless-next.js/default-handler.ts at serverless-nextjs/serverless-next.js

  • 静的なレスポンスを返せる場合はS3 bucketからアセットファイルを読み取りレスポンスを返す
  • SSRが発生する場合はHTMLのレンダリングまでをこのLambdaのコンテキストで行う
  • ISRの処理が発生する場合このLambdaが "Next.js Regeneration Lambda" を着火させるためのSQSにメッセージを送信する

API Lambda@Edge

serverless-next.js/api-handler.ts at serverless-nextjs/serverless-next.js

  • API Routes用のLambda
  • シンプルに該当するパスのNode.jsスクリプトが実行されるだけ

Image Lambda@Edge

serverless-next.js/image-handler.ts at serverless-nextjs/serverless-next.js

  • next/image 専用のLambda
  • 内部的には sharp を使って画像をオプティマイズしている
  • 対象のURLがビルド済みのS3 bucketにあるファイルではなくインターネット上の画像ならこのタイミングで fetch() してダウンロードする

Next.js Regeneration Lambda

serverless-next.js/regeneration-handler.ts at serverless-nextjs/serverless-next.js

  • ISRを実現するバックエンド
  • こいつだけ仲間外れでCloudFrontからではなく他のLambdaがSQSに送信したメッセージを受信することで実行される
  • やっていることは次のレスポンス用にSSGした結果をS3 bucketに書き出しておくのが主
  • ここで作成されたレスポンス結果のHTMLファイルに revalidate から計算されたExpire する時刻がメタ情報にセットされて、Default Lambda@Edgeはリクエストを返す時についでにそれを参照して再生成の命令をSQSへ出すのか決める

まとめ

  • 思ったよりシンプル。アプリケーション開発者としては packages/libs/lambda-at-edge/ を理解するだけでよさそう
  • Serverless ComponentはServerless Frameworkのプラグインみたいなものかと思っていたけど違った。単体で使えるようにしたツールという位置付けだった
  • デプロイ処理を見る時は packages/serverless-components/nextjs-component を参照する。Nextプロジェクトの構造を解析して適切なAWSリソースを作成してくれている。ここを読んでいたら自分のアプリケーションでうまく動作しない問題を発見できた
  • GitHubスターが2.5kもあるのにコントリビューター全然いなくて困ってるらしい

Discussion