🤔

CloudFront + S3 で対峙する初歩的なエラー:_next 配下呼ばれないぞ、、

2024/06/08に公開

内容

今回の投稿はFLINTERSブログ祭りの記事です。テーマは #CloudFront #S3 #SPA です。

CloudFront + S3 構成でフロントページにアクセスした際、_next配下が読み込まれなかった際の初歩的なエラーとそれに伴う今後の展望への備忘録を記載します。

今回の事象の背景

  • Next.js 13 を用いてCSRでフロントページを作成
  • システム構成
    • フロントページのビルドファイルは、S3バケットAに配置する
    • CloudFrontの設定にて
      • /hoge の場合、S3バケットAに遷移させる
      • /huga の場合、S3バケットAに遷移させる
      • それ以外のパスはALBへ遷移させる

エラーが起きるまでの手順

  1. Next.js 13 でCSRを用いてフロントページ作成
  2. next.config.js にて、output: 'export'を指定したのち、next buildを実行し、ビルドファイル(out配下のファイル群)を生成
  3. S3バケットAへout配下のファイル群を配置
  4. CloudFrontの設定にて /hoge, /huga に対して、S3バケットAへ遷移するように設定(S3バケットのポリシー設定もする)
  5. 今のままでは、/hoge/index.htmlでは画面描画できるはずだが、/hogeや/hoge/、/hugaや/huga/では描画できないので、CloudFront Functionsで下記のように設定
async function handler(event) {
    const request = event.request;
    const uri = request.uri;
    
    // Check whether the URI is missing a file name.
    if (uri.endsWith('/')) {
        request.uri += 'index.html';
    } 
    // Check whether the URI is missing a file extension.
    else if (!uri.includes('.')) {
        request.uri += '/index.html';
    }

    return request;
}
  1. デフォルトのパス(*)にて、ALBへ遷移するように設定
  2. https://example.com/hoge のようなURLへアクセスした際、画面が描画されない
    • _next/配下がALBの方に向かっていた

エラー内容

_next/配下がALBに向かっていたのは、ビルドファイルのhoge/index.htmlを見ると明らかで、例えば<script src="/_next/static/chunks/xxxxxx.js"></script>のように、src先が絶対パスになっている。

そのため、/_next/static/chunks/xxxxxx.js は https://example.com/_next/static/chunks/xxxxxx.js に遷移してしまう。

エラー対処法

CloudFrontの設定で、/_next/* に対して、S3バケットAを指定してあげれば良い。

今後の懸念点

想定展開

今後、フロントページを増やす際、今回とは別で切り出してフロントページを構築し、別S3バケットBへビルドファイルを格納したいとなった場合のCloudFront設定を少し懸念している。

例えば、現状は下記のようになっているが、今後[懸念]にもあるように、/piyoに対して新たなS3バケットを指定したいとなった時に、/_next/* に指定するS3バケットをどうするか、という問題がある。

現状

- /hoge
  - S3バケットA
  - CloudFront Functions A
- /huga
  - S3バケットA
  - CloudFront Functions A
- /_next/*
  - S3バケットA
- *  
  - ALB

今後[懸念]

- /hoge
  - S3バケットA
  - CloudFront Functions A
- /huga
  - S3バケットA
  - CloudFront Functions A
- /piyo
  - S3バケットB
  - CloudFront Functions A(Aと内容は同じなので、Aを指定) 
- /_next/*
  - S3バケットA? S3バケットB? // ここが懸念点
- *  
  - ALB

解決策?

next.config.js にて、assetPrefix を指定すると、ビルドしたindex.htmlのリンク先が変更になる。
参考:https://nextjs.org/docs/app/api-reference/next-config-js/assetPrefix

例えば、assetPrefix="/a" とすると、index.htmlの内容が<script src="/a/_next/static/chunks/xxxxxx.js"></script>のようになる。

そのため、
フロントページA(/hoge, /huga)のものは、assetPrefix="a"
フロントページB(/piyo)のものは、assetPrefix="b"

とし、新たな_next配下用のS3バケットCを作成し、
/a パスに フロントページAの _nextディレクトリを、
/b パスに フロントページBの _nextディレクトリを配置すれば良いのではと考えている

今後[解決策?]

- /hoge
  - S3バケットA
  - CloudFront Functions A
- /huga
  - S3バケットA
  - CloudFront Functions A
- /piyo
  - S3バケットB
  - CloudFront Functions A(Aと内容は同じなので、Aを指定) 
- /a/_next/*
  - S3バケットC
- /b/_next/*
  - S3バケットC
- *  
  - ALB

どなたか良い解決策があったら教えてくださいm

Discussion