CodeZine(コードジン)

特集ページ一覧

Next.jsのサーバーサイドレンダリングで、シングルページアプリケーションの課題を解消

基礎からはじめるReact入門 第14回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2018/11/09 14:00
目次

サーバーサイドレンダリングができること

 さて、シングルページアプリケーションの苦手なところを解決するために、いくつもの手法が編み出されました。そのうちの1つがサーバーサイドレンダリングと呼ばれる技術です(図3)。

図3:サーバーサイドレンダリングの概要
図3:サーバーサイドレンダリングの概要

 サーバーサイドレンダリングにおいて、HTMLデータは静的ファイルを配信するものではなく、Node.jsサーバーによって動的に生成されるものです。コンテンツが埋め込まれたHTMLデータを生成することで、クローラーにもちゃんとコンテンツを見せることができます。

 本来であれば、ブラウザ側で初期表示される際に生成されるはずだったDOMツリーを、サーバー側で動的に生成し、HTMLデータに埋め込んだ状態でサーバーから返却するのです。生成には、ReactDOMと同じパッケージに入っているReactDOMServerをNode.js上で使用します。リスト2のコードを実行することで、Virtual DOMから生成されたDOMツリーをHTML文字列として取得することができるので、これを返却するHTMLデータに埋め込みます。

[リスト2]ReactDOMServerをNode.jsで使うイメージ
import ReactDOMServer from 'react-dom/server';
import App from '../src/App.js'; // ブラウザ向けのコンポーネント

// Reactにより生成されたHTML文字列を取得する
const appString = ReactDOMServer.renderToString(<App />);
// appStringをHTMLデータに埋め込んで、ブラウザに返却する

 ReactDOMの仕組みを使用する性質上、これはNode.jsなどの、サーバーサイドJavaScriptの処理系でしか実行できません。

 さて、これによって生成されたHTMLデータは、リスト3の形でブラウザに渡されます。

[リスト3]サーバーサイドレンダリングで生成されたHTMLのイメージ
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- 略 -->
    <title>React App</title>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root">
      <!-- <App />に相当する部分 -->
      <div> <!-- (1) ここから-->
        Hello, React!
      </div> <!-- (1) ここまで -->
    </div>
    <script
      type="text/javascript"
      src="//cz-cdn.shoeisha.jp/static/js/main.a285be49.js"> <!-- (2) -->
    </script>
  </body>
</html>

 (1)がサーバー側で埋め込まれた部分です。ブラウザが読み込むためのJavaScriptは(2)のように従来通り存在していますが、それを先にサーバー側のアプリケーションでも読み込んでおいて、(1)の部分を生成している形になります。

読み込み後の流れ

 HTMLデータには初期表示を実現できるだけのコンテンツが埋め込まれているので、ひとまずJavaScriptのダウンロードを始める前に画面を表示できます。これで、サイズが大きいJavaScriptファイルは、画面が表示されてから後ろで読み込めば良いことになります。

 JavaScriptのダウンロードが終わると、従来通りにReactDOMがVirtual DOMの構築を始めます。これが終わると、現状のDOMツリーとの差分を見て、違いがあった場合だけVirtual DOMの内容でDOMツリーを更新します。それ以降は、通常のシングルページアプリケーションと同様に、DOMツリーはVirtual DOMの管理下に置かれます。

 この流れで初期化を行う場合は、ReactDOM.render()ではなく、同じAPIを持ったReactDOM.hydrate()を使うことが推奨されています。リスト4のように、render()を使った場合と使い方は同じです。

[リスト4]サーバーサイドレンダリングを使った場合のindex.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.hydrate(
  <App />,
  document.getElementById('root')
);

 React側でもサーバーサイドレンダリングを意識した機能を作ってくれているのは、うれしいところですね。

技術的に難しいところ

 さて、サーバーサイドレンダリングでシングルページアプリケーションの苦手な点をい解消できそうですが、いくらかの難点も抱えています。

 ブラウザで動かす前提のコードをNode.js上で動かすのは簡単ではない、といった点が、その最たるものです。ブラウザでもNode.jsでも動くようにツールを作る、IsomorphicやUniversal JavaScriptと呼ばれる概念が浸透してきたおかげで、両者で動くライブラリは増えてきていますが、そうでないライブラリも多くあります ブラウザにあってNode.jsにない機能の筆頭として、DOM APIがあります。DOMを操作する入り口であるdocumentがないので、DOMを操作するタイプの、jQueryなどのライブラリが初期表示時に動く構成になっていると、サーバーサイドレンダリングは実現しづらくなります。

 また、create-react-appで作られたプロジェクトのように、Babelによって言語仕様を調整されているJavaScriptコードを、Node.jsが直接読むことはできません。サーバー側のNode.jsがcreate-react-app相当の言語仕様を解釈できるように、適切にBabelなどでコードを変換する必要があります。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:基礎からはじめるReact入門

もっと読む

著者プロフィール

  • WINGSプロジェクト 中川幸哉(ナカガワユキヤ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5