Monday, February 11th 2019
Next.js 8
投稿者本日、プロダクションレディなNext.js 8をリリースできることを誇りに思います。主な機能は以下の通りです。
- サーバーレス Next.js
- ビルド時のメモリ使用量を大幅に削減
- ビルド時環境設定
- プリフェッチパフォーマンスの向上
- 初期HTMLサイズを縮小
- オンデマンドエントリの改善
- 開発時のポートリスニングを高速化
- 静的エクスポートを高速化
- Head要素の重複排除
- 新しいcrossOrigin設定オプション
- インラインJavaScriptを削除
- API認証の例
いつものように、これらのメリットが完全に後方互換性があることを確認するよう努めてきました。ほとんどのNext.jsアプリケーションでは、実行する必要があるのは
npm i next@latest react@latest react-dom@latestコミュニティと私たちの成功を信じてくれたすべての人々に感謝します。前回のブログ投稿以降、AT&T、Starbucks、Twitchのような企業がNext.jsで公開向けのウェブサイトやアプリケーションを再構築しています。
サーバーレス Next.js
サーバーレスデプロイメントは、アプリケーションをより小さな部分(ラムダとも呼ばれます)に分割することで、信頼性とスケーラビリティを劇的に向上させます。Next.jsの場合、pagesディレクトリ内の各ページがサーバーレスラムダになります。
サーバーレスには数多くのメリットがあります。参照されているリンクはExpressの文脈でいくつかのメリットについて説明していますが、原則は普遍的に適用されます。サーバーレスは、分散された障害点、無限のスケーラビリティを可能にし、"使用した分だけ支払う"モデルで信じられないほど手頃な価格です。
Next.jsでサーバーレスモードを有効にするには、next.config.jsにserverlessビルドtargetを追加します。
module.exports = {
target: 'serverless',
};serverlessターゲットは、ページごとに1つのラムダを生成します。このファイルは完全にスタンドアロンであり、実行するために依存関係は必要ありません。
pages/index.js=>.next/serverless/pages/index.jspages/about.js=>.next/serverless/pages/about.js
Next.jsサーバーレス関数のシグネチャは、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ディレクトリの各ページがサーバーレス関数(ラムダ)になります。- 最小限のサーバーレス関数(50 KBのベースzipサイズ)を作成します。
- 高速なコールドスタートのために最適化されています。
- サーバーレス関数には依存関係が0個です(関数バンドルに含まれています)。
- Node.jsのhttp.IncomingMessageおよびhttp.ServerResponseを使用します。
next.config.jsでtarget: 'serverless'を使用してオプトインします。serverターゲットは引き続き完全にサポートされ、メンテナンスされています。serverlessモードではpublicRuntimeConfigおよびserverRuntimeConfigはサポートされていません。代わりにビルド時設定を使用してください。
ビルド時のメモリ使用量を大幅に削減
webpackに貢献し、Next.js(および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ページが表示され、エラーが発生したことを示します。
Next.jsの最初のリリース以来、/_errorページのスクリプトタグは初期HTMLの一部であり、ランタイムエラーが発生しなかった場合でもロードされていました。
Next.js 8以降、/_errorページはエラー発生時にオンデマンドでロードされます。
これにより、デフォルトでロード、解析、実行されるコード量が少なくなります。
DXの改善
Next.jsの主な目標の1つは、可能な限り最高の開発者体験で最高のプロダクションパフォーマンスを提供することです。このリリースには、ユーザーからのフィードバックに基づいた多くの微妙な改善が含まれています。
オンデマンドエントリの改善
Next.jsは、デフォルトで、*アクティブに*開発されているページのみをコンパイルします。Next.jsは、next devを実行するたびにすべてのページをコンパイルするわけではありません。代わりに、ページにアクセスするとページがコンパイルされます。
例えば、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以降、next exportを介した静的レンダリングは、マシンに複数のCPUがある場合に速度が向上します。
4 CPUコアのMacBookでのテストに基づき、すべてのコアを活用してページをプリレンダリングすることで、エクスポート速度が約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',
};このオプションを導入するもう1つの利点は、アプリケーションでcross-originを設定するために、カスタムpages/_document.jsが不要になったことです。
以前の動作は引き続きサポートされますが、開発者の方が新しいオプションに移行するのを支援するために、開発中は警告が表示されます。
インラインJavaScriptを削除
Next.js 7以前を使用する場合、Content Security Policy (CSP)を有効にするには、Next.jsがデータ(例えばgetInitialPropsの結果)をクライアントに渡すためにインライン<script>タグを作成していたため、ポリシーにscript-src 'unsafe-inline'を含める必要がありました。
Next.js 8では、このインラインスクリプトタグをJSONタグに変更し、クライアントへの安全な転送を可能にしました。これは、Next.jsによってインラインスクリプトが一切含まれなくなったことを意味します。
慎重な検討により、script-src 'self'が使用できるようになりました。
API認証の例
Next.jsでの外部API(任意のAPI、任意のプログラミング言語)に対する認証方法について、これまでで最も要望の多い例の1つでした。
Next.js 8の導入に伴い、新しく作成された例:with-cookie-authも導入します。
この例は、外部Node.js APIへの認証方法を示していますが、適用される概念はステートレスAPIにも有効です。
この例では、サーバーサイドとクライアントサイドのレンダリング間でトークンを共有するためにCookieを使用しています。
これにより、アプリケーションがサーバーでレンダリングされた場合でも、ユーザーの代わりに認証されたデータをフェッチできます。
この例に貢献してくれたJuan Olveraに特に感謝します。
コミュニティ
最初のリリース以来、Next.jsはFortune 500企業から個人のブログまで、あらゆるものに使用されてきました。Next.jsの採用が継続的に拡大しているのを見るのは非常にエキサイティングです。
- 600人以上のコントリビューターが少なくとも1つのコミットを投稿しました。
- GitHubでは、プロジェクトは34,400回以上スターを獲得しました。
- 最初のリリース以降、2600件以上のプルリクエストが提出されました。
Next.jsコミュニティには4,570人以上のメンバーがいます。参加しましょう!