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

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

新しいMetadata APIによる組み込みSEOサポート

Next.jsは、当初から検索エンジン向けに最適化できるように設計されています

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

新しいMetadata 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はシンプルで構成可能であり、ストリーミングサーバーレンダリングとの互換性を持つように設計されています。たとえば、ルートレイアウトでアプリケーション全体の共通のメタデータ属性を設定し、アプリケーションの他のルートについてはメタデータオブジェクトを合成およびマージすることができます。

これには、静的なものだけでなく動的なメタデータのサポートも含まれます。

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プラグインを使用するか、Metadata型を追加することでTypeScriptのサポートも利用できます。

たとえば、メタデータを通じてOpen Graph画像を定義できます。

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 }) {}

Metadata APIは、以前のhead.js特別ファイルに代わり、App Router(app)向けに13.2で利用可能です。pagesディレクトリでは利用できません。

SEOについてさらに学ぶ、またはMetadataのAPIリファレンスを参照する。コミュニティパッケージでの作業と初期API設計に関するフィードバックを提供してくださったnext-seoに感謝いたします。

カスタムルートハンドラ

App Router(app)の最初のベータリリースで欠けていた要素の一つは、pages/apiディレクトリに存在するAPI Routesでした。私たちはこの機会に、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とともに、ルートハンドラ内で使用できます。これにより、Server Componentsとルートハンドラ間でコードを共有することが可能になります。

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}` },
  });
}

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

ルートハンドラについてさらに学ぶ、またはAPIリファレンスを参照する。SvelteKitの先行事例とインスピレーションに感謝いたします。

Server Components向けMDX

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

13.2では、MDXを完全にReact Server Componentsで使用できるようになりました。これにより、クライアントサイドJavaScriptが減り、ページの読み込みが高速化され、動的なUIをテンプレート化するReactの強力な機能を維持できます。必要に応じて、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-remoteおよびcontentlayerと協力し、React Server Componentsのサポートを追加しました。

Server ComponentsでMDXをセットアップする方法についてさらに学ぶ、またはサンプルをデプロイする

Rust MDXパーサー

Server Components向けMDXを有効にする一環として、パフォーマンスを向上させるためMDXパーサーをRustで書き直しました。これは、多数のMDXファイルを処理する際に著しい速度低下が見られた以前のJavaScriptベースのパーサーに比べて、大幅な改善です。

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.
バージョンが古いことを示す13.2の改良されたエラーオーバーレイ。

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

Turbopackの改善

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

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

  • next/dynamicのサポート
  • next.config.jsにおけるrewritesredirectsheaderspageExtensionsのサポート
  • pagesにおける404エラーとその他のエラーのサポート
  • CSSモジュールのcomposes: ... from ...のサポート
  • Fast Refreshの信頼性とエラーリカバリの向上
  • CSSの優先順位処理の改善
  • コンパイル時評価の改善

また、Turbopackを社内最大規模のNext.jsアプリケーションや初期のVercelのお客様にdogfooding(自社製品を自社で利用)する中で、多くのバグを修正し、安定性を向上させました。

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スタイルのResolveエイリアス

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キャッシュはよりきめ細かく、一時的なキャッシュを使用します。

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

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での本番環境と同じキャッシュ動作が表示されるようになります。これにより、Server Componentやデータロードコードが変更された際のFast Refreshの速度が向上します。

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

Vercel Cache APIとのNext.jsキャッシュ

Vercel上のNext.jsは、フレームワークによって定義されたインフラストラクチャを提供します。fetchによるコンポーネントレベルのデータフェッチのようなアプリケーションコードを記述するだけで、追加の労力なしにグローバルに分散されたインフラストラクチャを構築します。

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

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

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

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

Next.jsキャッシュのコアをさらにカスタマイズおよび変更したい開発者は、基盤となるキャッシュキーを変更したり、キャッシュエントリがどのように、どこに永続化されるかを変更したりできます。永続化を完全に無効にすることも可能です。

その他の改善

  • フォント: コミュニティで素晴らしい採用実績を挙げたため、@next/fontnext/fontとしてNext.jsに組み込まれました。これにより、@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ダウンロードと10万以上の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, and @hiddenest。