2024年3月13日
執筆
有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)に所属するテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。著書に『Bootstrap 5 フロントエンド開発の教科書』、『作って学べるHTML+JavaScriptの基本』など。
監修
静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。
主な著書に「独習」シリーズ、「これからはじめるReact実践入門」、「改訂3版 JavaScript本格入門」他、著書多数。
フロントエンド開発に日頃携わっている方は、ユーザ体験(UX)やユーザビリティの向上を考え、いかに効率的に、チーム開発でも問題を起こしにくい方法はないか、常に模索していると思います。こういった方々に、少しでも気付きとなるようなコンテンツを提供できないだろうか。そう思って始めたのは、この「新発見!フロントエンド技術のいま」という連載です。フロントエンド開発に従事している方はもちろん、バックエンド開発に従事する方にも、フロントエンド開発に関心があったらぜひ読んでいただきたい。
さて、本稿のテーマである「サーバコンポーネント(Server Component)」ですが、筆者は、サーバコンポーネントとは
クライアントサイドとサーバサイドのいいとこ取り
と考えています。
それぞれに強みがあるので、良いとこだけいただいてしまおうという欲張りな戦略ですね。今回は、このサーバコンポーネントを、ReactとNext.jsと少し絡めながら紹介したいと思います。
今、フロントエンド(クライアントサイド)のUI構築を何でやっているかと聞かれたら、ReactとかVueでやっているという開発者が多いのではないのでしょうか。フルスタックならAngularという答えもあるでしょう。ReactやVueの特徴といえば、コンポーネント指向はそのひとつとして挙げられます(もちろん、高速であるとか、分かりやすくて書きやすいといったこともあると思います)。コンポーネント指向とはこんな感じで表現できるのではないでしょうか。
テンプレート、スタイル、ロジックをまとめて再利用しやすい部品(コンポーネント)をつくって、それらを組み合わせてページを生成する
テンプレートとはHTML、スタイルはCSS、そして、ロジックとはJavaScriptのコードです。すなわち、コンポーネントとは、あるUI部品の単位にまとめられたHTML+JavaScript+CSSの集合体であるということですね。
ReactやVueによるUI開発は、それぞれに独立したコンポーネントをつくって組み合わせて使うことの繰り返しです。自分でコンポーネントをつくるのも良いし、誰かがつくったコンポーネントを使っても構いません。
このように、コンポーネントの組み合わせによる開発では、クライアントサイドでできることが大きく増加します。しかしながら、それには良いことも悪いこともあります。
クライアントサイドでできることが増えてくると、何でもクライアントサイドでやってしまおうということにもなりがちです。仕事のできる人が何でも任されるのと一緒で、本来はやらなくてもいいのになぜかやらされている、そんな状況にもなりがちです。このようなクライアントサイド偏重の状況下では、いろいろと不都合なことが起きがちです。
ページはコンポーネントの読み込み後にレンダリングされるので、ユーザはページが表示されるまで少し待つことになります。これはUXの低下につながります。
検索エンジンのクローラが読み込んだコンポーネントはレンダリングされないので、ページには何もないと思われてインデックスされません。これもSEO上不利です。
すべてのコンポーネントのJavaScriptコードとライブラリのバンドル(まとめ)が必要なので、ダウンロードサイズが大きくなりがちです。これはそのまま、通信時間や処理時間に影響します。
クライアントサイドでレンダリングするので、デバイスの性能に使用感が大きく左右されます。開発者は高性能なデバイスを使っていることが多いので、なかなか気付きにくいことです。
クライアントサイドからサーバサイドのリソースに直接アクセスする方法はないので、通常は別途APIサーバを立てて対応するなどの必要があります。
クライアントサイドでコードが動く都合上、アクセストークンやAPIキーなどの機密情報は扱いにくくなります。
クライアントサイドではJavaScriptやReactなどが、サーバサイドではPHP、Ruby on Railsなどが使われるといったように、いわゆる「技術の分断」が発生します。
クライアントサイド偏重で発生しがちな問題は、そのままサーバサイド処理が持つメリットにつながることが多いです。ここでは対比させる形で、クライアントサイドの処理をサーバサイドに任せる場合のメリットを確認します。
レンダリング済みのコンテンツが返ってくるので、ブラウザですぐに描画できます。そのためユーザはすぐにページを見ることができ、UXが向上します。
また、ページを読み込んだ時点でコンテンツがあるので、クローラの解析対象にできます。
クライアントサイドに必要なコンポーネントのみ、JavaScriptコードとライブラリのみをバンドルすれば良いので、バンドルのサイズを抑えられます。
サーバサイドで処理する比率が大きいほど、クライアントサイドの負担は減るため、あまり性能の良くないデバイスでもUXの低下を抑えられます。
データベースなどサーバ内のリソースに直接アクセスしたり、同一ネットワーク内のAPIサーバへアクセスしたりすれば、リソースを容易かつ高速に利用できます。
機密情報はサーバサイドでのみ扱い、クライアントサイドには現れないようにすることで、セキュリティ上のリスクを抑えられます。
クライアントサイドに重い処理を入れるのはためらわれるものですが、サーバサイドではハードウェアの性能次第で、重い処理を導入できる余地が高まります。
上記のようなサーバサイド処理が持つメリットをフロントエンド開発で享受できるように、サーバサイドでコンポーネントを処理する仕組みが登場しました。そのひとつが、Next.jsやVue.js/Nuxt.jsで使えるサーバサイドレンダリング(Server Side Rendering; 以降SSR)です。
コンポーネントをサーバサイドでレンダリングし、生成したコンテンツ(HTML、CSS、JS)を返すのがSSRです。SSRの目的は「ページの初回表示の速度向上」と「SEO効果の向上」です(Vue.jsのドキュメントより)。
リクエスト毎にレンダリングが発生する、性質上、ステート(※)は持てない。ブラウザのリソース(ローカルストレージ。位置情報などのAPI)は利用できない、などの制約があるほかは、クライアントサイドと同様にレンダリングし、最終的な出力を返します。基本的な性質は前述の通りですが、キャッシュによりレンダリングのコストを低減し、UXを向上できるといった効果もあります。
(※)コンポーネントの状態を表す情報です。たとえばカウンターアプリであれば、現在値を管理するために利用できます。
SSRで返されるコンテンツは静的なものなので、通常はユーザによるクリックなどのイベントに反応できません。そこで、登場するのが、ハイドレーション(Hydration)という仕組みです。ハイドレーションとは水分の注入といった意味ですが、この場合は静的な結果に動作(イベントリスナ)を紐づけて、動きを与えるという意味になります。
ハイドレーションでは、サーバはレンダリング結果とは別に、コンポーネントのバンドルを返します。クライアントはコンポーネントを独自にレンダリングし、その結果に基いて、イベントリスナを設定します。つまり、サーバサイドとクライアントサイドで二度レンダリングが実行されるわけです。
一見ムダなことをしているように見えますが、初期ページが遅延なく表示されるのでUXの低下を抑えられてSEOにも有効、かつ動的な処理にも対応できるといったメリットがあります。
SSRと同様にサーバサイドでレンダリングする仕組みに、静的サイトジェネレーション(Static Site Generation; SSG)があります。SSRと同じくNext.jsやNuxt.jsなどで利用できます。SSRはリクエスト毎にレンダリングしますが、SSGではデプロイ時にレンダリングするといった具合に生成タイミングが異なります。その性質上、SSGはいったんデプロイしたらコンテンツが変化しないようなサイトの構築に向いています。
今回のテーマであるサーバコンポーネント(Server Component; 以降SC)も、SSRと同様にサーバサイドでコンポーネントをレンダリングする仕組みですが、SCはSSRとは似て非なるものです。
ReactのSCであるReact Server Component(RSC)は、React 18で実装されました。ReactをベースとしたフレームワークであるNext.jsは、Next.js 13でApp Routerとしての機能の中でこのRSCを取り入れました(Next.js 13.4でStable化)。Next.jsでは、より容易にRSCを利用できるようになっています。ただし、ここでも実装には深く踏み込まず、一般論としてのSCについて紹介したいと思います。
SSRでは、すべてのコンポーネントをレンダリングしてクライアントに返しました。一方でSCでは、クライアントサイドで処理したいコンポーネント(※)は、そのままクライアントに返します。これにより、ハイドレーションを使わずに動的なページを構成できます。
(※)このようなコンポーネントを、クライアントコンポーネント(Client Component; 以降CC)として、サーバコンポーネントと区別します
SCのメリットは、「キャッシュなどによるUXの向上」や「安全性の向上」です(Next.jsのドキュメントより)。これ自体はサーバサイド処理そのもののメリットですが、CCと併用することで、動的な操作も可能になるなど、クライアントサイド処理のメリットも得られます。
SCを使っていくにあたり、CCとの使い分けがいつも課題になります。Next.jsでは、一般的にコンポーネントはSCと見なされます。CCとして使いたいコンポーネントだけを、「CCだよ」と明示する必要があるわけです。もっと言えば、基本はSCで、CCを特別扱いするということです。
RSCのドキュメントでは、SCとCCでできること、できないことを以下の表のように述べています。
難しい用語もありますが、まずは「どちらが優れているというものではなく、両者は、それぞれの守備範囲に応じて使い分けていくべきもの」であることを確認してください。大雑把には、ステート(状態)やライフサイクルを管理したい、クリックなどのイベントを監視したい、ブラウザの機能にアクセスしたい、Reactクラスコンポーネントを使用したいといった場合には、CCを採用します。
今回は、連載の第1回目として、サーバコンポーネントを紹介しました。フロントエンド開発においても、サーバサイドの役割は変わらない、むしろ従来とは違ったところで増しているというのをお伝えできたのではないかと思います。
次回は、同じコンポーネントでも「Web Components」というクライアントサイドの標準技術を紹介します。
関連記事
人気記事