Next.js 13.4
投稿者: Sebastian Markbåge @ sebmarkbage、Tim Neutkens @ timneutkens
公開日: 2023年5月4日(木)
Next.js 13.4は基盤となるリリースであり、App Routerの安定性を示すマイルストーンです:
App Router(安定版)
- React Server Components
- ネストされたルートとレイアウト
- 簡素化されたデータフェッチング
- ストリーミングとSuspense
- 組み込みSEOサポート
Turbopack(ベータ版)
Server Actions(アルファ版)
- クライアントJavaScriptゼロでサーバー上のデータを変更
6ヶ月前のNext.js 13のリリース以来、私たちはNext.jsの未来の基盤であるApp Routerを、不要な破壊的変更なしに段階的に採用できる方法で構築することに注力してきました。今日、13.4のリリースにより、本番環境でApp Routerの採用を開始できるようになりました。
npm i next@latest react@latest react-dom@latest eslint-config-next@latest
Next.js App Router
私たちは2016年にNext.jsをリリースし、Reactアプリケーションをサーバーレンダリングする簡単な方法を提供しました。その目標は、よりダイナミックで、パーソナライズされた、グローバルなWebを作ることでした。
オリジナルのアナウンス投稿で、Next.jsの設計原則をいくつか共有しました:
- ゼロセットアップ。ファイルシステムをAPIとして使用
- JavaScriptのみ。すべてが関数
- 自動サーバーレンダリングとコード分割
- データフェッチングは開発者次第
Next.jsは現在6年が経ちました。私たちの元の設計原則は維持されており、Next.jsがより多くの開発者や企業に採用されるにつれ、これらの原則をより良く実現するためのフレームワークの基盤的なアップグレードに取り組んできました。
私たちは次世代のNext.jsに取り組んでおり、今日の13.4により、この次世代は安定し、採用の準備が整いました。この投稿では、App Routerの設計決定と選択についてより詳しく共有します。
ゼロセットアップ。ファイルシステムをAPIとして使用
ファイルシステムベースのルーティングは、Next.jsの中核機能でした。元の投稿では、単一のReactコンポーネントからルートを作成するこの例を示しました:
import React from 'react';
export default () => <h1>About us</h1>;
追加の設定は何もありませんでした。pages/内にファイルを置くだけで、Next.jsルーターが残りを処理してくれました。
私たちは今でもこのルーティングのシンプルさを愛しています。しかし、フレームワークの使用が増えるにつれ、開発者がそれで構築しようとするインターフェースの種類も増えました。開発者は、レイアウトの定義、UIの一部をレイアウトとしてネストすること、ローディングとエラー状態の定義においてより柔軟性を求めてきました。
これは既存のNext.jsルーターに後付けするのは簡単なことではありませんでした。フレームワークのすべての部分がルーターを中心に設計される必要があります。ページ遷移、データフェッチング、キャッシング、データの変更と再検証、ストリーミング、コンテンツのスタイリングなど。
ルーターをストリーミングと互換性を持たせ、レイアウトの強化されたサポートに対するこれらの要求を解決するために、私たちは新しいバージョンのルーターを構築することにしました。これは、Layouts RFCの初期リリース後に到達した場所です。
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
ここで見るものよりも重要なのは、見えないものです。この新しいルーター(app/ディレクトリを通じて段階的に採用可能)は、React Server ComponentsとSuspenseの基盤上に構築された、まったく異なるアーキテクチャを持っています。
この基盤により、Reactプリミティブを拡張するために最初に開発されたNext.js固有のAPIを削除することができました。例えば、グローバル共有レイアウトをカスタマイズするためにカスタム_appファイルを使用する必要がなくなりました:
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
Pages Routerでは、レイアウトは構成できず、データフェッチングをコンポーネントと同じ場所に配置することができませんでした。新しいApp Routerでは、これがサポートされるようになりました。
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
export default function DashboardLayout({ children }) {
return (
<section>
<h1>Dashboard</h1>
{children}
</section>
);
}
Pages Routerでは、_documentがサーバーからの初期ペイロードをカスタマイズするために使用されていました。
import { Html, Head, Main, NextScript } from 'next/document';
export default function Document() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
App Routerでは、Next.jsから<Html>、<Head>、<Body>をインポートする必要がなくなりました。代わりに、Reactを使用するだけです。
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
新しいファイルシステムルーターを構築する機会は、ルーティングシステムに関する他の多くの関連機能要求に対処する適切なタイミングでもありました。例えば:
-
以前は、外部npmパッケージ(コンポーネントライブラリなど)からのグローバルスタイルシートを_app.jsでのみインポートできました。これは理想的でない開発者体験でした。App Routerでは、任意のコンポーネントで任意のCSSファイルをインポート(および同じ場所に配置)できます。
-
以前は、Next.jsでサーバーサイドレンダリングを選択する(getServerSidePropsを通じて)ことは、ページ全体がハイドレートされるまでアプリケーションとのやり取りがブロックされることを意味していました。App Routerでは、React Suspenseと深く統合されるようにアーキテクチャをリファクタリングしました。これにより、UIの他のコンポーネントがインタラクティブになることをブロックすることなく、ページの一部を選択的にハイドレートできます。コンテンツはサーバーから即座にストリーミングでき、ページの知覚的なローディングパフォーマンスが向上します。
ルーターはNext.jsを機能させる中核です。しかし、ルーター自体についてではなく、データフェッチングなど、フレームワークの他の部分とどのように統合するかが重要です。
JavaScriptのみ。すべてが関数
Next.jsとReact開発者は、JavaScriptとTypeScriptコードを書き、アプリケーションコンポーネントを一緒に構成したいと考えています。元の投稿から:
import React from 'react';
import Head from 'next/head';
export default () => (
<div>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<h1>Hi. I'm mobile-ready!</h1>
</div>
);
Next.jsの将来のバージョンでは、Reactを自動的にインポートするDXの改善を追加しました。このコンポーネントは、アプリケーションのどこでも再利用および構成できるロジックをカプセル化します。ファイルシステムルーティングと組み合わせることで、JavaScriptとHTMLを書いているような感覚でReactアプリケーションを構築する簡単な方法を意味しました。
例えば、データをフェッチしたい場合、Next.jsの元のバージョンは次のようでした:
import React from 'react';
import 'isomorphic-fetch';
export default class extends React.Component {
static async getInitialProps() {
const res = await fetch('https://api.company.com/user/123');
const data = await res.json();
return { username: data.profile.username };
}
}
Next.jsの将来のバージョンでは、fetchをポリフィルするDXの改善を追加し、isomorphic-fetchやnode-fetchをインポートする必要がなくなり、クライアントとサーバーの両方でWeb fetch APIを使用できるようになりました。
採用が増え、フレームワークが成熟するにつれ、データフェッチングの新しいパターンを探求しました。getInitialPropsはサーバーとクライアントの両方で実行されました。このAPIはReactコンポーネントを拡張し、Promiseを作成してその結果をコンポーネントのpropsに転送することを可能にしました。
getInitialPropsは今日でも動作しますが、その後、顧客のフィードバックに基づいて次世代のデータフェッチングAPIを反復的に進歩させました:getServerSidePropsとgetStaticProps。
export async function getStaticProps(context) {
return { props: {} };
}
export async function getServerSideProps(context) {
return { props: {} };
}
これらのAPIは、コードがクライアントまたはサーバーのどちらで実行されているかをより明確にし、Next.jsアプリケーションが自動的に静的最適化されることを可能にしました。さらに、静的エクスポートを可能にし、Next.jsをサーバーをサポートしない場所(例:AWS S3バケット)にデプロイできるようになりました。
しかし、これは「ただのJavaScript」ではなく、私たちは元の設計原則により密接に従いたいと考えていました。
Next.jsが作成されて以来、私たちはMetaのReactコアチームと密接に協力して、Reactプリミティブの上にフレームワーク機能を構築してきました。私たちのパートナーシップは、Reactコアチームからの長年の研究開発と組み合わさって、Server Componentsを含む最新バージョンのReactアーキテクチャを通じてNext.jsが目標を達成する機会をもたらしました。
App Routerでは、馴染みのあるasyncとawait構文を使用してデータをフェッチします。学習する新しいAPIはありません。デフォルトでは、すべてのコンポーネントがReact Server Componentsであるため、データフェッチングはサーバー上で安全に行われます。
例えば:
export default async function Page() {
const res = await fetch('https://api.example.com/...');
const data = res.json();
return '...';
}
重要なことに、「データフェッチングは開発者次第」という原則が実現されています。データをフェッチして任意のコンポーネントを構成できます。そして、ファーストパーティのコンポーネントだけでなく、Server Componentsエコシステムの任意のコンポーネント、例えばServer Componentsと統合してサーバー上で完全に実行されるように設計されたTwitter埋め込みreact-tweetも使用できます。
import { Tweet } from 'react-tweet';
export default async function Page() {
return <Tweet id="790942692909916160" />;
}
ルーターがReact Suspenseと統合されているため、コンテンツの一部がローディング中により流動的にフォールバックコンテンツを表示し、必要に応じて段階的にコンテンツを表示できます。
import { Suspense } from 'react';
import { PostFeed, Weather } from './components';
export default function Page() {
return (
<section>
<Suspense fallback={<p>Loading feed...</p>}>
<PostFeed />
</Suspense>
<Suspense fallback={<p>Loading weather...</p>}>
<Weather />
</Suspense>
</section>
);
}
さらに、ルーターはページナビゲーションをトランジションとしてマークし、ルート遷移を中断可能にします。
自動サーバーレンダリングとコード分割
Next.jsを作成したとき、開発者がReactアプリケーションを実行するためにwebpack、babel、その他のツールを手動で設定することはまだ一般的でした。サーバーレンダリングやコード分割などのさらなる最適化は、カスタムソリューションでは実装されないことが多くありました。
Next.jsは、他のReactフレームワークと同様に、これらのベストプラクティスを実装し、強制するための抽象化レイヤーを作成しました。ルートベースのコード分割は、pages/ディレクトリ内の各ファイルが