Next.js 13.2まとめ
基本的には以下のNext.js 13.2のブログを翻訳してまとめたものになります。
TL;DR
- ビルトインSEOサポート: 静的、動的に
meta
タグを設定するための新しいMetadata API - ルートハンドラー: Webの
Request
とResponse
に基づくカスタムリクエストハンドラー - MDXのサーバーコンポーネント対応: マークダウン内部でサーバーサイドのみで動くReactコンポーネントを使用
- Rust製MDXパーサー: 全く新しいRust製プラグインによるマークダウンパースの高速化
- エラーオーバーレイの改善: 可読性を改善するためにNext.jsとReactのスタックトレースを分離
- 静的に型付けされたリンク(ベータ):
next/link
とTypeScriptによる壊れたリンクの防止 - Turbopackのいくつかの改善(アルファ): Webpackローダーとの互換性とサポートを改善
- Next.jsキャッシュ(ベータ): 進歩的なISRとコード変更時の再デプロイの高速化
アップデート詳細
新しいMetadata APIによるビルトインSEOサポート
これまでapp
ディレクトリではhead.js
にmeta
タグを記載していましたが、page.js
、またはlayout.js
にNext.jsが定義したMetadata
オブジェクトを記載する形式になりました。
Metadata
オブジェクトが静的な場合はmetadata
変数として、Metadata
オブジェクトが動的な場合はgenerateMetadata
関数としてexportすることでmeta
情報を付与できます。
export const metadata = {
title: '...',
description: '...',
};
export async function generateMetadata() {
...
return {
title: '...',
description: '...',
};
};
また、head.js
はNested Layoutsに対応しておらず、全てのページで共通の内容も全てのhead.js
に書く必要がありましたが、Metadata APIはNested Layoutsに対応しており、Metadataはルートからマージされていきます。
詳細は以下のページで確認できます。
カスタムルートハンドラー
これまでapp
ディレクトリではAPI Routes(pages/api
)相当の機能がありませんでしたが、新たに追加されました。
page.js
やlayout.js
のようにroute.ts
を定義して、大文字のHTTPメソッドを関数名とした関数としてexportすることで対応するHTTPメソッドのエンドポイントを作成できます。
export async function GET(request: Request) {
...
};
ただし、同階層にpage.js
が存在する場合は使用できません。
詳細は以下のページで確認できます。
MDXのサーバーコンポーネント対応
MDXがサーバーコンポーネントに対応しました。
動的なUIをテンプレート化するReactの強力な機能を維持しながら、クライアントサイドJavaScriptを減らしてページロードを高速化できます。
@next/mdx
プラグインがアップデートされ、カスタムコンポーネントを提供するためにアプリケーションのルートで定義される新しい特別なファイル、mdx-components.js
をサポートするようになりました。
// このファイルはMDXファイルで使用されるカスタムReactコンポーネントを提供します
// 他のライブラリを含む、あらゆるReactコンポーネントをimportして使用することができます
function H1({ children }) {
...
};
function H2({ children }) {
...
};
export function useMDXComponents(components) {
return { h1: H1, h2: H2, ...components };
};
詳細は以下のページで確認できます。
Rust製MDXパーサー
MDXのサーバーコンポーネント対応の一環として、パフォーマンスを改善するためにMDXパーサーがRustで書き換えられ、大量のMDXファイルを処理する際に顕著な速度低下が見られた、以前のJavaScriptベースのパーサーと比較して大幅に改善されました。
next.config.js
でRustパーサーの使用をオプトインすることができます。
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
mdxRs: true,
},
};
const withMDX = require('@next/mdx')();
module.exports = withMDX(nextConfig);
エラーオーバーレイの改善
Next.jsとReactのスタックトレースが分離され、エラーの発生箇所を容易に特定することができるようになりました。さらに、エラーオーバーレイに現在のNext.jsのバージョンが表示されるようになり、バージョンが最新であるかどうかわかりやすくなりました。
静的に型付けされたリンク
next/link
を使用する際に、タイプミスなどのエラーを防ぐためにapp
ディレクトリのリンクが静的に型付けされるようになりました。
next.config.js
で静的に型付けされたリンクの使用をオプトインすることができます。
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
typedRoutes: true,
},
};
module.exports = nextConfig;
詳細は以下のページで確認できます。
Turbopackのいくつかの改善
Turbopackは現在アルファですがベータに向けて、Next.jsの既存機能をサポートし、全体的な安定性を改善することに注力してきたようです。
前回のリリースから以下が追加されています。
-
next/dynamic
に対応 -
next.config.js
のrewrites
とredirects
、headers
、pageExtensions
に対応 -
pages
の404とエラーに対応 - CSS Modulesの
compose: ... from ...
に対応 - Fast Refreshの信頼性とエラーからの復旧の改善
- CSSの優先順位の取扱いの改善
- コンパイル時の評価の改善
Webpackのローダーを使用したカスタムファイル変換
TurbopackはいくつかのWebpackのローダーへのサポートと互換性を開始しました。これにより、様々な種類のファイルをJavaScriptへ変換するために、Webpackのエコシステムから多くのローダーを使用できるようになります。サポートされるローダーやTurbopackのカスタマイズの詳細は以下のページで確認できます。
例えば、以下のようにnext.config.js
のexperimental.turbo.loaders
を使用して、各ファイルの拡張子に対するローダーのリストを設定します。
module.exports = {
experimental: {
turbo: {
loaders: {
'.md': [
{
loader: '@mdx-js/loader',
options: {
format: 'md',
},
},
],
'.svg': ['@svgr/webpack'],
},
},
},
};
ローダーを使用したTurbopackの完全な例は以下のページで確認できます。
Webpackスタイルのエイリアス解決
TurbopackはWebpackのresolve.alias
と同様に、エイリアスを使用してモジュール解決を行うように設定することができるようになりました。
例えば、以下のようにnext.config.js
のexperimental.turbo.resolveAlias
を使用して、設定します。
module.exports = {
experimental: {
turbo: {
resolveAlias: {
underscore: 'lodash',
mocha: { browser: 'mocha/browser-entry.js' },
},
},
},
};
Next.jsキャッシュ
ISRを進化させた新しいNext.jsキャッシュ(ベータ)が導入され、以下を実現します。
- コンポーネントレベルの進歩的なISR
- ネットワークリクエストなしでリフレッシュの高速化
- 静的ページへのコード変更時の再デプロイの高速化
完全に静的なページについてはISRはこれまでと同じように動作します。静的と動的が混在する、よりきめ細やかなデータフェッチが必要なページについてはNext.jsキャッシュはよりきめ細やかで、短期間のキャッシュを使用します。
Reactのサーバーコンポーネントの基盤とNext.jsのapp
ディレクトリでデータフェッチをコロケートする(一緒に書く)ことで、静的、または動的なデータをそれらを使用するコンポーネントのそばにカプセル化することができます。
export default async function Page() {
const [staticData, dynamicData, revalidatedData] = await Promise.all([
// 手動で無効にされるまでキャッシュされます
fetch(`https://...`),
// リクエストごとに再フェッチされます
fetch(`https://...`, { cache: 'no-store' }),
// 10秒間の有効期限でキャッシュされます
fetch(`https://...`, { next: { revalidate: 10 } }),
]);
return <div>...</div>;
}
app
ディレクトリでローカル開発している間、next dev
でnext start
を使用した本番環境と同様のキャッシュの振る舞いを確認できるようになります。これまでnext dev
ではキャッシュの振る舞いは確認できなかったので、これは非常に便利ですね。
Next.jsキャッシュでは、サードパーティのAPIではなく、アプリがキャッシュを制御します。これはcache-control
ヘッダーとは異なり、より上流で値がキャッシュされる期間を制御します。
Next.jsキャッシュによって、キャッシュの単位がページから一つ一つのデータになることで、よりきめ細やかなキャッシュの制御が可能になる一方で、難易度や複雑性は飛躍的に向上しそうですね。
詳細は以下のページで確認できます。
その他のいくつかの改善
- フォント:
@next/font
がnext/font
としてNext.jsにビルトインされ、@next/font
を別々にインストールする必要がなくなりました - パフォーマンス: エラーコンポーネントを最適化し、スタイルの変更なしでHTMLのペイロードを0.4KB削減しました
- など
Discussion