8)サーバサイドレンダリング
インターネットに公開しているサイトではユーザビリティを考えてJavaScriptを多用しています。しかし、検索エンジンのクローラは一般的にはJavaScriptを解釈しません。そのため、ブラウザがあるURLにアクセスした場合にJavaScriptでレンダリングされるHTMLと、クローラが同じURLにアクセスした場合にサーバでレンダリングされるHTMLを同一にする必要があり、クライアントサイドとサーバサイドで同じロジックを別の言語で実装するなど涙ぐましい努力が行われてきました。
React.jsではブラウザのDOM を使わずに軽量なDOM を使用してるため、レンダリングにブラウザは不要です。JavaScriptエンジンを使用すれば、クライアントサイドのコードをほぼそのまま使用できるため、同一のロジックを異なる言語で実装する必要はありません。
今回実装したOSS Radar Scope®ではSEO のことも考えてサーバサイドレンダリングも行っています。サーバサイドはJavaで動いているので、Java8で利用出来るJavaScriptエンジンのNashornを利用しています。
しかし、React.jsのサーバサイドレンダリングはNode.js を想定しているようで、Nashornを単純に使用しても正しく動作しません。ここでは、NashornでReact.jsのサーバサイドレンダリングをする際にぶつかった壁について記載していきます。
requireが使用できない
まず一番最初の壁はrequireが使用できないことです。 Nashornはrequireが実装されていないため、最初にrequireが実行できるようにする必要があります。jvm-npmというライブラリがあり、この問題を解決できます。jvm-npmはload
で読み込ませます。
ScriptEngine engine = new ScriptEngineManager(null).;engine.;
React.jsが使用しているグローバル変数がNashornに存在しない
React.jsは内部で以下のグルーバル変数を利用しています。
- console
- console.warn
- process
- process.env
- process.env.NODE_ENV
これらはNode.js にはあるようですが、Nashornには存在しません。したがってこれらをあらかじめJavaのNashorn内で定義しておく必要があります。
private void throws ScriptException {engine.;engine.;engine.;engine.;}
Ajaxが実行できない
当初アクションの内部でAjax を実行していたのですが、Aciton内部にAjax があるとサーバサイドでレンダリングすることができません。Action内部でAjax を呼ばず、Router内でAjax を利用するように構造を変更しています。サーバサイドではあらかじめ取得した値を直接Router.run内で使用しています。
var ranking = JavafromrankingList;var categories = JavafromcategoryList;var products = JavafromproductList;var rankDates = JavafromrankDateListmap return time; ;var props =ranking: rankingcategories: categoriesproducts: productsyearMonth: yearMonthrankDates: rankDatesdotPosition: RadarStorecalcDotPositionurl yearMonth ranking categories isChildCategory;var html;Routerrunroutes urlhtml = ReactrenderToString<Handler props/>;;html;
作成したソースコード
これらの問題を解決し、無事にサーバサイドレンダリングができるようになりました。こちらで実装を見ることができますので、参考にしてください。