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

2023年4月6日(木)

Next.js 13.3

投稿者

Next.js 13.3 では、コミュニティから要望の多かった以下の機能が追加されました。

今すぐ以下のコマンドを実行してアップデートしましょう

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

次回のマイナーリリースでApp Routerを安定版としてマークする時期が近づいており、パフォーマンスの最適化、動作の改善、バグ修正に焦点を移しています。

Mutationsのような一部の機能にはまだ取り組んでいますが、これらが他のApp Router機能のAPIサーフェスに影響を与えるとは考えていません。App Routerで皆さんが何を構築するか楽しみにしていますし、フィードバックをお待ちしております。

ファイルベースのメタデータAPI

Next.js 13.2では、新しいMetadata APIを発表しました。これにより、レイアウトまたはページからMetadataオブジェクトをエクスポートすることで、メタデータ(例: HTMLのhead要素内のtitlemetalinkタグ)を定義できます。

layout.js または page.js
// either Static metadata
export const metadata = {
  title: 'Home',
};
// Output:
// <head>
//	 <title>Home</title>
// </head>
 
// or Dynamic metadata
export async function generateMetadata({ params, searchParams }) {
  const product = await getProduct(params.id);
  return { title: product.title };
}
// Output:
// <head>
//	 <title>My Unique Product</title>
// </head>
 
export default function Page() {}

設定ベースのメタデータに加え、Metadata APIは新しいファイル命名規則をサポートし、SEOの改善やウェブ上での共有のためにページを便利にカスタマイズできるようになりました。

  • 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`ページのOpen Graph画像を追加できます。

app
├── favicon.ico
├── layout.js
├── page.js
└── about
    ├── opengraph-image.jpg
    └── page.js

Next.jsは、これらのファイルを本番環境でキャッシュのためにハッシュ(ファイル名用)を付けて自動的に提供し、アセットのURL、ファイルタイプ、画像サイズなどの正しいメタデータ情報で関連するhead要素を更新します。

// 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.xml`ファイルを追加できますが、ほとんどのサイトには外部データソースを使用して動的に生成されるページがあります。動的なサイトマップを生成するには、動的なルートの配列を返す`sitemap.js`ファイルを追加できます。

app/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];
}

設定ベースと新しいファイルベースのオプションにより、静的および動的メタデータの両方を網羅する包括的なMetadata APIが利用できるようになりました。

Metadata APIは、App Router (`app`) の13.3で利用可能です。`pages`ディレクトリでは利用できません。ファイルベースのメタデータの詳細とAPIリファレンスをご覧ください

動的なOpen Graph画像の生成

6ヶ月前、JSX、HTML、CSSを使用して画像を動的に生成できるライブラリ`@vercel/og`Satoriをリリースしました。

`@vercel/og`はNext.js Confで試され、すべての参加者向けに10万枚以上の動的なチケット画像を生成しました。Vercelのお客様に広く採用され、リリース以来90万回以上ダウンロードされており、外部パッケージなしで動的に生成された画像をすべてのNext.jsアプリケーションにもたらすことに興奮しています。

これで、`next/server`から`ImageResponse`をインポートして画像を生成できます。

/app/about/opengraph-image.tsx
import { ImageResponse } from 'next/server';
 
export const size = { width: 1200, height: 600 };
export const alt = 'About Acme';
export const contentType = 'image/png';
export const runtime = 'edge';
 
export default function og() {
  return new ImageResponse();
  // ...
}

`ImageResponse`は、Route HandlersやファイルベースのMetadataを含む他のNext.js APIと自然に統合されます。例えば、`ImageResponse`を`opengraph-image.tsx`ファイルで使用して、ビルド時またはリクエスト時に動的にOpen GraphおよびTwitter画像を生成できます。

Image Response APIの詳細をご覧ください。

App Routerの静的エクスポート

Next.js App Routerは、完全に静的なエクスポートをサポートするようになりました。

静的サイトまたはシングルページアプリケーション(SPA)として開始し、後で必要に応じてサーバーを必要とするNext.js機能を使用するようにアップグレードできます。

