コンテンツにスキップ
ブログに戻る

2023年2月23日 木曜日

Next.js 13.2

投稿者

Next.js 13.2 には、安定化に向けた App Router (app) の大幅な改善が含まれています。

本日、実行してアップデートしてください

ターミナル
npm i next@latest react@latest react-dom@latest eslint-config-next@latest

新しいメタデータ API による組み込み SEO サポート

Next.js は、最初から検索エンジンでの最適化を可能にするように設計されています。

プリレンダリングされた HTML コンテンツを提供することは、検索エンジンでのインデックス作成を向上させるだけでなく、アプリケーションのパフォーマンスも向上させます。Next.js は長年、アプリケーションのメタデータを変更するための簡単な API (next/head) を提供してきましたが、App Router (app) を使用して検索エンジンの最適化を行う方法を再設計・強化したいと考えました。

新しいメタデータ API では、Server Component であるレイアウトまたはページに明示的なメタデータ設定を使用して、メタデータ(例:HTML の head 要素内の meta および link タグ)を定義できます。

app/layout.tsx
import type { Metadata } from 'next';
 
export const metadata: Metadata = {
  title: 'Home',
  description: 'Welcome to Next.js',
};

この API はシンプルで、 composable であり、ストリーミングサーバーレンダリングとの互換性を考慮して設計されています。たとえば、ルートレイアウトでアプリケーション全体に共通のメタデータ属性を設定し、他のルートのメタデータオブジェクトを composable してマージすることができます。

これには、動的メタデータと静的メタデータの両方のサポートが含まれます。

layout.js / page.js
// Static metadata
export const metadata = {
  title: '...',
};
 
// Dynamic metadata
export async function generateMetadata({ params, searchParams }) {
  const product = await getProduct(params.id);
  return { title: product.title };
}

すべてのメタデータオプションが利用可能であり、カスタムメタデータを提供できる機能も含まれています。TypeScript プラグイン (TypeScript plugin) を使用するか、Metadata 型を追加することで TypeScript のサポートも受けられます。

たとえば、メタデータを通じてオープングラフ画像を定義できます。

app/layout.tsx
export const metadata = {
  openGraph: {
    title: 'Next.js',
    description: 'The React Framework for the Web',
    url: 'https://nextjs.dokyumento.jp',
    siteName: 'Next.js',
    images: [
      {
        url: 'https://nextjs.dokyumento.jp/og.png',
        width: 800,
        height: 600,
      },
    ],
    locale: 'en-US',
    type: 'website',
  },
};
 
export default function Layout({ children }) {}

メタデータ API は 13.2 で App Router (app) で利用可能になり、以前の head.js という特別なファイルを置き換えます。pages ディレクトリでは利用できません。

SEO についてさらに詳しく学習するか、メタデータの API リファレンスをご覧ください。コミュニティパッケージである next-seo の作業と、初期 API 設計におけるフィードバックに感謝いたします。

カスタムルートハンドラー

App Router (app) の最初のベータリリースで欠けていた要素の1つが API Routes でした。これは pages/api ディレクトリに存在します。この機会に、app の新しいルーティングシステムに深く統合された、よりモダンな API Routes のバージョンを作成しました。

ルートハンドラーを使用すると、Web のRequest および Response API を使用して、指定されたルートのカスタムリクエストハンドラーを作成できます。

app/example/route.ts
export async function GET(request: Request) {}

ルートハンドラーは、Edge および Node.js ランタイムをシームレスにサポートするための同型 API を持ち、ストリーミングレスポンスのサポートも含まれています。ルートハンドラーは、ページやレイアウトと同じ ルートセグメント設定 を使用するため、一般的に要望されていた静的レンダリング再検証などの機能もサポートします。

route.ts ファイルは、HTTP 動詞の名前(GETHEADOPTIONSPOSTPUTDELETEPATCH)の非同期関数をエクスポートできます。これらの関数は、カスタムルートロジックのためのヘルパー/再利用可能なロジックを作成するためにラップおよび抽象化できます。

cookiesheaders のような他のサーバー関数は、ルートハンドラー内で使用できます。これらは、これらの抽象化が構築されている Web API のいずれも使用できます。これにより、サーバーコンポーネントとルートハンドラー間でコードを共有できます。

