対象読者
- JavaScriptとWeb開発の基礎に理解がある方
- Reactに興味/関心があり、これから学び始める方
前提環境
筆者の検証環境は以下の通りです。
- macOS High Sierra 10.13.3
- Node.js v10.4.1/npm 6.1.0
- React 16.5.1
- firebase-tools 4.2.1
- create-next-app 0.5.9
- Next.js 6.1.2
- Babel 7.0.0
シングルページアプリケーションが苦手なこと
前回まで、create-react-appを用いたシングルページアプリケーションの開発手法について解説してきました。ここで、シングルページアプリケーションにおけるサーバーとブラウザの関係を、おさらいしておきましょう。
前回解説した通り、シングルページアプリケーションにおけるサーバーの役割は、HTMLやJavaScriptなどのファイルを保管し、ブラウザからの要求に応じて配信することです(図1)。
ファイルを受け取ったブラウザは、JavaScriptをひと通り解釈した後、Reactであれば ReactDOM.render()
を起点にしてDOMツリーの管理を開始します。この後は、ページ遷移のためにHTMLを読み込み直すこともなく、Virtual DOMで管理できる範囲で画面の書き換えを行っていくため、応答速度が高いアプリケーションを作りやすいと言われています。
さて、そんなシングルページアプリケーションですが、その性質に由来する弱点もあります。今回は次の2つについて着目します。
- ファイルサイズが大きくなりがち
- HTMLだけを取得されるとコンテンツが空になる
それぞれ、どういった点で問題になるのか、見ていきましょう。
ファイルサイズが大きくなる
シングルページアプリケーションのような近代的なJavaScriptアプリケーションでは、自分で書いたすべてのJavaScriptファイルと、そこから呼び出されたすべてのライブラリを、1つのJavaScriptファイルに結合しています。これによって require()
や import XXX from 'xxx'
といった、モジュール読み込みの仕組みを実現しています。
旧来のJavaScriptアプリケーション開発のように、グローバル変数の領域で各ライブラリが名前空間を奪い合うやり方に比べれば、格段に良い方式ではあるのですが、これはこれで新たな問題を抱えました。ファイルサイズが大きくなりがちなのです。
前回デプロイに使ったサンプルプロジェクトを例に挙げます。create-react-app
で作ったプロジェクトをそのままビルドしたので、あの方法で作れる最小のサイズになっているはずです。
ビルド後のフォルダの中を見てみると、118KBでした(図2)。
118KBと言えば、ちょっとしたJPEG画像に匹敵するファイルサイズです。とはいえ、現代の通信速度であれば、目くじらを立てるようなサイズではないのかもしれません。ただ、これは最小のサイズです。実際の開発の現場で、何の手だても打たずに開発を進めていくと、1MBを超える、ともすると数MBに達するような、巨大なJavaScriptファイルに出会うこともあります。
数MBともなってくると、速度の速いWi-Fiにつながったパソコンならばともかく、回線の遅いモバイルブラウザでは目に見えて待ち時間が発生します。場合によっては5秒や10秒では済まないかもしれません。
ダウンロードが終われば速いものの、それまでにかかる時間が長くなってしまうことがある。これがシングルページアプリケーションの弱点の1つです。
コンテンツが空になる
また別の問題もあります。クローラーなどがWebページを見に来たときに、空のコンテンツを返してしまうのです。
Googleをはじめとした検索エンジンの類いは、ときどき私たちのWebページを巡回して、情報の取得や更新を行っています。こういったクローラーと呼ばれるアプリケーションと、シングルページアプリケーションは少し相性が悪いです。なぜならば、クローラーの中には、HTMLファイルだけを取得して、その内容だけでコンテンツを判断しようとするものがあるからです。
例えば、 create-react-app
で作ったシングルページアプリケーションの場合、初期設定ではリスト1の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"></div> <script type="text/javascript" src="//cz-cdn.shoeisha.jp/static/js/main.a285be49.js"> </script> </body> </html>
ブラウザで表示する場合であれば、JavaScriptが実行されて ReactDOM.render()
が実行されれば、 <div id="root"></div>
の中に相当するDOMツリーにコンテンツが追加されていきます。
しかし、クローラーの場合はそうはいきません。クローラーはファイルをダウンロードするだけなのです。そこにあるのは空虚な <div id="root"></div>
だけで、機械的に「なにもないページ」と判断されるだけです。
ページの検索順位を上げたいWebサイト管理者からすれば、たまったものではありません。これもシングルページアプリケーションの注意すべき弱点です。
[コラム]クローラーが賢くなってきている
クローラーにコンテンツが入ったHTMLを返せないことを問題として挙げましたが、少なくともGoogleでは、この問題は解消されています。HTMLを読み込んだ後、JavaScriptによって描画されるコンテンツも、監視対象に含めてくれているのです。同じ検索エンジンを使っている、Yahoo!JAPANも同様です。
こういったケースもあるため、JavaScriptによって描画されるコンテンツを解釈しないクローラーに読まれることを想定している方だけが、クローラーの問題を考慮する必要があります。