(以下は2019年7月8日に公開された Next.js 9 の日本語和訳です。 以下原文 )
70のカナリアリリースを経て、遂に Next.js 9 がお披露目されます
主な特徴は以下です。
(訳者注* アップデート機能名は原文のまま)
Built-in Zero-Config TypeScript Support
TypeScriptサポートと統合型チェックにより信頼性を高めたアプリケーション構築を可能に。
File system-Based Dynamic Routing
カスタムサーバーなしでファイルシステムを介した複雑なアプリケーションルーティング定義を実行可能に。
Automatic Static Optimization
デフォルトでサーバーサイドレンダリングおよび静的事前レンダリングを利用することで超高速ウェブサイトの構築が可能に。
API Routes
ホットリロードと統合パイプラインを利用することで即座にバックエンドアプリケーションエンドポイントの構築が可能に。
More Production Optimizations:
ビューポート内のプリフェッチ、その他最適化によってアプリケーションはよりレスポンシブに。
Improved DX
最高の開発を支える、ささやかかつ使い易い改善の数々
これまで通り、上記全ての成果は後方互換であることを保証できるよう努めています。 Next.js アプリケーションへは、以下を実行すればよいだけです。
$ npm i next@latest react@latest react-dom@latest
稀にコードベースの変更を必要とする場合があります。詳しくは upgrade guideをご覧ください。
前回のリリース以後、IGN、Bang & Olufsen、Intercom、Buffer、そして Ferrari のような企業が Next.js でのローンチを行っていることを嬉しく思います。より多くの事例は showcase をご覧ください!!
Built-in Zero-Config TypeScript Support
1年前、Next.js 6は@zeit/next-typescript
というプラグインを通じたTypeScriptの基本的なサポート機能を導入しました。 ユーザーは、この機能を使うために自身の.babelrc
をカスタマイズし、next.config.js
を有効にする必要がありました。
このプラグインを設定することにより、Next.jsは.ts
ファイルと.tsx
ファイルを構築できるようになります。 しかし、型チェックは実装されておらず、Next.jsコアによって提供される型定義もありませんでした。 つまり、DefinitelyTyped上で、最新のリリースに同期が追い付いていない可能性のあるコミュニティパッケージを別個管理する必要がありました。
多くの新旧ユーザーに伺った結果、ほとんどのユーザーがTypeScriptを使用することに非常に興味があることが明らかになりました。ユーザーは、TypeScriptを既存または新規のコードベースに簡単に統合できる、より信頼性の高い、スタンダードソリューションを望んでいました。
これを受け、私たちはTypeScriptサポート機能をNext.jsコアに実装し、開発者エクスペリエンスの向上と開発プロセスの高速化を図りました。
Automated Setup
Next.jsでTypeScriptを使い始めるのは簡単です。ファイル、ページ、またはコンポーネントの拡張子を.js
から.tsx
に変更し、next dev
を実行してください!
これにより、Next.jsはあなたのプロジェクトでTypeScriptが使用されていることを検出します。 Next.js CLIはReactとNode.jsに必要な型定義をインストールする案内をします。
Next.jsは、tsconfig.json
が作成されていない場合、適切なデフォルト値のデフォルトtsconfig.json
を作成します。 このファイルは、Visual Studio Codeのようなエディタでの統合型チェックを可能にします。
Next.js 9 Automated TypeScript Setup 動画
Integrated Type-Checking
Next.jsは、開発とプロダクションビルド、両方であなたのために型チェックを行います。
開発の途中、ファイルを保存した際にNext.jsは型定義エラーを表示します。 型チェックはバックグラウンドで行われるため、ブラウザで更新されたアプリケーションを即座に操作できます。 型定義エラーは、利用可能になるとブラウザに伝播します。
Next.js 9 Development Type-Checking 動画
型定義エラーが検出された場合、Next.jsはプロダクションビルド(すなわち、next build
)を自動的に失敗させます。 これは、破損したコードをプロダクション環境に送り込むのを防ぐのに役立ちます。
Next.js Core Written in TypeScript
ここ数カ月の間に、私たちはコードベースの大部分をTypeScriptに移行しました。これは私たちのコード品質を強化しただけでなく、すべてのコアモジュールに型定義を提供することも可能にしました。
たとえば、next/link
をインポートすると、TypeScriptに対応したエディタであれば利用可能なプロパティやそれらが受け付ける値を表示します。
Dynamic Route Segments
ダイナミックルーティング(URLスラッグまたはプリティ/クリーンURLとも呼ばれます)は、Next.jsが2年半前にリリースされた際に、最初にGitHubにリクエストされた機能の1つでした!
Next.js 2.0では、Next.jsをプログラムで使用するためのカスタムサーバAPIを導入することで、このリクエストにお答えしました。これにより、Next.jsをレンダリングエンジンとして使用することが可能になり、特定のページをレンダリングするための着信URLの抽象化とマッピングが可能になりました。
私たちはユーザーの声を聞き、彼らのアプリケーションを調べたところ、ユーザーの多くはカスタムサーバーを使っていたことがわかりました。そして、カスタムサーバーを利用するのはダイナミックルーティングのためだという傾向が浮かび上がりました。
しかし、カスタムサーバーには独自の落とし穴があります。ルーティングはプロキシではなくサーバーレベルで処理され、モノリスとして展開・拡張され、パフォーマンス上の問題が発生しやすくなります。
カスタムサーバーでは、アプリケーション全体を1つのインスタンスで使用できるようにする必要があるため、これらの問題を解決するサーバーレス環境に展開することは通常困難です。サーバーレスリクエストはプロキシレイヤーでルーティングされ、パフォーマンスのボトルネックを回避するために独立してスケーリング/実行されます。
また、私たちはより良い開発者エクスペリエンスを提供できると考えています。 Next.jsの魔法は、pages / blog.js
という名前のファイルを作成した瞬間、/ blog
にアクセス可能なページが作成されたときから始まります。
/blog/my-first-post
(/blog/:id
)のようなルートをサポートするために、なぜユーザーは独自のサーバーを作成し、Next.jsのプログラムAPIについて学ぶ必要があるのでしょうか。
このフィードバックとビジョンを念頭に、私たちは多くのユーザーが既に知っているpages/ディレクトリを基にルートマッピングソリューションの調査を開始しました。
Creating a Dynamically Routed Page
Next.jsは、基本的な名前付きパラメータを使ったルートの作成をサポートしています。このパターンはpath-to-regexp
(Expressの動力源となるライブラリ)によって一般化されたものです。
pages
ディレクトリにpages/post/[pid].js
という名前のファイルを作成することで、/post/:pid
ルートに一致するページが作成できます。
Next.jsは/post/1
, /post/hello-nextjs
などのようなリクエストに自動的にマッチし、pages/post/[pid].js
で定義されたページをレンダリングします。 一致したURLセグメントは、[square-brackets]
の間に指定された名前でページにクエリパラメータとして渡されます。
たとえば、次のページと /post/hello-nextjs
をリクエストすると、queryオブジェクトは{pid:'hello-nextjs'}
になります。
static async getInitialProps({ query }) { // pid = 'hello-nextjs' const { pid } = query const postContent = await fetch( `https://api.example.com/post/${encodeURIComponent(pid)}` ).then(r => r.text()) return { postContent } }
複数のダイナミックURLセグメントも対応しています!
[param]
構文は、ディレクトリ名とファイル名に対応しています。つまり、次の例が成り立ちます。
./pages/blog/[blogId]/comments/[commentId].js ./pages/posts/[pid]/index.js
この機能についての詳細はread more about this feature in the Next.js Documentation 又は Next.js Learn sectionで確認できます。
Automatic Static Optimization
Next.jsは、2年ほど前にリリースされたv3で静的サイト生成に対応しました。これは当時Next.jsへの追加を最も求められていた機能でした。
それも当然で、静的サイトは文句の付けようもなく速いからです!サーバー側の計算が不要な上、CDNロケーションを通して即座にエンドユーザーへストリーミングできます。
ただし、サーバーサイドレンダリングされたアプリケーションと静的生成されたアプリケーションは2者択一で、サーバーサイドレンダリングと静的生成のどちらか一方を選ばなくてはいけませんでした。間を取るということができなかったのです。
現実には、アプリケーションごとに異なる要件があり得ます。これらの要件によって異なるレンダリング方法とトレードオフが必要となります。 例えば、ホームページとマーケティングページは一般的に静的コンテンツを含むため、静的最適化の対象として有力な候補となります。
その一方で、プロダクトダッシュボードはデータ更新を頻繁に行うサーバーサイドレンダリングを適用することにメリットがあります。
両方の利点を活かしデフォルトで速いサイトをユーザーに提供するためにどうすれば良いのか、私たちは探し始めました。ユーザーに静的マーケティングページや動的サーバーレンダリングされたページを使ってもらうにはどうすれば良いでしょうか。
Next.js 9を使い始めることで、ユーザーはフルサーバーレンダリングと静的エクスポートのどちらをアプリケーションに適用するべきか選ぶ必要がなくなります。ページ単位で両方の利点を得られるのです。
Automatic Partial Static Export
ページが静的HTMLにプリレンダリングできるか自動で判定するために、ヒューリスティックを導入しました。
これは、getInitialProps
を使うことでページにデータブロッキング要件が設定されているかを判定しています。
このヒューリスティックによって、Next.jsはサーバーレンダリングされたページと静的生成されたページの両方を備えるハイブリッドアプリケーションを出力可能となりました。
組み込みNext.jsサーバー (next start
) とプログラマティックAPI (app.getRequestHandler()
) の両方がこのビルドアウトプットを透過的に対応しています。構成や特別な処理は何も必要ありません。
静的生成されたページは引き続きリアクティブな状態です。Next.jsはアプリケーションのクライアント側をハイドレートすることで、完全な双方向性を実現します。
さらにページがURLのクエリパラメータを信頼している場合、Next.jsはハイドレーション後にアプリケーションを更新します。
開発中にページが静的に生成される場合、Next.jsはその生成を視覚的に知らせます。この視覚的成果物はクリックして非表示にできます。
また、静的生成されたページはNext.jsビルドアウトプットに表示されます。
API Routes
Reactアプリケーションを構築する際、多くのケースで何らかのバックエンドが必要となります。例えば、データをデータベースから検索する場合やユーザーから提供されたデータを処理する場合などです。(例: 問い合わせフォーム)
私たちが調べたところ、バックエンドを必要とする多くのユーザーが、カスタムサーバーを使ってAPIを構築しているようです。その結果、ユーザーはいくつかの課題を抱えています。
例えば、Next.jsはカスタムサーバーコードをコンパイルしません。つまりimport
/ export
やTypeScriptを使うことができません。
このため、多くのユーザーはカスタムサーバー上にカスタムコンパイルパイプラインを実装せざるを得ない状態になっていました。このパイプラインによって目的は達成できるのですが、同時にいくつもの落とし穴を生み出す傾向がありました。例えば、間違った構成を行ってしまった場合、ツリーシェイキングがアプリケーション全体で無効化されてしまいます。
このことはある問いを生み出しました。「Next.jsを使ったAPIバックエンド構築を可能とする開発者エクスペリエンスを提供してみてはどうだろう。」
今、Next.jsを使ってバックエンドを構築できる、ベストインクラスの開発者エクスペリエンスであるAPIルートをご紹介できることをうれしく思います。
APIルートを使うためには、まず始めにpages/
ディレクトリ内にapi
というディレクトリを作成します。
このディレクトリ内のすべてのファイルは、他のページのファイルがルートにマッピングされるのと同じ方法で、/api/<your route>
に自動マッピングされます。
例えば、pages/api/contact.js
は/api/contact
にマッピングされます。
注: APIルートはダイナミックルートにも対応しています!
pages/api/
ディレクトリ内のすべてのファイルは、Reactコンポーネントの代わりにリクエストハンドラ関数をエクスポートします。
export default function handle(req, res) { res.end('Hello World') }
* ‘req’はhttp.IncomingMessageを拡張するNextApiRequestを表します。
* ‘res’はhttp.ServerResponseを拡張するNextApiResponseを表します。
一般的には、APIエンドポイントはクエリ文字列や、リクエストボディ、クッキーなどいくつかの入力データを受け取り、他のデータを使って応答します。
APIルートのサポートをNext.jsへ追加するために調査をしていた際、私たちは、ユーザーは多くのケースでNode.jsリクエストを使うことなくオブジェクトへ直接応答していることを発見しました。ユーザーはNode.jsリクエストの代わりに、Expressのようにサーバーライブラリで提供されているアブストラクションを使っていました。
理由としては、入力データは多くの場合、何らかの形式のテキストで、まず初めに構文解析をしなければ利用できないためです。これら特定のサーバーライブラリは手動でデータを構文解析する手間を、ほとんどの場合ミドルウェアを通して、省く手助けとなります。最も広く使用されているミドルウェアではクエリ文字列や、ボディ、クッキーの構文解析を提供していますが、使用するためにある程度のセットアップ作業が求められます。
Next.js内のAPIルートは、デフォルトでこれらのミドルウェアを搭載しており、APIエンドポイントを作成する際の生産性を即座に上げることができます。
export default function handle(req, res) { console.log(req.body) // The request body console.log(req.query) // The url querystring console.log(req.cookies) // The passed cookies res.end('Hello World') }
加えて、入力データを使うことで、APIエンドポイントは一般的にデータを返します。この応答は通常JSONになります。データ送信をより簡単にするため、Next.jsはデフォルトでres.json()
を提供します。
export default function handle(req, res) { res.json({ title: 'Hello World' }) }
開発中にAPIエンドポイントを変更する場合、コードは自動でリロードされるため、サーバーをリスタートする必要がありません。
Production Optimizations
Prefetching in-Viewport<Link>
s
Next.js 9はビューポート内に表示される<Link>
コンポーネントを自動で読み込みます。
この機能によって新しいページへのナビゲーションをより早く作成でき、アプリケーションの応答性を向上できます。
Next.jsはバックグラウンドで必要なアセットを読み込むため、Intersection Observerを使用します。
これらのリクエストの優先順位は低く、fetch()
やXHRリクエストが優先されます。ユーザーがデータセーバーを有効にしている場合、Next.jsは自動読み込みを行いません。
アクセスの少ないページに対して、この機能はprefetch
プロパティをfalse
に設定することでオプトアウトできます。
<Link href="/terms" prefetch={false}> <a>Terms of Service</a> </Link>
Optimized AMP by Default
現行のNext.js 9はデフォルトで最適化されたAMPをAMPファーストおよびハイブリッドAMPページに対しレンダリングします。
AMPページがオプトインする一方で、Next.jsは自動でアウトプットを最適化します。これらの最適化によって、レンダリング速度を最大50%高速化できます!
この変更はAMPオプティマイザに対するSebastian Benzの驚異の取り組みによって実現しました。
Dead Code Elimination for typeof window Branches
Next.js 9はサーバーとクライアントビルド中に、typeof window
を適切な値(undefined
又は、object
)と置換します。この変更によって、Next.jsは自動でデッドコードを本番環境用にビルドされたアプリケーションから削除できます。
アプリケーション内のgetInitialProps
やその他の部分にサーバー専用コードがある場合、ユーザーはクライアント側バンドルサイズの減少を想定することになります。
Developer Experience Improvements
Compiling Indicator
9より前のバージョンでは、ホットコード置換が発生すること (およびNext.jsコンパイラツールチェインが動作していること) を確認する唯一の方法は、開発者コンソールを確認することでした。
ですが多くの場合、実行されているレンダリングを確認して上記の代わりとしているため、Next.jsがコンパイル動作を行っているか確認することが困難になっていました。例えば、微妙な変更をページ上のスタイルに対して行い、スタイルが更新されたかすぐに判断できない場合などでこの問題が起きます。
そのため、動作実行中かどうかを示すという問題について、潜在的な解決策を話し合うためのRFC / "good first issue"を発行しました。
多くのデザイナーやエンジニアの方からRFCについてのフィードバックをいただきました。例えば、インジケータのデザインについてどのようなものが好まれるか、デザインの潜在的な方向性などについてです。
Rafael Almeidaはこの機会をとらえて私たちのチームと協力し、まったく新しいインジケータを実装しました。そのインジケータは現在Next.js 9のデフォルトで利用できます。
Next.jsがコンパイル動作を行っているときはいつでも、小さな三角形がページ右下の隅に現れます!
Next.js Compilation Indicator 動画
Console Output
これまで開発中に変更を加えた場合、Next.jsはロード状態バーのゲージを満たすことでコンパイルインジケータの状態を表し、続けて変更が完了したらスクリーンをクリアしていました。
この動作によっていくつかの課題が生じました。最も注目に値するのは、例えばconsole.log
をコンポーネントに追加する場合などで、両方のアプリケーションコードからコンソールアウトプットをクリアしてしまうことです。Now CLIやdocker-compose
のようにログアウトプットをつなぎ合わせる外部ツールを使った場合も同様です。
Next.js 9から開始した場合、ログアウトプットの飛び越しは減り、スクリーンはクリアされなくなります。これによって全体のエクスペリエンスは向上し、ターミナルウィンドウにはより関連の深い情報が表示され、フリッカーは少なくなります。同時に、すでに使っているツールがある場合、Next.jsはそのツールとより一体化した動作をするようになります。
Next.js Development Console Output 動画
アウトプットクリアリングに関してご協力くださったJustin Chaseさんに、心よりの感謝を申し上げます。
Build Output Statistics
next build
を使って本番環境用のアプリケーションを構築することで、構築された全てのページについて詳細に確認することができます。
どのページもいくつかの統計を自動で行っています。
最も注目すべきものはバンドルサイズです。アプリケーションが大きくなるに連れてJavaScriptバンドルもまた大きくなります。ビルドタイム表示は本番環境用バンドルの大きさを示しています。将来的には、本番環境用の構成に失敗するページに対してパフォーマンスバジェットを設定できるようになります。
バンドルサイズに加えて、いくつのプロジェクトコンポーネントとnode_modules
コンポーネントが各ページに使用されているか示します。これによってページの複雑さがわかります。
各ページは異なる動作をすることが可能なため、静的に最適化されているかサーバーサイドレンダリングされているかを示す表示があります。
Per-Page Configuration Object
各ページは構成オブジェクトをエクスポートできます。この構成は、初めはAMPにオプトインすることを可能としますが、将来的にはより多くのページ特殊オプションを構成できるようになります。
// pages/about.js export const config = { amp: true } export default function AboutPage(props) { return <h3>My AMP About Page!</h3> }
ハイブリッドAMPレンダリングをオプトインするには、値hybridを使います。
高次コンポーネントはこの新しい構成に合わせて削除されます。
import { useAmp } from 'next/amp' export const config = { amp: 'hybrid' } export default function AboutPage(props) { const isAmp = useAmp() return <h3>My About Page!{isAmp ? <> Powered by AMP!</> : ''}</h3> }
withAmpの使用法を新しい構成オブジェクトに自動変換するcodemodを提供します。より詳細な情報はアップグレードガイドをご参照ください。
少し前にツーリングにいくつかの変更を行いました。これによって、コードベースを提供し、コードベースの増大に合わせて安定性を確保しつつ、エクスペリエンスを向上させることができます。
Codebase Improvements
TypeScriptのセクションで示したように、現行のNext.jsコアはTypeScriptで記述され、型定義は使用するNext.jsアプリケーションにあわせて生成されます。
Next.jsを使って構築されたアプリケーションに便利なことに加えて、コアコードベースを使った動作においても便利さを発揮します。例えば、型定義エラーや自動でオートコンプリートを実行した場合などで便利です。
Next.jsにはすでに、50+ Next.jsアプリケーションとそれらに対して行われるテストで構成される、極めて大規模な統合テストスイートがあります。これらのテストは、新バージョンがリリースされたとき、以前から利用できていた機能を同テストスイートによってテストし、アップグレードが確実にスムーズに行われるようにします。
多くの場面で開発にNext.jsを使っている「現実の」開発者を再現しているため、テストの大半は統合テストです。例えば、あるテストはホットモジュール置換が動作するか確認するNext.jsアプリケーションに変更を加える動作を再現しています。
統合テストは主に、ヘッドレスChrome内でテストするためにchromedriver と組み合わせたSelenium webdriverをベースとしています。ただし時間の経過とともに、ある程度の課題が他のブラウザ、特にInternet Explorer 11のような古いブラウザで発生するかもしれません。
Seleniumを使用したため、テストを複数のブラウザで自動実行できました。
今のところ、テストスイートをChrome、Firefox、Safari、そしてInternet Explorer 11.で実行しています。
Google Chrome Collaboration
Google ChromeチームはRFCとプルリクエストを提供することで、Next.jsを改良するための取り組みを続けています。
このコラボレーションの目標は、バンドルサイズ、ブートアップ、そしてハイドレーション時間に重点を置いた大規模なパフォーマンス向上です。
例えば、これらの変更によって小規模サイトだけでなく、HuluやTwitch、Deliverooなどの強力なアプリケーションのエクスペリエンスも向上できます。
Module / Nomodule
まず重視しているものとして、最新JavaScriptに対応しているブラウザに最新JavaScriptを搭載する領域があります。
例えば、現行のNext.jsはasync
/await
に対応していないブラウザ上でコードが実行され、ブラウザがクラッシュしてしまう場合に、シンタックス用にポリフィルを提供しなければいけません。
Next.jsはmodule/nomoduleパターンを使用することで、最新のJavaScriptを対応ブラウザに送りながら古いブラウザをクラッシュさせないようにしています。Module/nomoduleパターンによって、古いブラウザをポリフィルしたES5へフォールバックさせつつ最新JavaScriptを最新のブラウザに送る際に、信頼性のあるメカニズムを提供します。
Next.js内のmodule/nomoduleについてのRFCはこちらで確認できます。
Improved Bundle Splitting
現行のNext.js内バンドルスプリッティングストラテジは、単独の「commons」チャンク内モジュールを対象に含めた割合ベースのヒューリスティックに基づいています。バンドルが一つだけで細分性がほんのわずかしかないため、コードは不必要にダウンロードされる (commonsチャンクが特定のルートに実際には不要なコードを含むことができるため) か、コードが複数のページバンドルに跨って複製されます。
改良バンドルスプリッティングについてのRFCはこちらで確認できます。
Other Improvements
Chromeチームは他にもNext.jsを改良する多くの最適化や変更に取り組んでいます。それらについてのRFCはもうすぐご覧いただけるようになります。
これらのRFCとプルリクエストはNext.js話題トラッカー内で簡単に見つけられるよう、 "Collaboration"とラベルされています。
Community
私たちは、Next.jsコミュニティが成長し続けていることを大変うれしく思います。
今回のリリースでは、65名を超える プルリクエスト作成者の方々が、コアの改良や用例の作成にご協力くださいました。
用例について言うと、Next.jsを異なるライブラリやテクノロジに統合する方法について、現在200を超える用例をお使いいただけます!その中には大半のcss-in-jsライブラリやdata-fetchingライブラリが含まれています。
- 少なくとも一つの取り組みに対し、720を超える方々からの投稿がありました。
- このプロジェクトはGitHub上で38600スター以上を獲得しています。
- 最初のリリースから3400を超えるプルリクエストが提案され、前回のメジャーリリースからでも800を超えるご提案をいただいています!
spectrum.chat/next-js上のNext.jsコミュニティは、メンバー数が8600人を超え、前回のメジャーリリース時から倍増しています。ぜひご参加ください!
今回のリリース実現にあたり、コミュニティや外部フィードバックなどを通じてご協力くださった全ての方々に感謝いたします。