本日、Next.js 9.3のリリースを発表できることを嬉しく思います。主な新機能は以下の通りです:
- 次世代静的サイト生成 (SSG) サポート: 新しいデータ取得メソッドによる最適化された静的生成
- プレビューモード: 静的生成ページをバイパスしてCMSの下書きを表示
- グローバルスタイルシートのSassネイティブサポート:
.scss
ファイルをグローバルスタイルシートとして直接インポート可能 - コンポーネントレベルのSass CSSモジュールサポート:
.module.scss
規約を使用したローカルスコープCSSのサポート - 404ページの自動静的最適化: 404ページを静的に提供することで速度と信頼性を向上
- 32kB小さなランタイム: 最適化により全Next.jsアプリケーションのランタイムサイズを削減
- GitHub DiscussionsのNext.jsコミュニティ: Next.jsリポジトリ上で直接ディスカッションや質問が可能に
これらの機能はすべて非破壊的で完全な後方互換性があります。更新するには以下を実行するだけです:
npm i next@latest react@latest react-dom@latest
次世代静的サイト生成 (SSG) サポート
ウェブサイトやアプリケーションを構築する際、一般的に2つの戦略から選択する必要があります: 静的生成 (SSG) またはサーバーサイドレンダリング (SSR) です。
Next.jsは初のハイブリッドフレームワークで、ページごとに最適な手法を選択できます。
Next.js 9.0では自動静的最適化の概念が導入されました。getInitialProps
のようなブロッキングデータ取得要件がないページは、ビルド時に自動的にHTMLにレンダリングされます。
ブロッキングデータ取得要件があっても、ビルド時にページを静的なHTMLとしてレンダリングしたいケースはさらに多くあります。例としては、(ヘッドレス)コンテンツ管理システム(CMS)で動くマーケティングページや、サイトのブログセクションなどがあります。
私たちはHashiCorpのようなSSGとnext export
のヘビーユーザーと協力し、Next.js史上最もコメントの多いRFCでコミュニティと徹底的に議論を重ね、データ取得と静的生成の新しい統一的な方法を作り上げました。
本日、2つの新しいデータ取得メソッドを発表できることを大変嬉しく思います: getStaticProps
と getServerSideProps
。また、動的ルートに対して静的に生成するパラメータを提供する方法として getStaticPaths
も含まれています。
これらの新しいメソッドには、getInitialProps
モデルに比べて多くの利点があり、SSGとSSRの違いが明確になっています。
getStaticProps
(静的生成): ビルド時にデータを取得getStaticPaths
(静的生成): データに基づいてプリレンダリングする動的ルートを指定getServerSideProps
(サーバーサイドレンダリング): 各リクエストごとにデータを取得- これらの改善はAPI追加です。すべての新機能は完全な後方互換性があり、段階的に導入できます。非推奨は導入されておらず、
getInitialProps
は現在通り機能し続けます。新しいページやプロジェクトではこれらの新しいメソッドの採用を推奨します。
getStaticProps
ページからgetStaticProps
というasync
関数をエクスポートすると、Next.jsはビルド時にこのページをプリレンダリングします。これは特にCMSから特定の静的ページをレンダリングしたい場合に有用です。
getStaticProps
は常にNode.jsコンテキストで実行され、コードは自動的にツリーシェイクされてブラウザバンドルから除外されるため、ブラウザに送信されるコードが少なくなります。これにより、Node.jsとブラウザ環境の間で一貫性のないデータ取得コードの実行について心配する必要がなくなります。
これにより、fetch
、REST、GraphQL、または直接データベースにアクセスするなど、あらゆる非同期または同期データ取得技術を使用できます。
export async function getStaticProps(context) {
return {
props: {}, // ページコンポーネントにpropsとして渡されます
};
}
context
パラメータは以下のキーを含むオブジェクトです:
params
: 動的ルートを使用するページのルートパラメータを含みます。例えば、ページ名が[id].js
の場合、params
は{ id: ... }
のようになります。詳細は動的ルーティングドキュメントを参照してください。これは後で説明するgetStaticPaths
と一緒に使用する必要があります。
以下は、CMSからブログ投稿リストを取得するためにgetStaticProps
を使用する例です:
// 任意のデータ取得ライブラリを使用できます
import fetch from 'node-fetch';
// postsはgetStaticProps()によってビルド時に設定されます
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
);
}
// この関数はビルド時にNode.js環境で呼び出されます
// クライアントサイドでは呼び出されないので、
// 直接データベースクエリも可能です。「技術的詳細」セクションを参照
export async function getStaticProps() {
// 外部APIエンドポイントを呼び出して投稿を取得
const res = await fetch('https://.../posts');
const posts = await res.json();
// { props: posts }を返すことで、Blogコンポーネントは
// ビルド時に`posts`をpropsとして受け取ります
return {
props: {
posts,
},
};
}
export default Blog;
getStaticPropsはいつ使うべきか?
以下の場合にgetStaticProps
を使用するべきです:
- ページをレンダリングするために必要なデータがユーザーリクエスト前にビルド時に利用可能
- データがヘッドレスCMSから来る場合
- データが公開キャッシュ可能(ユーザー固有でない)場合
- ページがプリレンダリング(SEOのため)され、非常に高速である必要がある場合 -
getStaticProps
はHTMLとJSONファイルを生成し、どちらもCDNでキャッシュ可能
getStaticProps
の詳細についてはデータ取得ドキュメントを参照してください。
getStaticPaths
ページが動的ルートを持ち、getStaticProps
を使用する場合、ビルド時にHTMLにレンダリングする必要があるパスのリストを定義する必要があります。
動的ルートを使用するページからgetStaticPaths
というasync
関数をエクスポートすると、Next.jsはgetStaticPaths
で指定されたすべてのパスを静的にプリレンダリングします。
export async function getStaticPaths() {
return {
paths: [
{ params: { ... } } // 「paths」セクションを参照
],
fallback: true or false // 「fallback」セクションを参照
};
}
pathsキー(必須)
pathsキーはどのパスがプリレンダリングされるかを決定します。例えば、pages/posts/[id].js
という動的ルートを使用するページがあるとします。このページからgetStaticPaths
をエクスポートし、pathsに対して以下を返す場合:
return {
paths: [
{ params: { id: 1 } },
{ params: { id: 2 } }
],
fallback: ...
}
Next.jsはpages/posts/[id].js
のページコンポーネントを使用して、ビルド時にposts/1
とposts/2
を静的に生成します。
各params
の値はページ名で使用されるパラメータと一致する必要があります:
- ページ名が
pages/posts/[postId]/[commentId]
の場合、params
にはpostId
とcommentId
が含まれる必要があります - ページ名が
pages/[...slug]
のようなキャッチオールルートを使用する場合、params
には配列であるslug
が含まれる必要があります。例えば、この配列が['foo', 'bar']
の場合、Next.jsは/foo/bar
でページを静的に生成します
fallbackキー(必須)
getStaticPathsが返すオブジェクトにはbooleanのfallbackキーが含まれている必要があります。
fallback: false
fallback
がfalse
の場合、getStaticPaths
で返されないパスは404ページになります。これはすべてのパスがビルド時にわかっている場合に有用です。
以下はpages/posts/[id].js
というページごとに1つのブログ投稿をプリレンダリングする例です。ブログ投稿のリストはCMSから取得され、getStaticPaths
で返されます。その後、各ページに対して、getStaticProps
を使用してCMSから投稿データを取得します。
import fetch from 'node-fetch';
function Post({ post }) {
// 投稿をレンダリング...
}
// この関数はビルド時に呼び出されます
export async function getStaticPaths() {
// 外部APIエンドポイントを呼び出して投稿を取得
const res = await fetch('https://.../posts');
const posts = await res.json();
// 投稿に基づいてプリレンダリングするパスを取得
const paths = posts.map((post) => `/posts/${post.id}`);
// ビルド時にこれらのパスのみをプリレンダリング
// { fallback: false }は他のルートが404になることを意味します
return { paths, fallback: false };
}
// これもビルド時に呼び出されます
export async function getStaticProps({ params }) {
// paramsには投稿`id`が含まれます
// ルートが/posts/1のような場合、params.idは1です
const res = await fetch(`https://.../posts/${params.id}`);
const post = await res.json();
// props経由でページに投稿データを渡す
return { props: { post } };
}
export default Post;
fallback: true
fallback
がtrue
の場合、getStaticProps
の動作が変わり、Next.jsは提供されたパスをビルド時にHTMLにレンダリングします。ビルド時に生成されなかったパスは、ユーザーがページをリクエストしたときにオンデマンドで生成されます。
これは、アプリケーションに静的に生成可能な多くのルートがあるが、ビルド時にページのサブセットのみを生成することでビルド時間の増加を避けたい場合に有用です。
ページの生成をトリガーするユーザーにはフォールバックHTMLが提供されます。これは一般的にローディング状態のページです。これは、静的なHTMLがCDNから提供されるため、ページがまだ生成されていなくても常に高速であることを保証するためです。
追加ページをオンデマンドで静的に生成する例:
import { useRouter } from 'next/router';
import fetch from 'node-fetch';
function Post({ post }) {
const router = useRouter();
// ページがまだ生成されていない場合、
// getStaticProps()の実行が終わるまでこれが表示されます
if (router.isFallback) {
return <div>Loading...</div>;
}
// 投稿をレンダリング...
}
// この関数はビルド時に呼び出されます
export async function getStaticPaths() {
return {
// `/posts/1`と`/posts/2`のみがビルド時に生成されます
paths: [{ params: { id: 1 } }, { params: { id: 2 } }],
// 追加ページを静的に生成可能に
// 例: `/posts/3`
fallback: true,
};
}
// これもビルド時に呼び出されます
export async function getStaticProps({ params }) {
// paramsには投稿`id`が含まれます
// ルートが/posts/1のような場合、params.idは1です
const res = await fetch(`https://.../posts/${params.id}`);
const post = await res.json();
// props経由でページに投稿データを渡す
return { props: { post } };
}
export default Post;
getStaticPaths
の詳細についてはデータ取得ドキュメントを参照してください。
getServerSideProps
ページからgetServerSideProps
というasync
関数をエクスポートすると、Next.jsはこのページを各リクエストごとにサーバーサイドレンダリング (SSR) で描画します。
getServerSideProps
は常にサーバーサイドで実行され、コードは自動的にブラウザバンドルからツリーシェイクされます。これにより、ブラウザに送信されるコード量が削減されます。このため、サーバーとブラウザ環境間でデータ取得コードの実行に一貫性がない問題を気にする必要がなくなります。多くの場合、サーバーはデータソースへのより高速な接続を持っているため、パフォーマンスが向上します。また、データ取得ロジックの露出を減らすことでセキュリティも向上します。
これにより、fetch
、REST、GraphQL、さらにはデータベースへの直接アクセスを含む、あらゆる非同期または同期データ取得技術を使用できます。
next/link
を使用してページ間を移動する場合、ブラウザでgetServerSideProps
を実行する代わりに、Next.jsはサーバーに対してfetchを実行し、getServerSideProps
の呼び出し結果を返します。
export async function getServerSideProps(context) {
return {
props: {}, // ページコンポーネントにpropsとして渡されます
};
}
context
パラメータは以下のキーを含むオブジェクトです:
params
: このページがダイナミックルートを使用している場合、params
にはルートパラメータが含まれます。ページ名が[id].js
の場合、params
は{ id: ... }
のようになります。詳細については、ダイナミックルーティングのドキュメントをご覧ください。req
: HTTPリクエストオブジェクト。res
: HTTPレスポンスオブジェクト。query
: クエリ文字列。
以下は、getServerSideProps
を使用してリクエスト時にデータを取得し、それをレンダリングする例です:
function Page({ data }) {
// データをレンダリング...
}
// これは各リクエストで呼び出されます
export async function getServerSideProps() {
// 外部APIからデータを取得
const res = await fetch(`https://.../data`);
const data = await res.json();
// propsを介してページにデータを渡す
return { props: { data } };
}
export default Page;
getServerSideProps
の詳細については、データ取得ドキュメントを参照してください。
プレビューモード
この投稿で前述したように、静的生成 (Static Generation) はページがヘッドレスCMSからデータを取得する場合に有用です。しかし、ヘッドレスCMSで下書きを書いていて、その下書きをすぐにページでプレビューしたい場合には理想的ではありません。出力が静的であるため、変更をプレビューするのが難しくなります。その静的ページを再生成する必要があるからです。
Next.jsのgetStaticProps
の導入により、特定の条件下でNext.jsのオンデマンドレンダリング機能を活用するなど、新しい可能性が開けました。
例えば、ヘッドレスCMSの下書きをプレビューする場合、静的レンダリングをバイパスし、公開済みのコンテンツではなく下書きコンテンツでページをオンデマンドでレンダリングしたいでしょう。この特定のケースでのみ、Next.jsに静的生成をバイパスさせたいはずです。
このニーズに対応するため、Next.jsの新しい組み込み機能を発表できることを嬉しく思います: プレビューモードです。
プレビューモードでは、ユーザーは静的に生成されたページをバイパスし、例えばCMSからの下書きページをオンデマンドでサーバーサイドレンダリング (SSR) できます。
ただし、特定のCMSシステムに限定されません。プレビューモードはgetStaticProps
とgetServerSideProps
の両方と直接統合されているため、あらゆるタイプのデータ取得ソリューションで使用できます。
プレビューモードは、next start
を使用する場合、またはVercel Edge Networkにデプロイすることでシームレスに利用可能です。
プレビューモードを実際に試すには、https://next-preview.vercel.app/にアクセスしてください。
プレビューモードの詳細については、ドキュメントを参照してください。
CMSプロバイダーとの協業
getStaticProps
を使用すると、CMSシステムを含むあらゆるデータソースからデータを取得できます
私たちは、Next.jsとの統合に関する例やガイドを提供するため、CMSエコシステムの多くの主要プレイヤーと積極的に協力しています。
現在積極的に取り組んでいる例には以下があります:
あなたの会社がCMSエコシステムで活動している場合、ぜひ協力したいと思います!私たちのチームにメールまたはTwitterでご連絡ください。
グローバルスタイルシートのための組み込みSassサポート
Next.js 9.2では、より最適化された結果を提供するため、next-css
プラグインを置き換えるグローバルCSSスタイルシートの組み込みサポートが導入されました。
リリース直後、多くの企業がNext.jsに移行する際にSassベースの既存のデザインシステムを持っているため、Sassサポートの統合を求める声が増えました。
Next.jsプラグインの使用状況を調査したところ、約30%のNext.jsアプリケーションが現在next-sass
を使用していることがわかりました。比較すると、44%がバニラCSS、6%がLessを使用しています。
さらに、next-sass
にはnext-css
と同じ制約の欠如がありました。つまり、プロジェクトのすべてのファイルでSassファイルをインポートできましたが、このインポートされたSassファイルはアプリケーション全体でグローバルになります。
これらの統計とフィードバックを考慮した結果、Next.jsに組み込みのSassスタイルシートインポートサポートが追加されたことを嬉しく思います。
アプリケーションでグローバルSassインポートを使用するには、まずsass
をインストールしてください:
npm install sass
次に、pages/_app.js
内でSassファイルをインポートします。
例えば、プロジェクトのルートにstyles.scss
という名前のスタイルシートがある場合:
$primary-color: #333;
body {
padding: 20px 20px 60px;
margin: 0;
color: $primary-color;
}
まだ存在しない場合はpages/_app.js
ファイルを作成します。その後、styles.scss
ファイルをインポートします:
import '../styles.scss';
// このデフォルトエクスポートは新しい`pages/_app.js`ファイルで必要です。
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
スタイルシートは本質的にグローバルであるため、カスタム<App>
コンポーネントでインポートする必要があります。これは、グローバルスタイルのクラス名と順序の衝突を避けるために必要です。
開発時には、この方法でスタイルシートを表現すると、編集時にページ上のスタイルが自動的に更新されます。
本番環境では、すべてのSassとCSSファイルが自動的に単一のminified .css
ファイルに連結されます。このCSSファイルは<link>
タグを介してロードされ、Next.jsが生成するデフォルトのHTMLマークアップに自動的に注入されます。
この新機能は完全に後方互換性があります。@zeit/next-sass
や他のCSS関連プラグインを使用している場合、競合を避けるためにこの機能は無効になります。
現在@zeit/next-sass
を使用している場合は、next.config.js
とpackage.json
からプラグインを削除し、アップグレード時に組み込みのSassサポートに移行することをお勧めします。
コンポーネントレベルのスタイルのための組み込みSass CSSモジュールサポート
Next.jsは現在、[name].module.scss
ファイル命名規則を使用して、SassファイルでのCSSモジュールをサポートしています。
以前Next.js 5+でnext-sass
を使用して利用可能だったサポートとは異なり、グローバルSassとCSSモジュールが共存できるようになりました - next-sass
では、アプリケーション内のすべての.scss
ファイルをグローバルまたはローカルのいずれかとして処理する必要がありましたが、両方はできませんでした。
CSSモジュールは、一意のクラス名を自動的に作成することでSassをローカルスコープにします。これにより、異なるファイルで同じSassクラス名を使用しても衝突を心配する必要がなくなります。
この動作により、CSSモジュールはコンポーネントレベルのSassを含める理想的な方法となります。CSSモジュールファイルはアプリケーションのどこでもインポートできます。
アプリケーションでSass CSSモジュールを使用するには、まずsass
がインストールされていることを確認してください:
npm install sass
次に、components/
フォルダ内の再利用可能なButton
コンポーネントを考えてみましょう:
まず、以下の内容でcomponents/Button.module.scss
を作成します:
/*
他の`.css`や`.module.css`ファイルとの衝突を心配する必要はありません!
*/
$color: white;
.error {
color: $color;
background-color: red;
}
次に、components/Button.js
を作成し、上記のCSSファイルをインポートして使用します:
import styles from './Button.module.scss';
export function Button() {
return (
<button
type="button"
// インポートした`styles`オブジェクトのプロパティとして"error"クラスにアクセスする方法に注目
className={styles.error}
>
Destroy
</button>
);
}
SassファイルのCSSモジュールはオプション機能であり、.module.scss
拡張子を持つファイルに対してのみ有効になります。通常の<link>
スタイルシートとグローバルSassスタイルも引き続きサポートされます。
本番環境では、すべてのCSSモジュールファイルが自動的に多くのminifiedおよびコード分割された.css
ファイルに連結されます。これらの.css
ファイルはアプリケーション内のホットエグゼキューションパスを表し、アプリケーションが描画するためにページごとに最小限のCSSがロードされることを保証します。
上記と同様に、この新機能は完全に後方互換性があります。@zeit/next-sass
や他のCSS関連プラグインを使用している場合、競合を避けるためにこの機能は無効になります。
現在@zeit/next-sass
を使用している場合は、next.config.js
とpackage.json
からプラグインを削除し、組み込みのSassサポートに移行することをお勧めします。
404の自動静的最適化
Next.js 9のリリースでは、ページにブロッキングデータ要件がない場合に自動静的最適化の概念が導入されました。Next.jsはビルド時に自動的にページを静的HTMLとして生成します。しかし、自動的に静的HTMLとしてレンダリングされないページが1つありました: 404ページです。404ページが自動的に静的にならなかった主な理由は、404を処理する/_error
ページが404だけでなくエラーなども処理していたためです。
存在しないルートに対して404ページがレンダリングされるため、オンデマンドでページをレンダリングするとコストとサーバー負荷が増加する可能性があります。
私たちは2つの方法であなたを成功に導くことを目指しました:
- デフォルトのNext.jsエクスペリエンスでは静的404ページが生成されます
- 404ページをカスタマイズする場合でも、静的ページになることが保証されます
この機能は完全に後方互換性があるため、現在カスタムpages/_error.js
を持っている場合、pages/404.js
を追加するまで404ページに引き続き使用されます。
デフォルトの静的404ページ
アプリケーションにカスタムpages/_error.js
ページがない場合、Next.jsは自動的に404ページを静的に生成し、404を提供する必要があるときにそれを使用します。これは自動的に行われ、変更は必要ありません。
pages/404.jsを使用したカスタム404ページ
デフォルトの404ページを上書きするには、pages/404.js
を作成できます。これもビルド時に自動的に静的に最適化されます。このページは、アプリケーションに存在する場合、404をレンダリングするためにpages/_error.js
の代わりに使用されます。
export default () => <h1>This is the 404 page</h1>;
32kB以上小さいランタイム (15kB+ Gzip)
Next.jsはReact自体と同じブラウザをサポートしており、設定は不要です。これにはInternet Explorer 11 (IE11)とすべての主要なブラウザ(Edge、Firefox、Chrome、Safari、Operaなど)が含まれます。
この互換性の一環として、アプリケーションをIE11互換にコンパイルします: これにより、ES6+構文機能、Async/Await、オブジェクトのRest/Spreadプロパティなどを安全に使用できます - すべて設定不要で利用可能です。
このコンパイルプロセスの一部として、必要な機能ポリフィル(例: Array.from
やSymbol
)も透過的に注入されます。ただし、これらのポリフィルはウェブトラフィックの10%未満、ほとんどの場合IE11をサポートするためにのみ必要です。
Next.js 9.3以降、Next.jsはレガシーブラウザをサポートするために必要なポリフィルを自動的にロードし、これらのレガシーブラウザでのみポリフィルをロードします。
実際には、これはユーザーの90%以上にとって、_初回読み込み_サイズから32kB以上が削減されることを意味します。
これらのサイズ節約は、さらに多くのブラウザ機能に依存する大きなアプリケーションではさらに大きくなります。
この最適化は完全に自動的であり、この利点を活用するためにアプリケーションの変更は必要ありません!
コミュニティ
Next.jsの採用が継続的に成長しているのを見て非常に興奮しています:
- 927名以上の独立したコントリビューターがいます。
- GitHubでは、プロジェクトが46,600回以上スターされています。
- examplesディレクトリには226以上の例があります。
Next.jsコミュニティには現在15,250人以上のメンバーがいます。コミュニティは現在GitHubディスカッションで見つけることができ、コミュニティが議論し質問する新しい場所です!参加してください!
私たちはコミュニティと、このリリースを形作るのに役立ったすべての外部フィードバックと貢献に感謝しています。
新しいデータ取得方法に関する重要なフィードバックを提供してくれたJeff Escalanteに特に感謝します。
このリリースに貢献してくれたすべての方々に大感謝です: @arcanis, @lgordey, @ijjk, @martpie, @jaywink, @fabianishere, @dijs, @TheRusskiy, @quinnturner, @timneutkens, @lfades, @vvo, @adithwip, @rafaelalmeidatk, @bmathews, @Spy-Seth, @EvgeniyKumachev, @chibicode, @piglovesyou, @HaNdTriX, @Timer, @janicklas-ralph, @devknoll, @prateekbh, @ethanryan, @MoOx, @rifaidev, @msweeneydev, @motiko, and @balazsorban44 for helping!