Help us understand the problem. What is going on with this article?

ReactでSSR(サーバサイドレンダリング)している話

More than 3 years have passed since last update.

この記事はAkatsuki Advent Calendar 2016の7日目の記事です。

こんにちは、 @shimpeiws です。
アカツキのライブエクスペリエンス事業部で、Webエンジニアをしています。

今日は最近開発しているプロダクト、Wowful(現在β公開中)のアーキテクチャについて書きます。

※ 今回の記事は以前発表した :point_down: 2つのスライドの増補改訂版のポジションです。

Wowfulのサービス面の特徴と技術的な要求

Wowfulはサービスとして以下のような特徴を持っており、
これらの要求を解決できる技術・アーキテクチャの選定を行う必要がありました。

  • まずはWeb主導で展開する
  • BtoCのサービス
  • 利用ユーザはスマートフォンが多数になる予想
  • 検索からの流入を主な導線として想定
  • トラフィックが多いページのユーザインタラクションが複雑
  • SEOが大事

Wowfulのアーキテクチャ

Wowfulは以下の図のようなアーキテクチャ上で動作しています。

ServerSideRenderingするときのフロー

BFFにかける期待.006.png

SPAとして動作する時のフロー

BFFにかける期待.007.png

特徴的なのは、"Isomorphic JavascriptでSSR(サーバサイドレンダリング)を実現している"という点なのでこの点について掘り下げて紹介していきます。

なぜSSR(サーバサイドレンダリング)したかったか?

理由は2つで、1つ目はSEOのため、2つ目はユーザビリティ向上のためです。

SEO対策としてのSSR

"Wowfulのサービス面の特徴と技術的な要求"の項で触れましたが、
サービスの特徴として検索からの流入に重きをおいており、そのためSEOが非常に重要な位置を占めています。

SSRを導入する大きな動機として、SEO対策がありましたが、
GoogleのクローラはJSでの描画まで含めて認識している、という話もあり、効果的な選択であったかは疑問が残ります。

リクルートテクノロジーズ・リクルートライフスタイルの吉田尚弘さんのスライド、React with Reduxによる大規模商用サービスの開発 ではFetch as GoogleとPage Speed Insightの結果も提示されており、
GoogleのクローラはSPAであっても全コンテンツを認識しているという記載もあります。

ユーザビリティ向上のためのSSR

もう一つのSSRの目的としてユーザビリティ向上があげられます。

外部からランディングしたユーザを、真っ白なページやローディングで待たせること無く、
コンテンツが描画された状態で迎える事ができるのがメリットです。

実際的にはブラウザの標準的な動作にあわせている、という側面が強いので、ユーザビリティ向上というよりは、
SPAの動作をブラウザに合わせる努力をする、という方が正確かもしれません。

Node.js、 Isomorphic Javascript

Wowfulのアーキテクチャでは、SSRするために、Node.jsのサーバ(図中のPresentation Server)を置いています。
この構成を採用したのは、SSR時とクライアントでのSPAでの動作時で同じソースコードを使える = Isomorphicに動作させることができることにアーキテクチャ上のメリットを感じたためです。

例えばreact-railsを使えば簡単にReactでのSSRを実現することができますが、
SSRしつつSPAでも動作させることを考慮した場合、
初期表示用のデータ取得ロジックをRails側にもJavaScript側にも持つことになり、
ロジックが別の言語で重複してしまうことになります。

しかし、必ずしもIsomorphic Javascriptの採用だけがReactでSSRする際のベストプラクティスではありません。

r7akamuraさんのRuby on Rails on React on SSR on SPAは、react_on_railsのgemを中心に、つなぎこみのコードを丁寧に作ることで、Railsに寄せたSSRの構成を実現しています。

boilerplate

Isomorphicな構成のガイドラインとして、erikras/react-redux-universal-hot-example を参照しました。
ただし、作成から時間がたっており、npmのパッケージも古くなっているものが多いので、
構成の参考に留めておくことをおすすめします。

redux-async-loader

ReactでSSRする時に1つ難関となるのは、データ取得完了の待受です。

通常のReactアプリケーションであれば、初期表示用のデータが取得できるまでloadingを表示しておき、
データが揃った時点でstateの更新 -> Viewの更新といった流れが連続的に起こります。
しかしSSRの場合には、HTMLとして返却するのは一度なので、
データ取得完了 -> React.renderToString -> HTML返却のタイミングを決める必要があり、
データ取得完了を待ち受ける必要が出てきます。

そのためのnpmモジュールとして、Rezonans/redux-async-connectが先のboilerplateでは採用されていますが、
Wowfulではリクルートテクノロジーズ社がOSSとして公開しているrecruit-tech/redux-async-loaderを採用しました。

非常にシンプルなインタフェースながら、必要十分な機能を備えており、
例えば以下のようなコードでSSR時のデータの待受が可能です。

@asyncLoader((props, store) => (
  store.dispatch(fetchItem(props.params.id))
))

まとめ

実際にプロダクションで運用しているアーキテクチャやその選定理由について紹介しました。

  • SEOユーザビリティ向上のためにSSRすることにした
  • Isomorphic Javascriptのメリットを享受するためにNode.jsのサーバを用意した
  • Isomorphicな構成の参考としてboilerplateを参照した
  • データ取得完了の待受のために redux-async-loader を使っている

同じような構成を考えている方の参考になれば幸いです。


さて、明日の担当はウォーリーの仮装をさせると並ぶものなし、@paranishian です!

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away