app/example/route.ts
import { cookies } from 'next/headers';
 
export async function GET(request: Request) {
  const cookieStore = cookies();
  const token = cookieStore.get('token');
 
  return new Response('Hello, Next.js!', {
    status: 200,
    headers: { 'Set-Cookie': `token=${token}` },
  });
}

ルートハンドラーは 13.2 で App Router (app) で route.ts という特別なファイルを使用して利用できます。API Routes の代替となるため、pages ディレクトリでは利用できません。

ルートハンドラーについてさらに詳しく学習するか、API リファレンスをご覧ください。SvelteKit の先行事例とインスピレーション に感謝いたします。

サーバーコンポーネント向けの MDX

MDX は markdown のスーパーセットであり、markdown ファイルに JSX を直接書き込むことができます。これは、動的なインタラクティビティを追加し、コンテンツ内に React コンポーネントを埋め込むための強力な方法です。

13.2 では、React Server Components と共に MDX を完全に利用できるようになりました。これにより、クライアントサイドの JavaScript が削減され、ページロードが高速化されます。同時に、テンプレート作成における React の強力な機能を利用して動的な UI を作成することもできます。必要に応じて、MDX コンテンツにインタラクティビティを組み込むことができます。

@next/mdx プラグインは、アプリケーションのルートに定義された新しい特別なファイル mdx-components.js|ts のサポートが更新され、カスタムコンポーネントを提供できるようになりました。

your-project/mdx-components.js
// This file allows you to provide custom React components
// to be used in MDX files. You can import and use any
// React component you want, including components from
// other libraries.
function H1({ children }) {
  // ...
}
 
function H2({ children }) {
  // ...
}
 
export function useMDXComponents(components) {
  return { h1: H1, h2: H2, ...components };
}

さらに、MDX コンテンツの取得(next-mdx-remotecontentlayer といったコミュニティパッケージと協力し、React Server Components のサポートを追加しました。

サーバーコンポーネントとの MDX セットアップ方法についてさらに詳しく学習するか、例をデプロイ してください。

Rust MDX パーサー

サーバーコンポーネント向けの MDX を有効にする一環として、パフォーマンスを向上させるために MDX パーサーを Rust で書き直しました。これは、JavaScript ベースの以前のパーサーと比較して大幅な改善であり、多数の MDX ファイルを処理する際に顕著な遅延が発生していました。

next.config.js で Rust パーサーの使用を選択できます。たとえば、@next/mdx の場合

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    appDir: true,
    mdxRs: true,
  },
};
 
const withMDX = require('@next/mdx')();
module.exports = withMDX(nextConfig);

このプロジェクトに取り組むためにスポンサーさせていただいた Titus Wormer に感謝いたします。Next.js 外で使用したい場合は、新しいパッケージ mdxjs-rs をチェックしてください。

Next.js は、app ディレクトリ内のリンクを静的に型付けできるようになり、next/link を使用する際のタイプミスやその他のエラーを防ぎ、ページ間ナビゲーションの型安全性を向上させます。

import Link from 'next/link'
 
// ✅
<Link href="/about" />
// ✅
<Link href="/blog/nextjs" />
// ✅
<Link href={`/blog/${slug}`} />
 
// ❌ TypeScript errors if href is not a valid route
<Link href="/aboot" />

この機能は、新しい App Router および TypeScript の使用が必要です。

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    appDir: true,
    typedRoutes: true,
  },
};
 
module.exports = nextConfig;

この機能は現在ベータ版で利用可能です。rewritesredirects はまだサポートされていません。

静的型付けルートについてさらに詳しく.

エラーオーバーレイの改善

エラーの可読性とデバッグ可能性を向上させるために、Next.js のエラーオーバーレイにいくつかの改善を加えました。

13.2 では、Next.js と React のスタックトレースが分離され、エラーの原因を特定しやすくなりました。さらに、エラーオーバーレイには現在の Next.js のバージョンが表示されるようになり、バージョンが最新かどうかを理解するのに役立ちます。

The improved error overlay in 13.2 showing version staleness.
バージョン staleness を示す 13.2 の改善されたエラーオーバーレイ。

