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

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は多くのバージョンでアプリケーションのメタデータ(`next/head`)を変更するためのシンプルなAPIを提供してきましたが、App Router(`app`)を使用して検索エンジンの最適化方法を再設計および強化したいと考えていました。

新しいメタデータAPIを使用すると、サーバーコンポーネントであるレイアウトまたはページ内の明示的なメタデータ構成を使用して、メタデータ(例: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`型を追加することで、カスタムメタデータを提供する機能を含むすべてのメタデータオプションを利用できます。

たとえば、メタデータを使用して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 }) {}

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

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

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

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

ルートハンドラーを使用すると、WebのRequestResponseAPIを使用して、特定のルートのカスタムリクエストハンドラーを作成できます。

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

ルートハンドラーは、EdgeとNode.jsの両方のランタイムをシームレスにサポートする同型APIを持っており、ストリーミングレスポンスもサポートしています。ルートハンドラーはページやレイアウトと同じルートセグメント構成を使用するため、汎用的な静的レンダリング再検証などの待望の機能をサポートしています。

`route.ts`ファイルは、`GET`、`HEAD`、`OPTIONS`、`POST`、`PUT`、`DELETE`、`PATCH`というHTTP動詞で名前付けされた非同期関数を出力できます。これらの関数は、ラップして抽象化して、カスタムルートロジックのヘルパー/再利用可能なロジックを作成できます。

`cookies`や`headers`などの他のサーバー関数は、ルートハンドラー内で使用できます。これにより、サーバーコンポーネントとルートハンドラー間でコードを共有できます。

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ルートの代替となるため、pagesディレクトリでは利用できません。

ルートハンドラについて詳しく学ぶか、APIリファレンスを参照してください。SvelteKitの先進的な技術とインスピレーションに感謝いたします。

サーバーコンポーネントのためのMDX

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

13.2では、MDXをReactサーバーコンポーネントで完全に使用できるようになりました。これにより、クライアント側の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-remotecontentlayerと連携して、Reactサーバーコンポーネントのサポートを追加しました。

サーバーコンポーネントを使用したMDXの設定方法について詳しく学ぶか、サンプルをデプロイすることができます。

RustによるMDXパーサー

サーバーコンポーネントで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は、ローカル開発と将来の運用ビルドの両方を高速化するために設計されたインクリメンタルバンドラーです。

私たちは、既存のNext.js機能のTurbopackへの対応と、ベータ版への移行に向けた全体的な安定性の向上に注力してきました。前回のリリース以降、次を追加しました。

  • next/dynamicのサポート
  • next.config.js内のrewritesredirectsheaderspageExtensionsのサポート
  • pages内の404エラーとその他のエラーのサポート
  • CSSモジュールのcomposes: ... from ...のサポート
  • 高速リフレッシュの信頼性とエラー回復の改善
  • 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 Cache

Next.js 13.2では、新しいNext.js Cache(ベータ版)が導入されました。これはISRを進化させたもので、以下を実現します。

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

完全に静的なページの場合、ISRは現在と同じように機能します。静的データと動的データが混在する、より詳細なデータ取得を行うページの場合、Next.js Cacheはより詳細で一時的なキャッシュを使用します。

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 Cacheを使用すると、アプリケーションがキャッシュを制御し、サードパーティAPIは制御しません。これは、アップストリームが値のキャッシュ期間を制御するcache-controlヘッダーとは異なります。

Vercel Cache APIを使用したNext.js Cache

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

新しいNext.js Cacheにより、コードの変更とデータの変更が独立します。これにより、これらのページの生成で既存のキャッシュを使用できるため、静的ページの再デプロイ速度が大幅に向上する可能性があります。

この新しいVercel Cache APIは、あらゆるフレームワークで動作するように設計されていますが、Next.js Cacheとのネイティブ統合が可能です。ISRがどのようにNext.js Cacheに進化したか、およびVercelへのデプロイ時のNext.js Cacheの動作について詳しく説明します。

自己ホスティング時のNext.js Cache

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

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

その他の改善点

  • フォント: コミュニティによる素晴らしい採用を受けて、@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)。
  • セキュリティ: 画像最適化APIに直接アクセスしたときに画像のダウンロードを強制するための設定images.contentDispositionType: "attachment"を追加しました(PR)。

コミュニティ

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

コミュニティに参加するには、GitHub DiscussionsReddit、およびDiscordにご参加ください。

このリリースは、以下の人々によって実現されました。

そして、以下の方々からの貢献: @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。