なぜNext.jsを採用するのか?

2019.12.17

こちらは Next.js Advent Calendar 2019 17日目の記事です。

Next.jsの話をすると「ReactでSSRをするやつでしょ?」と言われます。正しくはありますが、その答えでは不十分です。 ここでNext.jsの公式サイトを見るとランディングページにはThe React Framework for Production Server-rendered App, Static Websites, the Enterprise, the Desktop, the Mobile Apps, SEO-Freiendly App, PWAs and Electronとあります。要するに、いろんな用途に使えるということです。

SSRを使用しないのであれば、「ユーザー向け(Not管理画面)なサービス開発であればCRA(create-react-app)で十分じゃない?」と思う方もいるかもしれません。 そこでなぜ私はNext.jsを使うのか?という理由を整理してみました。チームの技術選定でNext.jsを候補に入れている方に届けば嬉しいです。

比較対象

CRA(create-react-app)はFacebookが提供しているReactのプロジェクトをセットアップするコマンドです。CRAで作られたプロジェクトはreact-scriptsというパッケージを通してプロジェクトの開発を行います。react-scriptsの範囲で開発を行うのは簡単ですが、自分で拡張しようとすると力技が必要になります。

自分でフロントエンド開発周りの設定を行う方法もあるでしょう。これはwebpackなどの設定を自分で書いた上で、expressなどのサーバーの上でReactをレンダリングする仕組みを実装する方法です。 自分でSSRの仕組みを実装し、本番運用をしていたこともありますが大変でした。

これらの比較対象を頭にいれた上で、Next.jsのメリットを整理してみました。

具体的なメリット

フロントエンドの足回りが整う。

CRAでも同じメリットが得られますが、webpackやbabelといった開発に必要なツールをフレームワーク側に持たせることができます。 もし、自分で設定するとなると、webpack本体やwebpackのプラグインのアップデートはもちろん、設定ミスによるバグを自分で解決する必要があります。また、保守においても属人化しやすく、担当者がいなくなってしまったために触れなくなった…などという話も聞きます。 IMOですが、これらの設定を自分でカスタマイズするのは組織として大きくなり、開発の足回りを整える役割ができてからでも遅くないと感じています。初期はアプリケーション開発に専念するためにフレームワーク側に設定を隠蔽してもらうことをおすすめします。 CRAでは設定を拡張するのに、eject(隠蔽されていた設定を露出させる)やreact-app-rewrited(CRAの設定を拡張するための”非公式”ツール、積極的なメンテは行われていない)を利用する必要がありますが、Next.jsでは標準でwebpackの設定を拡張できるので、簡単な拡張であればフレームワークを外れずに行えます。

管理画面的なReactアプリケーションでNext.jsを使おうとするとルーターとの相性が悪いですが、ユーザー向けなSPAであれば問題はありません。

SSR(サーバーサイドレンダリング)をやってくれる

React単体で行うクライアントサイドのレンダリングだけでは、クローラーが対応しない限り内部のコンテンツは読み込むことができず、ほとんど空のindex.htmlを読むことになります。 Googleのクローラーは対応を初めていますが、FacebookやTwitterなどのクローラーはクライアントでレンダリングしたコンテンツを読むことができません。(従来のWebページと完全に互角とは言えません)そのため、SNSシェアする際に、ページごとにOGP情報を設定することができませんでした。 また、クライアントでレンダリングを行うということは、レンダリングされるまではユーザーからは真っ白なページが表示されることになります。クライアントのレンダリングでは通信速度や端末の性能にも依存することがあるので、ユーザーによってはページ表示まで長い時間を待つことになります。

こういった問題に対応するためにSSR(サーバーサイドレンダリング)が行われます。通常クライアントでやっていたレンダリングを、サーバーで行うことでページごとにレンダリングされたHTMLを配信します。また、HTMLを読み込み後はSPAとして動作します。 Next.jsがこういった仕組みをフレームワーク側で提供してくれます。(自分で作ると、保守やドキュメンテーションが大変だったりします。)

Static Exporting

ビルド時にSSRし、レンダリングした結果をHTMLファイルに出力する機能です。このHTMLファイルを利用するとSSRが必要なくなり、本番環境では静的ファイルを配信する単純な構成になります。 HTMLファイルと言っても、SPAのメリットは失われません。HTMLを読み込み後、JSが実行されるとSPAとして振る舞います。

SPA単体で利用した際に、デメリットとなる表示速度やOGP問題などを回避しつつ、SSRによる保守コストも負う必要もありません。ただし、コンテンツの更新などで配信するHTMLを変更する際には、ビルドを行う必要があるため、コンテンツの更新を即時反映できない等のデメリットがあります。 この方向性で、より高性能なStatic Exportingを行うフレームワークとしてGatsbyJSというものもあります。

速度の最適化

フレームワークに乗ることで機能要件だけでなく、ページの表示速度面といった非機能要件でのサポートも行ってくれます。例を上げると、次のようなものがあります。

その他

目立った機能ではありませんが、Googleが中心になって進めているAMP HTMLを出力する機能があります。 他にも、Next.jsを開発しているZEIT社が提供しているnowという開発プラットフォームへのデプロイが簡単などのメリットも得られます。(本番で使ったことはないですが、no configなデプロイが可能です。) また、機能ではありませんが、Next.jsではexampleが提供されており、非常に多くのケースが想定されています。

まとめ

Next.jsを使うと以上のようなメリットが得られ本番運用に必要なパーツが一気に揃います。 SSRじゃない場合でもStatic Exporting、またはServerlessと組み合わせることで実運用に乗せることも可能です。(これに興味を持った方はJAMstackを掘っていくと面白いです)

今までは過剰なミニマムと言われていましたが、最近は機能的にも充実してきており、Chrome Dev Summitでも取り上げられるなど将来が楽しみなフレームワークです。 まずは年末の自由研究にNext.jsを触ってみてはどうでしょうか? Next.jsは比較的薄めなフレームワークなのでReactを学習した方であれば覚えることは多くありません。

技術書典8ではNext.jsの本を書きたいと思っており、言語化を進めています。もし新刊が無事に出せたらよろしくおねがいします。