【Java】【react】jettyサーバーでreactをserver side renderingしてみた


今回書くこと

Nashorn使ってreactをserver side renderingやってみたらさくっと動いたのでメモ。

つかったもの

・Jetty(軽量アプリケーションサーバ)

・thymeleaf(おすすめテンプレートエンジン)

・React

内容

準備

  • jettyを組み込んだプロジェクトを作っておく
  • react.jsのスターターキットみたいなのをダウンロードしておく

ポイント

AbstractHandlerをextendsしたとこで、
Thymeleafのテンプレートエンジンと、reactを読み込んだスクリプトエンジンを初期化しておく。

JettyHandler.java
    protected void doStart() throws Exception {
        // Thymeleaf
        ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
        resolver.setTemplateMode("HTML5");
        resolver.setPrefix("html/");
        resolver.setSuffix(".html");
        resolver.setCharacterEncoding(CHARSET);
        resolver.setCacheTTLMs(3600000L);
        resolver.setCacheable(!JavaInJettyProperties.getBoolean(Name.DEVELOP));
        templateEngine = new TemplateEngine();
        templateEngine.setTemplateResolver(resolver);

        // script engine
        manager = new ScriptEngineManager();
        engine = manager.getEngineByName("react");
        engine.eval(new FileReader("src/main/resouces/build/react.js"));

        super.doStart();
    }

動くかどうかの確認なのでThymeleafではこんな感じ。
clientでもreactしたいときはreactを読み込んでおく必要ありますね。

index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8"/>
        <title>index</title>
    </head>
    <body>
        <div id="contents" th:utext="${content}"></div>
    </body>
</html>

あとは、react使ってサーバーサイドでレンダリング。
オーバーライドしたhandleメソッドでどうぞ。
メソッド名が意味不明になりましたが、いいんです、単なる確認ですから。
本当に使うときにはちゃんと書いて下さい。外部ファイル読込とか作る感じかと思います。

JettyHandler.java
()ルーティングとか色々~~

final Context ctx = new Context();              
engine.eval(getComponentString());
ctx.setVariable("content", engine.eval(getRenderString("Hello world!!")));

templateEngine.process("index", ctx, response.getWriter());
JettyHandler.java
    private String getComponentString(){
        return 
        "var MyComponent = React.createClass({" +
                "render: function() {" +"return React.DOM.div(null, this.props.text)" +"}" +
        "});";
    }

JettyHandler.java
    private String getRenderString(String text){
        return
            "React.renderToString(React.createFactory(MyComponent)({" +"text: '" + text + "'" + "}))";
    }

あとがき

簡単に動かすとこまでできました。

実際使う場合は外部ファイルを読み込んで、とか
jsxで記載したものを変換するところを自動化して、とか
やんなきゃいけないことがいくつかありますが、目新しいことはなさそうですね。

jetty+Thymeleaf+reactって上手くいくのか不明でしたがやってみた感じ、
この組み合わせ、何か良い感じになりそう。

NashornではJavaScriptがJavaバイトコードになっているらしく、
パフォーマンスも良いです。

機会があれば使いやすいベースを作って使いこんでみたいです。