`next build`を実行すると、Next.jsはルートごとにHTMLファイルを生成します。厳密なSPAを個別のHTMLファイルに分割することで、Next.jsはクライアント側で不要なJavaScriptコードを読み込むのを避け、バンドルサイズを削減し、ページ読み込みを高速化できます。

next.config.js
/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  output: 'export',
};
 
module.exports = nextConfig;

静的エクスポートは、静的Route Handlers、Open Graph画像、React Server Componentsを含むApp Routerの新しい機能と連携します。

例えば、Server Componentsはビルド中に実行され、従来の静的サイト生成と同様に、コンポーネントを初期ページ読み込み用の静的HTMLと、ルート間のクライアントナビゲーション用の静的ペイロードにレンダリングします。

以前は、`pages`ディレクトリで静的エクスポートを使用するには、`next export`を実行する必要がありました。しかし、`next.config.js`オプションを使用すると、`output: 'export'`が設定されている場合に`next build`が`out`ディレクトリを出力します。`app`ルーターと`pages`ディレクトリで同じ設定を使用できます。これにより、`next export`は不要になりました。

高度な静的エクスポートのサポートにより、`cookies()`や`headers()`のようにサーバーを必要とする動的関数を使用しようとした場合など、開発プロセス(`next dev`)の早い段階でエラーが発生するようになります。

静的エクスポートの詳細をご覧ください

パラレルルートとインターセプション

Next.js 13.3では、高度なルーティングケースを実装できる新しい動的命名規則が導入されました: パラレルルートとインターセプトするルート。これらの機能により、複雑なダッシュボードやモーダルのように、同じビューで複数のページを表示できます。

パラレルルートを使用すると、同じビュー内で1つ以上のページを同時にレンダリングでき、それぞれ独立してナビゲートできます。また、条件付きでページをレンダリングするためにも使用できます。

パラレルルートは、名前付きの「スロット」を使用して作成されます。スロットは`@folder`の命名規則で定義されます。

dashboard
├── @user
   └── page.js
├── @team
   └── page.js
├── layout.js
└── page.js

同じルートセグメントのレイアウトは、スロットをプロパティとして受け入れます。

app/dashboard/layout.js
export default async function Layout({ children, user, team }) {
  const userType = getCurrentUserType();
 
  return (
    <>
      {userType === 'user' ? user : team}
      {children}
    </>
  );
}

