Next.js 13.3まとめ
基本的には以下のNext.js 13.3のブログを翻訳してまとめたものになります。
TL;DR
- ファイルベースのメタデータAPI: サイトマップ、robots、ファビコンなどの動的な生成
- 動的なOG画像: ビルトインのJSXとHTML、CSSを使用したOG画像の生成
- Appルーターの静的エクスポート対応: サーバーコンポーネントの静的サイト・SPA対応
- 並行ルートと横取りルート: Appルーターの拡張的なルーティングの機能
また、Appルーターは次のマイナーリリースで安定版になる予定のようです。ついにですね。
アップデート詳細
ファイルベースのメタデータAPI
Next.js 13.2で登場した設定ベースのメタデータAPIに加えて、ファイルベースのメタデータAPIとして以下の新しいファイル規約に対応しました。
opengraph-image.(jpg|png|svg)
twitter-image.(jpg|png|svg)
favicon.ico
icon.(ico|jpg|png|svg)
sitemap.(xml|js|jsx|ts|tsx)
robots.(txt|js|jsx|ts|tsx)
manifest.(json|js|jsx|ts|tsx)
以下の例では、アプリケーション全体にファビコンを設定し、/about
ページにOG画像を追加で設定しています。
そして、Next.jsはキャッシュのためにハッシュ付きのファイルを本番環境で自動的に提供し、関連するhead
要素をアセットのURL、ファイルタイプ、画像サイズなどの適切なメタデータ情報で更新します。
app
├── favicon.ico
├── layout.js
├── page.js
└── about
├── opengraph-image.jpg
└── page.js
// Visiting "/"
<link rel="icon" href="<computedUrl>"/>
// Visiting "/about"
<link rel="icon" href="<computedUrl>"/>
<meta property="og:image" content="<computedUrl>" type="<computedType>" ... />
また、静的なファイルを追加するだけではなく、.js|.jsx|.ts|.tsx
のファイルを使用して動的なファイルを追加することもできます。
以下の例では、外部のデータソースを使用して動的に生成されたページを持つサイトで動的にサイトマップを生成するために、sitemap.js
を追加し、動的なルートの配列を返しています。
export default async function sitemap() {
const res = await fetch('https://.../posts');
const allPosts = await res.json();
const posts = allPosts.map((post) => ({
url: `https://acme.com/blog/${post.slug}`,
lastModified: post.publishedAt,
}));
const routes = ['', '/about', '/blog'].map((route) => ({
url: `https://acme.com${route}`,
lastModified: new Date().toISOString(),
}));
return [...routes, ...posts];
}
設定ベースとファイルベースのメタデータAPIを組み合わせることで、静的・動的両方のメタデータに対応することができます。
動的なOG画像の生成
Next.jsではこれまでも@vercel/og
をインストールして、APIルートで@vercel/og
からImageResponse
をインポートすることで動的なOG画像の生成ができました。
Next.js 13.3では@vercel/og
をインストールしなくても、ルートハンドラーやファイルベースのメタデータAPIを含むNext.js APIでnext/server
からImageResponse
をインポートすることで動的なOG画像の生成ができるようになりました。
import { ImageResponse } from 'next/server';
export const size = { width: 1200, height: 600 };
export const alt = 'About Acme';
export const contentType = 'image/png';
export default function og() {
return new ImageResponse();
// ...
}
Appルーターの静的エクスポート対応
Appルーターが静的エクスポートに対応しました。
next.config.js
でoutput: 'export'
を指定してnext build
を実行すると、Next.jsはルートごとのHTMLファイルを生成します。厳格なSPAを個々のHTMLファイルに分割することで、Next.jsはクライアントサイドで不要なJavaScriptコードの読み込みを回避し、バンドルサイズを小さくしてページの読み込みを高速化できます。
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
output: 'export',
};
module.exports = nextConfig;
静的エクスポートは静的ルートハンドラーやOG画像、Reactサーバーコンポーネントを含むAppルーターの新機能と連携します。
例えば、サーバーコンポーネントは、従来の静的サイト生成と同様に、ビルド中に実行され、コンポーネントを最初のページの読み込みのための静的HTMLとルート間のクライアント遷移のための静的ペイロードにレンダリングします。
並行ルートと横取りルート
並行ルートでは、独立して遷移される同じビューで1つ、または複数のページを同時にレンダリングすることができます。また、条件付きでページをレンダリングすることもできます。
並行ルートは名前付きの "スロット" を使用して作成し、スロットは@folder
の規約で定義します。
dashboard
├── @user
│ └── page.js
├── @team
│ └── page.js
├── layout.js
└── page.js
そして、同じルートセグメントのレイアウトは引数としてスロットを受け取ります。
export default async function Layout({ children, user, team }) {
const userType = getCurrentUserType();
return (
<>
{userType === 'user' ? user : team}
{children}
</>
);
}
上記の例では、明示的な並行ルートのスロットである@user
と@item
は任意のロジックに基づいて条件付きでレンダリングされます。ここでchildren
は@folder
へ対応される必要がない暗黙のルートのスロットです。例えば、dashboard/page.js
はdashboard/@children/page.js
と同等です。
横取りルートでは、ブラウザのURLを"マスキング"しながら現在のレイアウト内で新しいルートを読み込むことができます。これは、モーダルでフィードの写真を展開するとフィードがモーダルの背景に保持されるなど、現在のページのコンテキストを維持することが重要な場合に、便利です。
横取りルートは、相対パス(../
)と同様に、(..)
の規約で定義されます。また、(...)
の規約を使用して、app
ディレクトリへの相対パスを作成することもできます。
feed
├── @modal
│ └── (..)photo
│ └── [id]
│ └── page.tsx
├── page.tsx
└── layout.tsx
photo
└── [id]
└── page.tsx
上記の例では、ユーザーのプロフィールから写真をクリックすると、Instagramのようにクライアントサイドの遷移中にモーダルで写真が開かれます。しかし、ページをリロード、またはシェアした場合は通常のレイアウトで写真が読み込まれます。
これは、モーダルのコンテンツをURLでシェアできるようにしたり、ページがリロードされた際にコンテキストが失われるのを防いだり、戻る・進むの遷移でモーダルを閉じたり開いたりするなどの、モーダルを作成する際のいくつかの課題を解決します。
その他のいくつかの改善
-
next.config.js
のファストリフレッシュ:next.config.js
の変更を契機にローカルの開発サーバーを自動的に再起動します。 -
create-next-app
のオプションにTailwind CSSを追加:npx create-next-app@latest
で新プロジェクトを立ち上げる際、Tailwind CSSを任意で選択することができます。 - ルーティングから特定のフォルダを除外: フォルダの先頭に
_
を付けると、ルーティングからそのフォルダと子セグメントを除外することができます。例えば、app/_dashboard/page.tsx
はルーティングされません。 - Appルーターに
useParams
を追加: 与えられたルートセグメントの動的パラメータを読み取るための新しいuseParams
クライアントコンポーネントフックが追加されました。詳しくはこちら。 - Not Foundの取り扱いの改善: 予想される
notFound()
エラーを捕捉するだけでなく、ルートのapp/not-found.js
ファイルはアプリケーション全体の一致しないURLを捕捉します。これは、アプリケーションで取り扱われていないURLを訪れたユーザーにapp/not-found.js
ファイルでエクスポートされたUIを表示することを意味します。詳しくはこちら。 - など
Discussion
失礼します。
intercepting に関してですが、通信の傍受、サッカーでのパスをカットするプレーを指して使われるように、二者の「間」に割り込んで彼らが渡そうとしてるモノを「取る」ニュアンスがある単語だと思います。
↓の解説を考えに入れると、photo/[id]/page.tsx から
photo/[id]
というルートを 「横取り」してレンダリングされる、というニュアンスに思えるので、「遮断」だけでは不足していて「横取り」「割り込み」のようなニュアンスがある単語のほうが的確に挙動を表しているかと思います。ご指摘ありがとうございます。
Intercepting Routesの訳語についてはまさに悩んでいたので、納得のご指摘でした。
コメントとツイートを拝見した上で、単語の意味を調べ直して、「横取りルート」が挙動を表すもっともらしい訳語ではないかと思ったので、そちらで修正させていただきます。
対応ありがとうございます!わずかでも協力できて光栄です!