クライアントサイドとサーバサイドの「良いとこ取り」。SSRとは違うサーバコンポーネントのメリットとは?

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開発は、それぞれに独立したコンポーネントをつくって組み合わせて使うことの繰り返しです。自分でコンポーネントをつくるのも良いし、誰かがつくったコンポーネントを使っても構いません。

このように、コンポーネントの組み合わせによる開発では、クライアントサイドでできることが大きく増加します。しかしながら、それには良いことも悪いこともあります。

カプセル化
コンポーネントのポイントの一つがカプセル化です。オブジェクト指向プログラミングでもおなじみのこのキーワードは、外部に公開する状態・手続きと、内部に秘匿すべき状態・構造を分けることをいいます。利用者は、公開された情報のみに基づきコンポーネントを利用でき、コンポーネント自身は外部の影響を受けにくくなるという利点があります。

行き過ぎたクライアントサイド偏重は問題を孕む

クライアントサイドでできることが増えてくると、何でもクライアントサイドでやってしまおうということにもなりがちです。仕事のできる人が何でも任されるのと一緒で、本来はやらなくてもいいのになぜかやらされている、そんな状況にもなりがちです。このようなクライアントサイド偏重の状況下では、いろいろと不都合なことが起きがちです。

▲クライアントサイド偏重で起きがちな問題点

(1)ページの初期表示に時間がかかる

ページはコンポーネントの読み込み後にレンダリングされるので、ユーザはページが表示されるまで少し待つことになります。これはUXの低下につながります。

(2)SEOに不利になる

検索エンジンのクローラが読み込んだコンポーネントはレンダリングされないので、ページには何もないと思われてインデックスされません。これもSEO上不利です。

(3)バンドルサイズが大きくなる

すべてのコンポーネントのJavaScriptコードとライブラリのバンドル(まとめ)が必要なので、ダウンロードサイズが大きくなりがちです。これはそのまま、通信時間や処理時間に影響します。

(4)クライアントのデバイスの性能に左右される

クライアントサイドでレンダリングするので、デバイスの性能に使用感が大きく左右されます。開発者は高性能なデバイスを使っていることが多いので、なかなか気付きにくいことです。

(5)サーバのリソースを使うにはAPIを立てる必要がある

クライアントサイドからサーバサイドのリソースに直接アクセスする方法はないので、通常は別途APIサーバを立てて対応するなどの必要があります。

(6)セキュリティ上の問題を抱えやすくなる

クライアントサイドでコードが動く都合上、アクセストークンやAPIキーなどの機密情報は扱いにくくなります。

(7)クライアントサイドとサーバサイドで技術の分断が起きる

クライアントサイドではJavaScriptやReactなどが、サーバサイドではPHP、Ruby on Railsなどが使われるといったように、いわゆる「技術の分断」が発生します。

サーバサイドのメリットがクライアント偏重の問題点を解決する

クライアントサイド偏重で発生しがちな問題は、そのままサーバサイド処理が持つメリットにつながることが多いです。ここでは対比させる形で、クライアントサイドの処理をサーバサイドに任せる場合のメリットを確認します。

▲サーバサイドで処理することのメリット

(1)ページの初期表示を速くできる

レンダリング済みのコンテンツが返ってくるので、ブラウザですぐに描画できます。そのためユーザはすぐにページを見ることができ、UXが向上します。

(2)SEOに有利になる

また、ページを読み込んだ時点でコンテンツがあるので、クローラの解析対象にできます。

(3)バンドルサイズを小さくできる

クライアントサイドに必要なコンポーネントのみ、JavaScriptコードとライブラリのみをバンドルすれば良いので、バンドルのサイズを抑えられます。

(4)クライアントのデバイスの性能に左右されにくい

サーバサイドで処理する比率が大きいほど、クライアントサイドの負担は減るため、あまり性能の良くないデバイスでもUXの低下を抑えられます。

(5)サーバのリソースへのアクセスが効率的

データベースなどサーバ内のリソースに直接アクセスしたり、同一ネットワーク内のAPIサーバへアクセスしたりすれば、リソースを容易かつ高速に利用できます。

(6)セキュリティ上のリスクを抑えられる

機密情報はサーバサイドでのみ扱い、クライアントサイドには現れないようにすることで、セキュリティ上のリスクを抑えられます。

(7)比較的重い処理も思い切って導入できる

クライアントサイドに重い処理を入れるのはためらわれるものですが、サーバサイドではハードウェアの性能次第で、重い処理を導入できる余地が高まります。

レンダリングをサーバサイドが肩代わりするサーバサイドレンダリング(SSR)

