最近聞かれなくなってきた Isomorphic JavaScript ですが、気付けば今は Universal JavaScript と呼ばれているらしいです。
そもそも日本語の記事が少なくて困ったので、色々調べたものを整理するために書きます。
とても簡単にふわっとまとめると、以下のような感じ。
- SPA で問題となるのがSEO対策、初回ロード時間
- SSR はこれを解決してくれるが、クライアントとサーバでロジックの重複が発生
- 同じコードをクライアントとサーバで実行しよう = Isomophic!
- 同じコードをネイティブアプリやデスクトップアプリや組み込みデバイスでも実行しよう = Universal!
なぜ Isomorphic JavaScript なのか
まず、なぜ Isomorphic という概念が出てきたのかについて。
シングルページアプリケーションにおける問題
2013年頃から、シングルページアプリケーション (SPA) が盛り上がりを見せています。
SPA は、単一ページによる Web アプリケーションで、画面のレンダリングをクライアントサイドが担います。
必要なところだけをレンダリングすることができるので、ページ全体がリロードされることなく画面変化や遷移が行えます。
SPA では、より高速で流動的な UX をユーザに提供することができますが、同時に、以下のような問題を持っています。
SEO対策
SPA はクライアントサイドで JavaScript が実行されることでコンテンツがレンダリングされます。サーバサイドが返すのはただの空白のページです。
なので、JavaScript を実行できないクローラでは、コンテンツがない Web ページとして認識されてしまいます。
(Google に関して言えば、現在は JavaScript を解釈してくれるので問題ないとのこと)
初回ロード時間
SPA はまず空白のページを表示して、JavaScript をブラウザで読み込んで、それ評価し終わってからページのレンダリングが始まります。
そのため、初回のロード時間がどうしても長くなってしまいます。
サーバサイドレンダリングとの両立
これらの問題を解決するために、JavaScript が実行されないときや初回ロードのときは、サーバサイドでそのコンテンツをレンダリングするというアプローチが生まれました。
その後でクライアントサイドの JavaScript が読み込まれれば SPA として動作するので、SPA の良さも活かすことができます。
サーバサイドレンダリング (SSR) という言葉があえて使われるときは、この「SPA + SSR を両立したアーキテクチャ」を指していることが多いです。
クライアントサイドとサーバサイドのコード共有
しかし、クライアントとサーバで同じコンテンツをレンダリングするとなると、バリデーションやルーティングといったアプリケーションロジックや、ビューロジックに重複が出てしまいます。
サーバサイドは JavaScript 以外の言語で書かれることが多いので、開発者は異なる言語の同じロジックを、同時にメンテナンスし続けなければいけません。
そこで、クライアントとサーバを同じ言語 (= JavaScript) で記述し、同じコードを共有できるようにしよう、というアイディアが Isomophic JavaScript です。
つまりまとめると、SPA + SSR を両立するために、クライアントとサーバで同じコードが実行できると良くて、それが Isomorphic JavaScript
(もう少し知りたい人は Isomorphic Survival Guide を読むのがおすすめです)
Isomorphic から Universal に?
それから一時期は Isomorphic がかなり熱かったようなのですが、最近は Universal と言われています。
発端となったのは Universal JavaScript という記事で、この中で「クライアントやサーバに限らず、モバイルや組み込みデバイスといった環境でも実行できる」という意味を含めて、Universal という呼び方をすべきと言っています。
また、Isomorphic という言葉の意味自体について尋ねられることも多かったようで、Universal の方がより一般的で伝わりやすい、という理由もあるようです。
Isomorphic と Universal の違いは非常に主観的なもの、とも言っていて、基本的には、同じ対象に向けた呼び方が変わっただけのように思えます...が、英語に自信がないので不安。
Universal JavaScript を実感するには?
Universal Reactというチュートリアルが、とてもシンプルで分かりやすかったです。
(React を書いたことがない人だと、少し敷居が高いかもしれません...)
このチュートリアルを見るまでは、Universal JavaScript を実現するために、特殊なモジュールの導入が必要なんだろうと思っていましたが
React や Express、 webpack を使えば、変わったことをしなくても SSR ができます。
ただ、クライアントとサーバのいずれかでしか実行できない部分は、Universal なコードになるよう工夫する必要があります。
例えば window や document を使っている場合、Node.js では使えないので if (typeof(window) == 'undefined'){...}
という感じで分岐処理を入れる必要が出てきたりします。
Universal は悪いアイディア?
一方で、Say No to Universal Apps という記事では、Universal JavaScript について以下のように批判しています。
- ネイティブアプリのパフォーマンスは劇的に向上し、モバイルユーザの普及率はどんどん上がっていく
- Web の利用はなくならないが、利用率は下がる
- より良いユーザ体験のためには、プラットフォーム特有の機能を使用する必要がある
- Web は日々良くなっているが、パフォーマンスとユーザ体験においてネイティブアプリに打ち勝つことはできない
- すべてのプラットフォームに一つのコードベースというのは、本当に悪いアイディア
- これはプラットフォーム毎に異なるため、多くのハッキングを必要とし、コードベースの管理を非常に困難にする
- すべてに繋がるモノリシックなアプリケーションを長期的に管理するのは難しい
- 解決策は、プラットフォーム毎にアプリケーションを構築することである
まだまだ未知なところが多いですが、こんなところで。
間違いや誤解などがあれば、優しく指摘してくださるととても嬉しいです!
東京Node学園付属小学校 2時限目 for Girl で発表しました
発表のときのスライドを共有します。図がある分、もう少し分かりやすいかもしれません。
参考
- Isomorphic Survival Guide
- Isomorphic JavaScript: The Future of Web Apps
- yahoo/fluxible による SPA + Server Rendering の概観
- Isomorphic Architecture を実装してるときの細かいアレコレ
- react + redux + react-router のサーバサイドレンダリングを試してみた
- Universal JavaScript
- Universal JavaScript and the future of the Single Page Apps
- Universal React
- Say No to Universal Apps