Back to Blog 2019年7月8日(月)
Posted by Connor Davis @ connordav_is, JJ Kasper @ _ijjk, Joe Haddad @ timer150, Luis Alvarez @ luis_fades, Lukáš Huvar @ huv1k, Tim Neutkens @ timneutkens
After 70 canary releases we are pleased to introduce Next.js 9, featuring:
- 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
ごく一部のケースではコードベースの変更が必要になる場合があります。詳細はアップグレードガイドを参照してください。
前回リリース以降、IGN、Bang & Olufsen、Intercom、Buffer、FerrariなどがNext.jsでローンチしているのを嬉しく思います。ショーケースもぜひご覧ください。
Built-In Zero-Config TypeScript Support
1年前、Next.js 6は@zeit/next-typescriptプラグインを通じて基本的なTypeScriptサポートを導入しました。ユーザーは.babelrcをカスタマイズし、next.config.jsで有効化する必要がありました。プラグインを設定すると.tsと.tsxファイルをNext.jsでビルドできましたが、型チェックは統合されておらず、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を自動で作成します。このファイルにより、Visual Studio Codeなどのエディタで統合された型チェックが可能になります。
Integrated Type-Checking
Next.jsは開発中および本番ビルドの両方で型チェックを処理します。開発中は、ファイル保存後に型エラーを表示します。型チェックはバックグラウンドで行われるため、ブラウザ上で更新されたアプリケーションにすぐに触れることができます。型エラーは使用可能になり次第ブラウザに伝播します。
Next.jsは本番ビルド(next build)で型エラーが存在する場合、自動的にビルドを失敗させます。これにより不完全なコードが本番に出るのを防ぎます。
Next.js Core Written in TypeScript
過去数か月でコアの大部分をTypeScriptへ移行しました。これによりコード品質が強化されただけでなく、すべてのコアモジュールに型を提供できるようになりました。例えばnext/linkをインポートすると、TypeScriptをサポートするエディタは許容されるプロパティや受け取る値を表示します。
Dynamic Route Segments
ダイナミックルーティング(URLスラッグやきれいなURL)は、Next.jsがリリースされてから2.5年の間に最初に要望された機能の1つでした。Next.js 2.0でカスタムサーバーAPIを導入することで“解決”され、Next.jsをプログラム的に使うことでURLをページにマッピングできるようになりました。多くのアプリケーションでカスタムサーバーが使われていることを調べたところ、最も顕著な理由はダイナミックルーティングでした。
しかしカスタムサーバーには落とし穴があります: ルーティングはプロキシではなくサーバーレベルで扱われ、モノリシックにデプロイ・スケールされ、パフォーマンス問題になりやすい点です。カスタムサーバーはアプリケーション全体を一つのインスタンスで可用にする必要があるため、Serverless環境へのデプロイが難しくなります。Serverlessはプロキシ層でリクエストをルーティングし、ボトルネックを避けるために独立してスケール/実行されます。
これらのフィードバックとビジョンを元に、ユーザーが既に知っているもの――pages/ディレクトリ――を起点にルートマッピングの解決策を検討し始めました。
Creating a Dynamically Routed Page
Next.jsは基本的な名前付きパラメータを持つルートの作成をサポートします。これはpath-to-regexp(Expressを支えるライブラリ)で一般的になったパターンです。/post/:pidにマッチするページは、pagesディレクトリ内に次のようなファイルを作成することで実現できます:
pages/post/[pid].js
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 }) {
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
詳細はNext.jsドキュメントやNext.js Learnセクションを参照してください。
Automatic Static Optimization
Next.jsは約2年前のv3で静的サイト生成のサポートを追加しました。当時これは最も要望の多い機能でした。静的サイトが高速であることは明白です: サーバーサイドの計算が不要で、CDNから即座に配信できます。しかし、サーバーサイドレンダリングと静的生成の選択は二択で、中間がありませんでした。実際のアプリケーションではページごとに要件が異なり、レンダリング戦略やトレードオフも異なります。
例えばホームページやマーケティングページは静的コンテンツが多く静的最適化に向きますが、頻繁にデータが更新されるダッシュボードはサーバーサイドレンダリングが適しています。我々は両方の利点をユーザーに与えつつ、デフォルトで高速にできないか検討しました。どうすればページ単位で静的なマーケティングページと動的なサーバーレンダーの両方を提供できるか?
Automatic Partial Static Export
Next.js 9から、ページが静的HTMLへ事前レンダできるかを自動判定するヒューリスティックが導入されました。この判定は、ページがgetInitialPropsを使ってブロッキングなデータ要求を持つかどうかによって行われます。このヒューリスティックにより、サーバーレンダーと静的生成の両方を含むハイブリッドアプリケーションをNext.jsが出力できるようになりました。組み込みのNext.jsサーバー(next start)とプログラム的API(app.getRequestHandler())はどちらもこのビルド出力を透過的にサポートします。設定や特別な取り扱いは不要です。
静的に生成されたページはクライアントサイドでハイドレートされ、完全なインタラクティビティを持ちます。さらに、ページがURLのクエリパラメータに依存する場合はハイドレーション後にNext.jsが表示を更新します。開発中はページが静的生成されるかどうかをNext.jsが視覚的に示します(この表示はクリックで非表示にできます)。静的ページはビルド出力でも表示されます。
API Routes
Reactアプリを構築する際、多くの場合バックエンドが必要になります。データベースからデータを取得したり、ユーザーが提供したデータを処理したり(例: お問い合わせフォーム)するためです。多くのユーザーはカスタムサーバーを使ってAPIを構築していましたが、そこにはいくつかの問題がありました。例えばNext.jsはカスタムサーバーコードをコンパイルしないため、import/exportやTypeScriptが使えません。そのため独自のコンパイルパイプラインをカスタムサーバー上に構築するケースがありましたが、これも設定を誤るとツリーシェイキングが無効になるなどの落とし穴がありました。
そこで考えたのは、Next.jsが提供する優れた開発者体験をAPIバックエンド構築にも提供できないか、ということです。今日、我々はAPI routesを紹介します。これはNext.jsによるバックエンド構築のためのベストインクラスの開発者体験です。
API routesを使い始めるには、pages/ディレクトリ内にapi/ディレクトリを作成します。このディレクトリ内の任意のファイルは/api/<your route>に自動的にマッピングされます。他のページファイルがルートにマッピングされるのと同じ仕組みです。例えばpages/api/contact.jsは/api/contactにマップされます。
Note: API Routesはダイナミックルートもサポートします。
pages/api/ディレクトリ内のすべてのファイルはReactコンポーネントの代わりにリクエストハンドラ関数をエクスポートします:
export default function handle (req, res) {
res.end('Hello World');
}
reqはNextApiRequestを指し、http.IncomingMessageを拡張します。
resはNextApiResponseを指し、http.ServerResponseを拡張します。
一般にAPIエンドポイントはクエリストリング、リクエストボディ、クッキーなどの入力を受け取り、別のデータで応答します。API RoutesをNext.jsに追加するにあたり、ユーザーの多くはNode.jsのreq/resを直接使っておらず、むしろExpressのようなサーバーライブラリが提供する抽象を使っていることに気づきました。これらのライブラリを使う理由は、受信データがテキストなど解析が必要な形式であることが多く、その解析をミドルウェアで肩代わりしてくれるためです。一般的に使われるミドルウェアはクエリストリング、ボディ、クッキーの解析を提供しますが、セットアップが必要です。
Next.jsのAPI routesではこれらのミドルウェアがデフォルトで提供されるため、すぐにAPIエンドポイントを作り始めることができます。例:
export default function handle (req, res) {
console.log(req.body);
console.log(req.query);
console.log(req.cookies);
res.json({ status: 'ok' });
}
(注: 上の例はAPIルート内での一般的なアクセス例を示しています。)
詳細やより多くの例については、公式のNext.jsドキュメントを参照してください。