$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

Next.jsでNot FoundページやISEページをカスタマイズする

https://nextjs.org/docs/advanced-features/custom-error-page を見て設定したが、特にstatusCode周りでハマったのでメモ。

  • pages/_error.tsxを作ると、SSR(Server Side Rendering)時やCSR(Client Side Rendering)時に例外が起きるなどした時やルーティングが存在しないエラーが発生した時に、そのページを表示してくれる
  • このページで400エラー、404エラー、500エラーをハンドリングして、自前のページを作成すれば良い
  • pages/_error.tsxはproduction環境時(next build -> next startした時)にしか使われないので注意。デバッグするときはnext buildをする必要がある
  • statusCode算出周りはハマりどころなので、自前でやったほうが良い場合がある
    • next/errorのgetInitialPropsではCSR時に例外が起きた時、err.statusCodeに何も入っていないという問題がある
    • 参考
  • next/errorによるとstatusCodeには400、404、405、500が入ってくるようなので、エラーページではそれらに対応すれば良い

pages/_error.tsxのサンプル

import React from 'react';
import { NextPage, NextPageContext } from 'next';

// production時(next buildの成果物を使っている時)のエラー表示に使われる
// See Also: https://nextjs.org/docs/advanced-features/custom-error-page

interface Props {
  statusCode: number;
}
const Error: NextPage<Props> = ({ statusCode }) => {
  // ここでエラーページをちゃんと構築する。statusCodeが400の時BadRequest、
  // 404/405の時Not Found、500の問Internal Server Errorが出るように正しく処理すれば良いだろう
  return <div>{statusCode}エラーが発生しました</div>;
};

Error.getInitialProps = async ({ res, err }: NextPageContext) => {
  // statusCodeを算出する。
  // - resが存在する時はSSRであり、res.statusCodeをそのまま利用すれば良い。
  // - resがない場合はCSRである。
  //   - err.statusCodeがあればそれをそのまま利用する
  //   - 意図しない例外が起きてerrがここに渡ってくる場合、単なるErrorオブジェクトが入っていてstatusCodeプロパティがない。errがある時点でISEなので500にする
  // See Also: https://nextjs.org/docs/advanced-features/custom-error-page
  const statusCode = res ? res.statusCode : err ? err.statusCode ?? 500 : 404;

  return { statusCode };
};

export default Error;

Next.js利用時の静的画像配信の方法

静的な画像を使いたくなったら、基本はnext-imagesを使っておけば良い。https://github.com/zeit/next-plugins でも紹介されている。

このライブラリはNext.jsを使う時のwebpackのfile-loaderの推奨設定を書いてくれているだけの薄いライブラリ。file-loaderを使っているので、画像を使いたいところではimportして使うと良い。詳しい使い方はnext-imagesのドキュメントを参照のこと。

実装は非常に薄いので、もし静的画像の配信周りでチューニングしたければ中身を拝借して自分好みに変えると良いだろう。

production環境での配信

next-imagesを使うことで、静的画像も配信できるようになる。しかしproduction環境ではNodeのプロセスから画像を配信せず、S3に静的ファイルを配置し、CloudFrontを経由して配信したくなるだろう。その場合はS3にファイルを配置した上で、フルCDNアーキテクチャCDNドメインを分けるアーキテクチャなどのアーキテクチャに応じて配信方法を変えると良い。

S3に静的ファイルをアップロードする

next buildすると.next/以下に成果物が作成される。特に静的ファイルは.next/static/以下に生成されている。この成果物はURLとしては /_next/static/ 以下から配信されている。

  • 例1) /_next/static/mxB2bTmDn1q4LbLd4s4qP/pages/index.js
  • 例2) /_next/static/images/image1-2ae516abfafa31abf108c359ca581b8c.jpg

そのため、.next/以下のファイルをS3に配置しておくと良い。もしかしたら.next/static/以下だけで良いかもしれないが、生成されている成果物のそれぞれのディレクトリごとの役割が把握しきれていないので、一旦全部アップロードしておく。

フルCDNアーキテクチャパターンでの配信

動的なページも含めて全て一度CDN(CloudFrontなど)を通る設計となっているなら、URLのpathベースでS3にルーティングしたら良い。すなわちCloudFrontなどで

  • /_next/配下へのリクエストならS3をオリジンとする
  • それ以外ならNext.jsが動くNodeプロセスをオリジンとする

CDNドメインが、アプリケーションのドメインと別の場合での配信

例えばCDNドメインcdn.example.com で、アプリケーションのドメインexample.comの場合、静的ファイルのURLのドメインCDNドメインにする必要がある。この場合は、assetPrefixを設定することで対応できる。

エリック・エヴァンズのドメイン駆動設計読んだ

読んだ。

エンティティ、値オブジェクト、集約など、自分の中でなんとなくの理解になっていたところを、より具体的に言語化出来たことが良かった。一方、用語が難解なため理解が難しく、既に経験則でなんとなく理解していることを言語化する役には立ったが、新しい知識を習得できたという実感はないことが残念だった。なぜDDD初心者はググり出してすぐに心がくじけてしまうのか - little hands' labの記事を読んだとき「分かる分かる」って感じだったので、「実践ドメイン駆動設計」をまた読んでみようと思う。

読書ノート

* 4つのレイヤ 1938
    * プレゼンテーション層
    * アプリケーション層
    * ドメイン層
    * インフラストラクチャ層
* エンティティ: 主に同一性によって定義されるオブジェクト 2314
* 値オブジェクト: ドメインにおける記述的な側面を表現し、概念的な同一性を持たない場合、そういうオブジェクトは値オブジェクトと呼ぶ 2459
* サービス: 2615
    * モデルにおいて独立したインターフェースとして提供される操作で、状態をカプセル化していない
    * クライアントに対して何が実行できるかという観点から定義
    * 名詞でなく動詞的
* 優れたサービスの特徴 2639
    * 操作がドメインの概念に関係しており、その概念がエンティティや値オブジェクトの自然な一部ではない
    * ドメインモデルの他の要素の観点からインターフェースが定義されている
    * 操作に状態がない
* 集約: 関連するオブジェクトの集まりであり、データを変更するための単位 3102
    * 集約のルートのエンティティを決め、内部へのオブジェクトのアクセスはそれ経由にして制御する
    * ルートエンティティは集約内での不変条件も管理する
* 意図の明白なインターフェース 5310
    * ユビキタス言語を使って、クラスと操作にはその効果と目的を記述する名前をつけることで、利用者に意図を表明する
* リファクタリングのタイミング 6715
    * 設計が、ドメインに関するチームの現在の理解を表現していない
    * 重要な概念が設計で暗黙的になっている(かつ、それを明示的にする方法が分かっている)
    * 設計において重要な部分を、よりしなやかにする好機がある