【翻訳】AngularJSからReactへ: Isomorphicな方法

本エントリは翻訳リクエストより投稿いただきました。
ありがとうございます!リクエストまだまだお待ちしております!

先週、私たちはWebサイトを検索エンジン向けにインデックス付けできるようにしようとしていました。この記事では、私たちがWebサイトを書き直していて学んだことの要約を紹介したいと思います。

背景

2ヵ月前にRisingStack.comを作成した時、私たちはそのWebサイトでどんなテクノロジを使うか決めなくてはなりませんでした。イベントを追跡する静的なページが数ページあるだけだったので、とても簡単でしたが、私たちはWebサイトをスケーラブルでできるだけ高速なままにしておきたいと考えていました。
私たちのチームはAngularJSの経験が豊富なので、フロントエンドにAngularを選ぶのは妥当だと思われました。

この記事はReactやAngularJSがどちらか一方より優れている理由について述べているわけではないので注意してください。どちらがいいかは常にユースケース次第です。

“Angularな方法”

AngularJSはGoogleによって開発されているかなりすごいツールです。ルーティングや双方向データバインディングのようなすばらしい機能をたくさん提供して、開発を勢いづけ、テスト可能なアプリケーションを作り出しています。

Angularによって単一ページアプリケーション(SPA)を作成することができ、コンテンツをクライアント側でレンダリングできますが、JavaScriptをサポートしない検索ロボットはコンテンツにインデックスを付けることができません。
それはSEOの観点から深刻な問題になる可能性があります。特に新しく設立されたNode.js企業を有名にしたい時はね(^-^)

Angular site without JavaScript

JavaScriptを使用していない私たちのAngularサイト

koa-prerender

RisingStackでは、私たちは半端なことは好きではないので、この問題を解決したいと考えました。そんな時に登場したのがprerender.ioです。ヘッドレスブラウザを使って外部サーバ上にサイトをレンダリングし、その結果をHTMLで送り返してくれる外部サービスです(オープンソースプロジェクトでもあります)。
それにより、ほとんどの検索エンジンが読み取り可能なサイトになりますが、AngularJSバインディングが解かれてしまうので本物の人間のユーザのためにprerender.ioを使うことはできません。

私たちのサイトでは、ジェネレータをベースとした、prerender.ioにサポートされていないNode.jsフレームワークであるKoaが使われているので、私たちはprerender.ioを自分たちで実装しなければなりませんでした。
それでRisingStackはKoa向けのkoa-prerenderミドルウェアを公開しました。
簡単に言うと、リクエストパラメータ(_escaped_fragment_やuser-agentなど)からクローラを検出し、外部のprerenderサービスを呼び出して静的なHTMLコンテンツで応答します。

ようやくGoogleやYahooのような検索エンジンのほとんどにサイトを見つけてもらえるようになったので私たちは喜びましたが、それで終わりではありませんでした。ユーザエージェントは変わる可能性がありますし、同じユーザエージェントのままにしておきたくはないので、私たちはより良いソリューションを探し続けました。

Our Angular site without JavaScript
JavaScriptを使用していないがkoa-prerenderを使用している私たちのAngularサイト

IsomorphicなJavaScript

私たちが求めていたのは、最初にロードした時はサーバサイドでコンテンツをレンダリングするが、その後はシングルページアプリケーションとしての体験を提供するものです。
クライアントサイドとサーバサイドの両方でレンダリングすることができ、2つのサイドの間でアプリケーションの状態を共有できるものが必要でした。そうすれば、クライアントは、サーバがジョブを終えたポイントから続行できるはずです。
この種のアーキテクチャを実装するためには、コードベースがサーバサイドとクライアントサイドで共通でなければならず(BrowserifyまたはWebpack)、またアプリケーションも両方のサイドでレンダリングできなければなりません。

「Browserifyでは、従属関係をすべてまとめることにより、ブラウザ内でrequire(‘modules’)ができるようになります」 – browserify.org

このことは、事実上、Node.jsの従属関係システムとnpmパッケージをブラウザ内で使用できるということを意味します。例えば、AJAXリクエストのためのsuperagentや、フローコントロールを改善するためのasyncなどです。

Isomorphic JavaScript architecture
IsomorphicなJavaScript アーキテクチャ 出典:AirBnb Nerds