また、React のハイドレーションエラーのエラー出力も改善し、より読みやすくデバッグしやすくなりました。

Turbopack の改善

Turbopack は、Next.js 13 で発表されたアルファ版で、ローカル開発と将来のプロダクションビルドの両方を高速化するように設計されたインクリメンタルバンドラーです。

Turbopack では、既存の Next.js 機能をサポートし、ベータ版への移行に向けて全体的な安定性を向上させることに注力してきました。前回のリリース以降、以下の機能が追加されました。

  • next/dynamic のサポート
  • next.config.js における rewrites, redirects, headers, pageExtensions のサポート
  • pages における 404 およびエラーのサポート
  • CSS Modules の composes: ... from ... のサポート
  • Fast Refresh の信頼性とエラー回復の改善
  • CSS の優先順位処理の改善
  • コンパイル時評価の改善

また、当社の最大の内部 Next.js アプリケーションや Vercel の初期顧客で Turbopack をドッグフーディングする過程で、多くのバグを修正し、安定性を向上させました。

Webpack ローダーによるカスタムファイル変換

Turbopack は、一部の webpack ローダーのサポートと互換性を備えるようになりました。これにより、Webpack エコシステムの多くのローダーを使用して、さまざまな種類のファイルを JavaScript に変換できます。@mdx-js/loader@svgr/webpackbabel-loader などのローダーがサポートされています。Turbopack のカスタマイズについてさらに詳しく学習してください。

たとえば、experimental.turbo.loaders を使用して、ファイル拡張子ごとにローダーのリストを設定します。

next.config.js
module.exports = {
  experimental: {
    turbo: {
      loaders: {
        '.md': [
          {
            // Option format
            loader: '@mdx-js/loader',
            options: {
              format: 'md',
            },
          },
        ],
        '.svg': ['@svgr/webpack'],
      },
    },
  },
};

ローダーを使用した Turbopack の例については、完全な例 を参照してください。

Webpack スタイルの解決エイリアス

Turbopack は、webpack のresolve.alias と同様に、エイリアスを通じてモジュール解決を修正するように設定できるようになりました。これは experimental.turbo.resolveAlias で設定します。

next.config.js
module.exports = {
  experimental: {
    turbo: {
      resolveAlias: {
        underscore: 'lodash',
        mocha: { browser: 'mocha/browser-entry.js' },
      },
    },
  },
};

Next.js キャッシュ

Next.js 13.2 では、ISR の進化形である新しい Next.js キャッシュ(ベータ版)を導入し、以下の機能を実現します。

  • コンポーネントレベルでのプログレッシブ ISR
  • ネットワークリクエストなしの高速リフレッシュ
  • 静的ページへのコード変更の高速な再デプロイ

完全に静的なページについては、ISR は現在と同様に機能します。より詳細なデータ取得(静的と動的の混合)を持つページについては、Next.js キャッシュはより粒度の高い一時的なキャッシュを使用します。

React Server Components と Next.js App Router (app) でのコロケーションされたデータ取得の基盤により、静的または動的なデータを、それを利用するコンポーネントと共にカプセル化できるようになりました。

app/page.jsx
export default async function Page() {
  const [staticData, dynamicData, revalidatedData] = await Promise.all([
    // Cached until manually invalidated
    fetch(`https://...`),
    // Refetched on every request
    fetch(`https://...`, { cache: 'no-store' }),
    // Cached with a lifetime of 10 seconds
    fetch(`https://...`, { next: { revalidate: 10 } }),
  ]);
 
  return <div>...</div>;
}

App Router を使用したローカル開発では、next dev でのキャッシング動作が、next start でのプロダクションと同様になります。これにより、サーバーコンポーネントまたはデータローディングコードが変更された場合の Fast Refresh の速度が向上します。

Next.js キャッシュでは、アプリがキャッシュを制御します。サードパーティの API ではありません。これは cache-control ヘッダーとは異なり、アップストリームが値のキャッシュ期間を制御します。

Vercel キャッシュ API を使用した Next.js キャッシュ

Vercel 上の Next.js では、フレームワーク定義のインフラストラクチャが提供されます。アプリケーションコード(fetch を使用したコンポーネントレベルのデータ取得など)を記述するだけで、追加の労力なしにグローバルに分散されたインフラストラクチャがスキャフォールドされます。