上記のようなサーバサイド処理が持つメリットをフロントエンド開発で享受できるように、サーバサイドでコンポーネントを処理する仕組みが登場しました。そのひとつが、Next.jsやVue.js/Nuxt.jsで使えるサーバサイドレンダリング(Server Side Rendering; 以降SSR)です。

▲サーバサイドレンダリング(SSR)の仕組み

SSRではレンダリング済みのコンテンツを返す

コンポーネントをサーバサイドでレンダリングし、生成したコンテンツ(HTML、CSS、JS)を返すのがSSRです。SSRの目的は「ページの初回表示の速度向上」と「SEO効果の向上」です(Vue.jsのドキュメントより)。

リクエスト毎にレンダリングが発生する、性質上、ステート(※)は持てない。ブラウザのリソース(ローカルストレージ。位置情報などのAPI)は利用できない、などの制約があるほかは、クライアントサイドと同様にレンダリングし、最終的な出力を返します。基本的な性質は前述の通りですが、キャッシュによりレンダリングのコストを低減し、UXを向上できるといった効果もあります。

(※)コンポーネントの状態を表す情報です。たとえばカウンターアプリであれば、現在値を管理するために利用できます。

SSRで返されるコンテンツは静的なものなので、通常はユーザによるクリックなどのイベントに反応できません。そこで、登場するのが、ハイドレーション(Hydration)という仕組みです。ハイドレーションとは水分の注入といった意味ですが、この場合は静的な結果に動作(イベントリスナ)を紐づけて、動きを与えるという意味になります。

ハイドレーションでは、サーバはレンダリング結果とは別に、コンポーネントのバンドルを返します。クライアントはコンポーネントを独自にレンダリングし、その結果に基いて、イベントリスナを設定します。つまり、サーバサイドとクライアントサイドで二度レンダリングが実行されるわけです。

一見ムダなことをしているように見えますが、初期ページが遅延なく表示されるのでUXの低下を抑えられてSEOにも有効、かつ動的な処理にも対応できるといったメリットがあります。

静的サイトジェネレーション(SSG)

SSRと同様にサーバサイドでレンダリングする仕組みに、静的サイトジェネレーション(Static Site Generation; SSG)があります。SSRと同じくNext.jsやNuxt.jsなどで利用できます。SSRはリクエスト毎にレンダリングしますが、SSGではデプロイ時にレンダリングするといった具合に生成タイミングが異なります。その性質上、SSGはいったんデプロイしたらコンテンツが変化しないようなサイトの構築に向いています。

SSRとは異なるアプローチのサーバコンポーネント(SC)

今回のテーマであるサーバコンポーネント(Server Component; 以降SC)も、SSRと同様にサーバサイドでコンポーネントをレンダリングする仕組みですが、SCはSSRとは似て非なるものです。

▲サーバコンポーネント(SC)の仕組み

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について紹介したいと思います。

SCとクライアントコンポーネント(CC)

SSRでは、すべてのコンポーネントをレンダリングしてクライアントに返しました。一方でSCでは、クライアントサイドで処理したいコンポーネント(※)は、そのままクライアントに返します。これにより、ハイドレーションを使わずに動的なページを構成できます。

(※)このようなコンポーネントを、クライアントコンポーネント(Client Component; 以降CC)として、サーバコンポーネントと区別します

SCのメリットは、「キャッシュなどによるUXの向上」や「安全性の向上」です(Next.jsのドキュメントより)。これ自体はサーバサイド処理そのもののメリットですが、CCと併用することで、動的な操作も可能になるなど、クライアントサイド処理のメリットも得られます。

SCを使っていくにあたり、CCとの使い分けがいつも課題になります。Next.jsでは、一般的にコンポーネントはSCと見なされます。CCとして使いたいコンポーネントだけを、「CCだよ」と明示する必要があるわけです。もっと言えば、基本はSCで、CCを特別扱いするということです。

RSCのドキュメントでは、SCとCCでできること、できないことを以下の表のように述べています。

▲SCとCCの役割分担

難しい用語もありますが、まずは「どちらが優れているというものではなく、両者は、それぞれの守備範囲に応じて使い分けていくべきもの」であることを確認してください。大雑把には、ステート(状態)やライフサイクルを管理したい、クリックなどのイベントを監視したい、ブラウザの機能にアクセスしたい、Reactクラスコンポーネントを使用したいといった場合には、CCを採用します。

まとめ

今回は、連載の第1回目として、サーバコンポーネントを紹介しました。フロントエンド開発においても、サーバサイドの役割は変わらない、むしろ従来とは違ったところで増しているというのをお伝えできたのではないかと思います。

次回は、同じコンポーネントでも「Web Components」というクライアントサイドの標準技術を紹介します。

関連記事

人気記事

  • コピーしました

RSS
RSS