上記の例では、`@user`と`@team`のパラレルルートスロット(明示的)は、ロジックに基づいて条件付きでレンダリングされます。`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

上記の例では、ユーザーのプロフィールから写真をクリックすると、クライアントサイドのナビゲーション中にモーダルで写真が開きます。ただし、ページを更新したり共有したりすると、デフォルトのレイアウトで写真が読み込まれます。

Parallel routes and interception enable Instagram-like modal routing.
パラレルルートとインターセプションにより、Instagramのようなモーダルルーティングが可能になります。

これは、モーダルコンテンツをURL経由で共有可能にする、ページが更新されたときにコンテキストが失われるのを防ぐ、戻る・進むナビゲーションでモーダルを閉じたり再度開いたりするなど、モーダル作成時に発生する可能性のある課題を解決します。

より多くの例と動作については、パラレルルートインターセプトするルートのドキュメントをご覧ください。

その他の改善点

  • デザインの更新: Next.jsのホームページショーケースが新しいデザインに刷新されました。
  • Turbopack: Middleware、すべての`next/font`オプション、およびServer Componentsでのストリーミングのサポートが追加され、ベータ版に近づいています(デモを見る)。また、vercel.comnextjs.orgのような成熟したNext.jsアプリでドッグフーディング中に発見された追加のバグも修正しました。詳細はこちら
  • `next.config.js`の高速リフレッシュ: `next.config.js`を変更すると、ローカル開発サーバーが自動的に再起動するようになりました。これは、`.env`、`.env.*`、`jsconfig.json`、`tsconfig.json`設定ファイルの自動リロードを拡張するものです。
  • アクセシビリティ: App Routerに、`pages`からのルートアナウンス機能が組み込まれました。この機能は、クライアントサイドのルート遷移をスクリーンリーダーやその他の支援技術にアナウンスします。詳細はこちら
  • 静的型付きリンク: `next.config.js`で設定された`redirects`と`rewrites`が、型チェック中に考慮されるようになりました。詳細はこちら
  • `create-next-app`のTailwind CSSサポート: `npx create-next-app@latest`で新しいプロジェクトを開始する際に、オプションでTailwind CSSを選択するか、`--tailwind`フラグを使用して、このスタイリングソリューションでアプリケーションを事前設定できるようになりました。
  • ルートハンドラー: サポートされているHTTP動詞の代わりに`export default`を使用すると、`route.ts`で分かりやすいエラーがスローされるようになりました。ルートハンドラーの詳細はこちら
  • 画像: `next/image`が`fetchPriority="high"`属性をサポートするようになりました。
  • メタデータ: 13.2で非推奨となったメタデータ用の以前のAPI(`head.js`)は削除されました。代わりに、Metadata APIを介したSEOの組み込みサポートを使用してください。
  • ルーティングからのフォルダ除外: フォルダ名の先頭に`_`を付けることで、そのフォルダとその子セグメントをルーティングから除外できます。例えば、`app/_dashboard/page.tsx`はルーティングされません。
  • App Router: 指定されたルートセグメントの動的パラメーターを読み取るための新しいクライアントコンポーネントフック`useParams`を追加しました。詳細はこちら
  • スタイルシートの読み込みの改善: Next.jsはReactのSuspensey CSSを実装し、CSSの読み込みとスタイルのないコンテンツのフラッシュに関する多くの問題、特にナビゲーション中の問題を修正しました。
  • Not Found処理の改善: 予期される`notFound()`エラーを捕捉することに加えて、ルートの`app/not-found.js`ファイルは、アプリケーション全体の未一致URLも処理します。これにより、アプリケーションで処理されないURLにアクセスしたユーザーには、`app/not-found.js`ファイルによってエクスポートされたUIが表示されます。詳細はこちら
  • クライアントサイドのルーターキャッシュの改善: `router.refresh()`はキャッシュ全体を無効にするようになり、検索パラメーターもキャッシュキーの一部となるため、2つの検索パラメーター間(例: `/?search=leerob`と`/?search=tim`)のナビゲーションで、パラメーターに依存するコンテンツを正しく復元できるようになりました。

コミュニティ

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

GitHub Discussions、Reddit、Discordでコミュニティに参加しましょう。GitHub DiscussionsReddit、そしてDiscord

このリリースは以下によって提供されました

および以下の貢献者: @shuding, @huozhi, @sokra, @hanneslund, @JesseKoldewijn, @kaguya3222, @yangshun, @ijjk, @konomae, @Brooooooklyn, @jridgewell, @zlrlyy, @JohnDaly, @abhiyandhakal, @benjie, @johnnyomair, @nk980113, @dirheimerb, @DerTimonius, @DuCanhGH, @padmaia, @stafyniaksacha, @Gladowar, @zek, @jankaifer, @styfle, @balazsorban44, @wbinnssmith, @chibicode, @ForsakenHarmony, @franktronics, @FSaldanha, @Schniz, @raisedadead, @AdamKatzDev, @wyattjoh, @leerob, @meesvandongen, @vladikoff, @feedthejim, @tka5, @pyjun01, @gdborton, @M3kH, @aretrace, @shivanshubisht, @alexkirsz, @agrattan0820, @vinaykulk621, @heyitsuzair, @mrkldshv, @timneutkens, @furkanmavili, @swaminator, @EndangeredMassa, @DevEsteves, @rishabhpoddar, @schehata, @molebox, @dlehmhus, @akshaynox, @sp00ls, @janicklas-ralph, @tomryanx, @kwonoj, @karlhorky, @kdy1, @dante-robinson, @lachlanjc, @ianmacartney, @hotters, @isaackatayev, @insik-han, @jayair, @ivanhofer, @javivelasco, @SukkaW, @visshaljagtap, @imranbarbhuiya, @nivak-monarch, @HarshaVardhanReddyDuvvuru, @ianldgs, @ricardofiorani, @swarnava, and @gustavostz。