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

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 で、新しいメタデータ API を発表しました。これにより、レイアウトまたはページからメタデータオブジェクトをエクスポートすることで、メタデータ (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() {}

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

  • 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];
}

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

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

動的 Open Graph イメージの生成

6 か月前には、JSX、HTML、および CSS を使用して画像を動的に生成できるライブラリである @vercel/ogSatori をリリースしました。

@vercel/ogNext.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 は、ルートハンドラーやファイルベースのメタデータなど、他の Next.js API と自然に統合されます。たとえば、opengraph-image.tsx ファイルで ImageResponse を使用して、ビルド時またはリクエスト時に動的に 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;

静的エクスポートは、静的ルートハンドラー、Open Graph イメージ、React サーバーコンポーネントなど、app ルーターの新機能と連携します。

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

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

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

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

並列ルートとインターセプション

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

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

並列ルートは、名前付きの「スロット」を使用して作成されます。スロットは、@folder規約を使用して定義します。

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

同じルートセグメントのレイアウトは、スロットを props として受け取ります。

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: ミドルウェア、すべてのnext/fontオプション、およびベータ版に近づくにつれてサーバーコンポーネントを使用したストリーミングのサポートが追加されました(デモを見る)。また、vercel.comnextjs.orgのような成熟したNext.jsアプリでのドッグフーディング中に発見された追加のバグも修正しました。詳細はこちら
  • next.config.jsの高速リフレッシュ: next.config.jsに変更を加えると、ローカルの開発サーバーが自動的に再起動するようになりました。これにより、.env.env.*jsconfig.jsontsconfig.json構成ファイルの自動リロードが拡張されます。
  • アクセシビリティ: App Routerには、pagesからのルートアナウンスが含まれるようになりました。この機能は、クライアント側のルート遷移をスクリーンリーダーやその他の支援技術にアナウンスします。詳細はこちら
  • 静的に型付けされたリンク: next.config.jsで設定されたredirectsrewritesが型チェック中に考慮されるようになりました。詳細はこちら
  • create-next-appのTailwind CSS: npx create-next-app@latestで新しいプロジェクトを開始するときに、Tailwind CSSをオプションで選択するか、--tailwindフラグを使用すると、このスタイリングソリューションでアプリケーションを事前構成できます。
  • ルートハンドラー: サポートされているHTTP動詞の代わりにexport defaultを使用すると、route.tsに関する役立つエラーがスローされるようになりました。ルートハンドラーの詳細をご覧ください。
  • 画像: next/imagefetchPriority="high"属性をサポートするようになりました。
  • メタデータ: 13.2で非推奨になったメタデータ(head.js)の以前のAPIが削除されました。代わりに、メタデータ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 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, および @gustavostz.