2019年2月11日(月)
Next.js 8
投稿者本日、本番環境対応のNext.js 8を発表できることを誇りに思います。主な機能は以下の通りです。
- Serverless Next.js
- ビルド時のメモリ使用量の大幅な削減
- ビルド時環境設定
- プリフェッチ性能の向上
- 初期HTMLサイズの縮小
- オンデマンドエントリーの改善
- 開発中のポートリスニングの高速化
- 静的エクスポートの高速化
- Head要素の重複排除
- 新しいcrossOrigin設定オプション
- インラインJavaScriptの削除
- API認証の例
常にそうであるように、これらの利点がすべて完全に後方互換性があることを保証するよう努めてきました。ほとんどのNext.jsアプリケーションでは、以下のコマンドを実行するだけで済みます。
npm i next@latest react@latest react-dom@latest
コミュニティの皆様、そして私たちの成功に賭けてくださったすべての方々に感謝いたします。前回のブログ投稿以来、AT&T、スターバックス、そしてTwitchといった企業がNext.jsで公開ウェブサイトやアプリを再起動するのを見てきました。
Serverless Next.js
Serverlessデプロイは、アプリケーションをより小さな部分(ラムダとも呼ばれます)に分割することで、信頼性とスケーラビリティを劇的に向上させます。Next.jsの場合、pages
ディレクトリ内の各ページがサーバーレスラムダになります。
サーバーレスには多くの利点があります。参照リンクではExpressの文脈でその一部が述べられていますが、原則は普遍的に適用されます。サーバーレスは、分散された障害点、無限のスケーラビリティを可能にし、「使用した分だけ支払う」モデルで信じられないほど手頃な価格です。
Next.jsでサーバーレスモードを有効にするには、next.config.js
にserverless
ビルドtarget
を追加します
module.exports = {
target: 'serverless',
};
serverless
ターゲットは、ページごとに単一のラムダを出力します。このファイルは完全にスタンドアロンであり、実行に依存関係を必要としません
pages/index.js
=>.next/serverless/pages/index.js
pages/about.js
=>.next/serverless/pages/about.js
Next.jsのServerless関数のシグネチャは、Node.jsのHTTPサーバーコールバックに似ています
type Function = (req: http.IncomingMessage, res: http.ServerResponse) => void;
- http.IncomingMessage
- http.ServerResponse
void
は関数が戻り値を持たないことを指し、JavaScriptのundefined
と同等です。関数を呼び出すとリクエストが完了します。
Next.jsは、ホスティングプラットフォームによって関数シグネチャが異なるため、サーバーレスデプロイメント向けの低レベルAPIを提供します。一般的には、Next.jsのサーバーレスビルドの出力を互換性レイヤーでラップすることをお勧めします。
例えば、プラットフォームがNode.jsのhttp.Serverクラスをサポートしている場合
const http = require('http');
const page = require('./.next/serverless/about.js');
const server = new http.Server((req, res) => page.render(req, res));
server.listen(3000, () => console.log('Listening on https://:3000'));
概要
- サーバーレスデプロイメントを実装するための低レベルAPI
pages
ディレクトリ内のすべてのページがサーバーレス関数(ラムダ)になります- 最小サイズのサーバーレス関数を作成します(ベースzipサイズ50 KB)
- 関数の高速なコールドスタートに最適化
- サーバーレス関数は依存関係を持ちません(関数バンドルに含まれています)
- Node.jsのhttp.IncomingMessageとhttp.ServerResponseを使用
next.config.js
でtarget: 'serverless'
を使用してオプトインserver
ターゲットは引き続き完全にサポートおよび維持されますpublicRuntimeConfig
とserverRuntimeConfig
はserverless
モードではサポートされていません。代わりにビルド時設定を使用してください。
ビルド時のメモリ使用量の大幅な削減
Next.js(およびwebpackエコシステムのその他すべて)のビルド性能とリソース利用率を向上させるために、webpackに貢献してきました。
この取り組みにより、性能を劣化させることなく最大16倍のメモリ使用量改善が実現しました。
メモリがはるかに迅速に解放され、多くの負荷(多数のページ)がかかってもプロセスがクラッシュすることがなくなりました。
この最適化をどのように達成したかについては、近日中に詳しく説明します。Next.jsブログにご注目ください。
ビルド時環境設定
Next.jsアプリケーションをレビューする中で、アプリケーションに設定値を提供するためにbabel-plugin-transform-define
またはwebpack.DefinePlugin
を追加するというパターンが頻繁に観察されました。
Next.js 8では、後方互換性を保ちながら同じ機能を提供するために、next.config.js
にenv
という新しいキーを導入します
module.exports = {
env: {
customKey: 'MyValue',
},
};
これにより、コード内でprocess.env.customKey
を使用できるようになります。例えば
export default function IndexPage() {
return <h1>The value of customKey is: {process.env.customKey}</h1>;
}
process.env.customKey
はビルド時に'MyValue'
に置き換えられます。
プリフェッチ性能の向上
Next.jsルーターは、ページをプリフェッチしてより高速なナビゲーションを可能にします
import Link from 'next/link';
export default function IndexPage() {
return (
<>
<Link href="/about" prefetch>
<a>To About Page</a>
</Link>
</>
);
}
これは、prefetch
属性を持つすべてのリンクのJavaScriptバンドルをプリフェッチすることで機能します。
Next.js 8より前のバージョンでは、これはドキュメントの<body>
に<script>
タグを挿入することを意味していました。
しかし、これによりページを開く際にいくつかのオーバーヘッドが発生し、特にブラウザの「読み込み中」表示が、ページがすでに操作可能であるにもかかわらず、予想よりも長く表示されることがありました。
Next.js 8では、prefetch
は<script>
タグの代わりに<link rel="preload">
を使用します。また、ブラウザがリソースを管理できるように、onload
後にのみプリフェッチを開始します。
さらに、Next.jsは2Gインターネットとnavigator.connection.saveData
モードを検出し、低速なネットワーク接続でのプリフェッチを無効にするようになりました。
初期HTMLサイズの縮小
Next.jsがHTMLをプリレンダリングする際、ページを<html>
、<head>
、<body>
、およびページをレンダリングするために必要なJavaScriptファイルを含むデフォルトの構造でラップします。
Next.js 7では、初期ペイロードを1.50KBに最適化し、これは以前のバージョンから7.4%の削減でした。
さらに初期ペイロードサイズを1.16KBに削減し、さらに23%の削減を達成しました
7.0 | 8.0 | 差分 | |
---|---|---|---|
ドキュメントサイズ(サーバーレンダリング) | 1.50KB | 1.16KB | 23% 縮小 |
サイズを削減した主な方法は以下の通りです
- ページ初期化のインラインスクリプトが削除されました
/_error
ページがすべてのページ読み込みに含まれなくなりました
/_errorのオンデマンド読み込み
本番環境でエラーが発生した場合、エラーが発生したことを表示するために/_error
ページがレンダリングされます。
Next.jsの最初のリリース以来、/_error
ページのスクリプトタグは初期HTMLの一部であり、これはランタイムエラーがない場合には使用されないにもかかわらず読み込まれていたことを意味します。
Next.js 8からは、エラーが発生した際に/_error
ページがオンデマンドで読み込まれるようになりました。
これは、デフォルトで読み込まれ、パースされ、実行されるコードが少なくなったことを意味します。
DXの改善
Next.jsの主な目標の1つは、**最高の開発者体験**とともに最高のプロダクション性能を提供することです。このリリースには、ユーザーからのフィードバックに基づいた多くの細かな改善が含まれています。
オンデマンドエントリーの改善
Next.jsは、デフォルトで*積極的に*開発中のページのみを自動的にコンパイルします。next dev
が実行されるたびに、pagesディレクトリ内のすべてのページをコンパイルするわけではありません。代わりに、アクセスしたときにページをコンパイルします。
例えば、https://:3000/my-page
にアクセスすると、pages/my-page.js
ファイルがオンデマンドでコンパイルされ、その後ページがレンダリングされます。
これにより、開発者は開発サーバー起動時にすべてのページがコンパイルされるのを待つ必要がなくなります。これは大規模なアプリではかなりの時間がかかることがあります。また、バンドル時にすべてのページを考慮する必要がないため、メモリ使用量を低く抑え、コンパイラの速度を高速に保ちます。