新しい Next.js キャッシュにより、コードの変更とデータの変更が独立します。これにより、静的ページ生成に既存のキャッシュを使用できるため、静的ページの再デプロイが劇的に高速化されます。

この新しい Vercel Cache API は、どのフレームワークでも動作するように設計されていますが、Next.js Cache とネイティブに統合されています。ISR が Next.js キャッシュにどのように進化したか、および Vercel にデプロイした際の Next.js キャッシュの動作についてさらに詳しく学習してください。

セルフホスト時の Next.js キャッシュ

セルフホストの場合、LRU キャッシュが使用され、デフォルトで 50MB になります。キャッシュへのすべてのエントリは、デフォルトでディスクに自動的に書き込まれます。このファイルシステムキャッシュは、現在の ISR の動作と同様に、ノード間で同じキャッシュキーを持つ場合に共有できます。

Next.js キャッシュのコアをさらにカスタマイズおよび変更したい開発者は、基盤となるキャッシュキーを変更し、キャッシュエントリの永続化方法や場所を変更したり、永続化を無効にしたりできます。

その他の改善点

  • フォント: 素晴らしいコミュニティの採用を受けて、@next/font は Next.js に next/font として組み込まれました。これにより、@next/font を別途インストールする必要がなくなりました。さらに詳しく
  • フォント: next/font のデフォルトの font-display プロパティは、コミュニティのフィードバックに基づき、optional から font-display: swap に変更されました。
  • パフォーマンス: ビルドプロセスを最適化し、メモリ使用量を削減しました。テストでは約 550MB を節約しました(PR)。
  • パフォーマンス: プロジェクト設定の複数回ロードを回避し、テストでは平均で約 400ms のビルド高速化を実現しました(PR)。
  • パフォーマンス: エラーコンポーネントを最適化し、スタイリングを変更せずに HTML ペイロードを 0.4kb 削減しました(PR)。
  • パフォーマンス: エッジバンドルサイズを約 130KB(ほぼ半分)に削減し、Vercel のようなエッジ環境にデプロイした際のコールドブートサイズをさらに削減しました(PR)。
  • セキュリティ: Image Optimization API に直接アクセスした場合に画像をダウンロードさせるように、images.contentDispositionType: "attachment" の設定を追加しました(PR)。

コミュニティ

Next.js は、2,500 人以上の個々の開発者、Google や Meta のような業界パートナー、そして Vercel のコアチームの共同作業の成果です。週に 390 万回以上の npm ダウンロードと 100,000 以上の GitHub スターを持つ Next.js は、Web を構築するための最も人気のある方法の 1 つです。

GitHub DiscussionsRedditDiscord でコミュニティに参加しましょう。

このリリースは、以下の方々によってもたらされました。

そして、@timneutkens, @loettz, @okcoker, @clive-h-townsend, @shuding, @JanKaifer, @sepiropht, @hanneslund, @huozhi, @aralroca, @balazsorban44, @cristobaldominguez95, @vinaykulk621, @Brooooooklyn, @feedthejim, @samsisle, @MarDi66, @styfle, @therealrinku, @sebmarkbage, @cravend, @hu0p, @kdy1, @ijjk, @juzhiyuan, @IvanKiral, @LukeSchlangen, @wojtekolek, @samdenty, @Josehower, @bennettdams, @SCG82, @mike-plummer, @kwonoj, @David0z, @denchance, @joulev, @wbinnssmith, @alexkirsz, @UnknownMonk, @leerob, @sairajchouhan, @imranbarbhuiya, @jomeswang, @ductnn, @thomasballinger, @chibicode, @jridgewell, @sreetamdas, @Juneezee, @SukkaW, @wyattjoh, @michaeloliverx, @cattmote, @joefreeman, @valentincostam, @qrohlf, @ossan-engineer, @rishabhpoddar, @vasucp1207, @Schniz, @andrii-bodnar, @gergelyke, @abstractvector, @wherehows, @BrodaNoel, @taep96, @abe1272001, @0xadada, @nbouvrette, @teobler, @lubakravche, @molebox、および @hiddenest による貢献。