isomorphicなアプリケーションの詳細については、ぜひAirBnbの記事を参照してください:Isomorphic JavaScript: The Future of Web Apps

React

ユーザインタフェースを構築するためのJavaScriptライブラリ – React

Reactは、データバインディングに単方向のフローを使用してクライアントサイドとサーバサイドの高性能なレンダリングを提供します。ReactJSはオープンソースで、Facebook Engineeringチームにより構築されました。

Reactはフレームワークではないので、FacebookのFluxアプリケーションアーキテクチャのような他のソリューションを使って拡張します。

Fluxについて

「FluxはMVCを避けて単方向データフローを採用します。ユーザがReactビューと対話すると、このビューはセントラルディスパッチャを介して、アプリケーションのデータとビジネスロジックを保存する様々な記憶装置にアクションを伝え、このアクションは、影響を受けるすべてのビューを更新します。このことは、状態間でビューをどのように推移させるかを指定することなく記憶装置がアップデートの保存と送信を行うことが可能な、Reactの宣言型プログラミングスタイルでは特に効果的です」 – Flux docs

Flux architecture
Fluxアーキテクチャ 出典:http://facebook.github.io/

React + Flux + Koa = isomporhicの美点

ReactとFluxを使ってisomorphicなアプリケーションを作成すると決めてから、私たちは、他社からアイデア、つまりサンプルを探し始めました。
最終的には、Yahooのflux-examplesを元にしてサイトの構築を開始しました。

Yahooのflux-examplesには、ルーティングとExpressを使ったNode.jsの2つのisomorphicなアプリケーションのサンプルコードがありました。

このアイデアはとてもシンプルです。Webpackを使えば、サーバサイドとクライアントサイドの両方から実行可能なJavaScriptコードを書けるということです(私たちはWebpackからBrowserifyに変えてしまいましたが)。

Isomorphicなアーキテクチャの主なコンセプトは以下のとおりです。
アプリケーションの状態とコードは、ブラウザとサーバ間で共有されています。サーバがリクエストを受け取ると、新しいflux-reactアプリケーションインスタンスを生成してレンダリングをします。すると、ストレージ(アプリケーション)の状態がそのレンダリング済みのHTMLアウトプットに渡されます:サーバはこのレンダリング済みのファイルで応答します。

ブラウザは(BrowserifyやWebpackで作られた)同じコードをロードし、(サーバによって共有され、グローバル/ウィンドウスコープに送り込まれた)共有の状態からアプリケーションを起動させます。つまり、アプリケーションはサーバが処理を終えたポイントからずっと動き続けることができるのです。

ユーザは以前と同じように最初のロードで完全にレンダリングされたサイトを見ることができますが、超高速のシングルページアプリとしてネットサーフィンを続けることもできるのです。
JavaScriptなしでサイトのコンテンツを閲覧できるので、検索エンジンはインデックスを付けることができます。

RisingStack.comはKoaを使うので、私たちはいくつかのミドルウェアを移し変えなければなりませんでした。近日RisingStack GitHub repositoryで発表する予定です)

React site
JavaScriptを使用していない私たちのReactのサイト

結論

ここでの私たちにとって一番のプラスになったのは、インデックス可能なisomorphicなSPAがやっと使えるようになったことでしょう。これは私たちの最優先課題ではありませんでしたが、今や人間のユーザのためにもJavascriptなしで私たちのサイトが機能するようになったのです。

繰り返しになりますが、今回の記事の投稿の目的はReactがAngularJSより優れていると主張することではありません。ある部分ではReactが勝っているのは事実ですが、別の部分ではAngularJSより劣っている部分もあります。どちらがいいのかはユースケース次第でしょう。

また、この2つは共存することもできます。ngReactGridプロジェクトがいい例です。

今回はここまでです。Isomorphicの時代が今後、Web開発やNode.jsに何をもたらしてくれるのか、私たちはとても楽しみにしています。

もし類似の話題があれば、ぜひあなたのお話を聞かせてください。私たちのツイッターアカウントは@RisingStackです。

アップデート:

発表したばかりのisomorphicの例です。

アプリケーションの開発をお手伝いします

RisingStackではJavaScriptの開発とコンサルティングサービスを行っています。ご連絡お待ちしています!