25秒間アクセスされなかったページは、コンパイラのビルドキャッシュから破棄され、コンパイラの高速化とメモリ使用量の削減に貢献します。
Next.jsがページへのアクセスを追跡する方法は、ポーリングメカニズムを使用することです。5秒ごとに「on-demand-entries-ping」が送信され、Next.js開発サーバーに特定のページがアクセスされていることを通知します。
この機能の初期リリース以来、pingはwindow.fetch
呼び出しを使用して行われていたため、pingがトリガーされるたびにブラウザの開発ツールのconsole
とnetwork
タブに表示されていました。
最も要望の多かった機能の1つは、これらのリクエストが不要なノイズを追加する可能性があるため、ブラウザ開発者ツールから非表示にする機能です。
Next.js 8では、fetch
ベースのpingがWebSocketベースのアプローチに置き換えられたことを発表できることを嬉しく思います。これにより、pingは引き続き行われますが、WebSocket接続を検査するときにのみ表示されます。
WebSocketへの変換に協力してくれたJJ Kasperに感謝します。
開発中のポートリスニングの高速化
Next.js開発サーバーを起動すると、リクエストを処理できるように初期コンパイルを実行する必要があります。デフォルトでは、Next.jsはこのコンパイルステップが完了するまでHTTPサーバーの起動を待っていました。つまり、next dev
を実行してからブラウザにアクセスした場合、HTTPサーバーがまだ接続をリッスンしていないために「このサイトにアクセスできません」というメッセージが表示されることがありました。
Next.js 8では、コンパイルが開始される前にHTTPが接続をリッスンするようになります。つまり、コンパイルが完了する前にhttps://:3000/
にアクセスしても、ページが利用可能になるまで更新し続ける必要がなく、初期コンパイルが完了するまでリクエストが待機して処理されます。
この機能を実装してくれたBrian Beckに感謝します。
静的エクスポートの高速化
Next.jsは、高いパフォーマンスを達成するための手段として、**プリレンダリング**という考え方に焦点を当てています。プリレンダリングには2つの形式があります
- サーバーレンダリングは、各リクエストがレンダリングをトリガーするものです。その結果、エンドユーザーはデータを消費し始めるためにJavaScriptがダウンロードされるのを待つ必要がありません。
- 静的レンダリングは、サーバー上でコードを実行することなく直接提供できる静的ファイルを出力するものです。
Next.js 8から、マシンに複数のCPUがある場合、next export
による静的レンダリングの速度が向上します。
4CPUコアのMacBookでのテストによると、全コアを活用してページをプリレンダリングすることで、エクスポート速度が1秒あたり約25ページから75ページに向上しました。
Next.jsはCPUコア数を自動的に検出し、それに応じてページを分散するため、コードの変更は不要です。
この機能を実装してくれたBenjamin Knifflerに感謝します。
Head要素の重複排除
アプリケーションを構築する際によくあるニーズは、ページの<head>
要素を更新することです。例えば、レスポンシブデザインのために<title>
や<meta name="viewport">
を設定するなどです。
Next.jsは、<head>
に変更を加えるための組み込みコンポーネントを公開しています。
import Head from 'next/head';
export default function IndexPage() {
return (
<>
<Head>
<title>My page title</title>
</Head>
</>
);
}
<Head>
コンポーネントは、異なるコンポーネントで複数回使用することもできます。例えば、レイアウトコンポーネントでデフォルトのheadタグを設定できます。
ただし、デフォルトのheadタグを異なる値で上書きしたい場合があります。Next.jsの以前のバージョンでは、タグを重複排除する方法がなかったため、出力でタグが重複してしまっていました。
このため、<Head>
コンポーネント内のすべての要素にkey
プロパティを提供できるようになり、同じkey
値を持つタグが自動的に重複排除されます。
2つのタグにkey="viewport"
を設定した場合、最後のタグのみがレンダリングされます。
import Head from 'next/head';
export default function IndexPage() {
return (
<>
<Head>
<title>My page title</title>
<meta
name="viewport"
content="initial-scale=1.0, width=device-width"
key="viewport"
/>
</Head>
<Head>
<meta
name="viewport"
content="initial-scale=1.2, width=device-width"
key="viewport"
/>
</Head>
</>
);
}
セキュリティの改善
新しいcrossOrigin
設定オプション
Next.js 6では、pages/_document.js
の<Head>
と<NextScript>
にcrossOrigin
属性を追加するオプションを導入しましたが、これはcross-origin
を設定するすべてのユースケースをカバーしていませんでした。
Next.jsには、<script>
タグを動的に挿入するクライアントサイドルーターがありますが、これらのタグは挿入時にcross-origin
属性が欠落していました。
すべての<script>
タグにcross-origin
が設定されるようにするため、next.config.js
に新しい設定オプションを導入しました
module.exports = {
crossOrigin: 'anonymous',
};
このオプションを導入するもう一つの利点は、アプリケーションでcross-origin
を設定するためにカスタムのpages/_document.js
が不要になったことです。
以前の動作は引き続きサポートされますが、開発中に警告が出力され、開発者が新しく導入されたオプションに移行するのを支援します。
インラインJavaScriptの削除
Next.js 7以前を使用する場合、Content Security Policy (CSP)を有効にするには、ユーザーはポリシーにscript-src 'unsafe-inline'
を含める必要がありました。これは、Next.jsがデータを渡すため、例えばgetInitialProps
の結果をクライアントサイドに渡すためにインラインの<script>
タグを作成していたためです。
Next.js 8では、このインラインスクリプトタグをクライアントへの安全な転送のためにJSONタグに変更しました。これにより、Next.jsによってインラインスクリプトが含まれることはなくなりました。
慎重な検討により、script-src 'self'
が使用できるようになりました。
API認証の例
Next.jsで、あらゆるプログラミング言語の外部APIに対して認証を行う方法が、これまでで最も要望の多かった例の1つでした。
Next.js 8の導入に伴い、新しく作成された例であるwith-cookie-authも導入します。
この例は、外部のNode.js APIに対して認証を行う方法を示していますが、適用される概念はあらゆるステートレスAPIに適用されます。
この例では、サーバーサイドとクライアントサイドのレンダリング間でトークンを共有するためにクッキーを使用しています。
そうすることで、アプリがサーバーでレンダリングされた場合でも、ユーザーに代わって認証済みデータをフェッチできます。
この例に貢献してくれたJuan Olveraに感謝します。
コミュニティ
Next.jsは最初のリリース以来、Fortune 500企業から個人のブログまで、あらゆる場所で使用されてきました。Next.jsの採用が継続的に成長していることを大変嬉しく思います。
- 600人以上の貢献者が少なくとも1つのコミットを行ってきました。
- GitHubでは、このプロジェクトは34,400回以上スターされています。
- 最初のリリース以来、2600件以上のプルリクエストが提出されました。
Next.jsコミュニティには4,570人以上のメンバーがいます。ご参加ください!