commmune Developer Blog

commmune開発者ブログ

【全文和訳】Next.js 9

(以下は2019年7月8日に公開された Next.js 9 の日本語和訳です。 以下原文 )

nextjs.org

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をご覧ください。

前回のリリース以後、IGNBang & OlufsenIntercomBuffer、そして 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 )を自動的に失敗させます。 これは、破損したコードをプロダクション環境に送り込むのを防ぐのに役立ちます。

f:id:commmune:20190804175523p:plain
Next.js 9 Production Type-Checking


Next.js Core Written in TypeScript

ここ数カ月の間に、私たちはコードベースの大部分をTypeScriptに移行しました。これは私たちのコード品質を強化しただけでなく、すべてのコアモジュールに型定義を提供することも可能にしました。

たとえば、next/linkをインポートすると、TypeScriptに対応したエディタであれば利用可能なプロパティやそれらが受け付ける値を表示します。

f:id:commmune:20190804175459p:plain
Next.js Core Types


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-regexpExpressの動力源となるライブラリ)によって一般化されたものです。

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はその生成を視覚的に知らせます。この視覚的成果物はクリックして非表示にできます。

f:id:commmune:20190804192654p:plain
Next.js Static Optimization Indicator

また、静的生成されたページはNext.jsビルドアウトプットに表示されます。

f:id:commmune:20190804180651p:plain
Next.js Build Output Type Indicator


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 CLIdocker-composeのようにログアウトプットをつなぎ合わせる外部ツールを使った場合も同様です。

Next.js 9から開始した場合、ログアウトプットの飛び越しは減り、スクリーンはクリアされなくなります。これによって全体のエクスペリエンスは向上し、ターミナルウィンドウにはより関連の深い情報が表示され、フリッカーは少なくなります。同時に、すでに使っているツールがある場合、Next.jsはそのツールとより一体化した動作をするようになります。

Next.js Development Console Output 動画

アウトプットクリアリングに関してご協力くださったJustin Chaseさんに、心よりの感謝を申し上げます。


Build Output Statistics

next buildを使って本番環境用のアプリケーションを構築することで、構築された全てのページについて詳細に確認することができます。 どのページもいくつかの統計を自動で行っています。

最も注目すべきものはバンドルサイズです。アプリケーションが大きくなるに連れてJavaScriptバンドルもまた大きくなります。ビルドタイム表示は本番環境用バンドルの大きさを示しています。将来的には、本番環境用の構成に失敗するページに対してパフォーマンスバジェットを設定できるようになります。

f:id:commmune:20190804184454p:plain
Next.js Built Page Size

バンドルサイズに加えて、いくつのプロジェクトコンポーネントnode_modulesコンポーネントが各ページに使用されているか示します。これによってページの複雑さがわかります。

f:id:commmune:20190804184527p:plain
Next.js Page Package Count

各ページは異なる動作をすることが可能なため、静的に最適化されているかサーバーサイドレンダリングされているかを示す表示があります。

f:id:commmune:20190804184554p:plain
Next.js Built Page Type


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を使用したため、テストを複数のブラウザで自動実行できました。

今のところ、テストスイートをChromeFirefoxSafari、そしてInternet Explorer 11.で実行しています。

Google Chrome Collaboration

Google ChromeチームはRFCとプルリクエストを提供することで、Next.jsを改良するための取り組みを続けています。

このコラボレーションの目標は、バンドルサイズ、ブートアップ、そしてハイドレーション時間に重点を置いた大規模なパフォーマンス向上です。

例えば、これらの変更によって小規模サイトだけでなく、HuluTwitchDeliverooなどの強力なアプリケーションのエクスペリエンスも向上できます。


Module / Nomodule

まず重視しているものとして、最新JavaScriptに対応しているブラウザに最新JavaScriptを搭載する領域があります。

例えば、現行のNext.jsはasync/awaitに対応していないブラウザ上でコードが実行され、ブラウザがクラッシュしてしまう場合に、シンタックス用にポリフィルを提供しなければいけません。

f:id:commmune:20190804185046p:plain
Next.js Module/Nomodule Collaboration RFC

Next.jsはmodule/nomoduleパターンを使用することで、最新のJavaScriptを対応ブラウザに送りながら古いブラウザをクラッシュさせないようにしています。Module/nomoduleパターンによって、古いブラウザをポリフィルしたES5へフォールバックさせつつ最新JavaScriptを最新のブラウザに送る際に、信頼性のあるメカニズムを提供します。

Next.js内のmodule/nomoduleについてのRFCこちらで確認できます。


Improved Bundle Splitting

現行のNext.js内バンドルスプリッティングストラテジは、単独の「commons」チャンク内モジュールを対象に含めた割合ベースのヒューリスティックに基づいています。バンドルが一つだけで細分性がほんのわずかしかないため、コードは不必要にダウンロードされる (commonsチャンクが特定のルートに実際には不要なコードを含むことができるため) か、コードが複数のページバンドルに跨って複製されます。

f:id:commmune:20190804185237p:plain
Next.js Chunking Collaboration RFC

改良バンドルスプリッティングについての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人を超え、前回のメジャーリリース時から倍増しています。ぜひご参加ください!

今回のリリース実現にあたり、コミュニティや外部フィードバックなどを通じてご協力くださった全ての方々に感謝いたします。