LoginSignup
4
8

More than 5 years have passed since last update.

PlayでカスタマイズされたプロジェクトでReact.jsを使う

Last updated at Posted at 2016-06-04

完成形

やりたいことは、下記のような形のプロジェクトでsbt(activator)のrunコマンドだけでScalaとJSXのコンパイルとサーバ起動が出来るようになること。

project

手順

reactjsプラグイン

まず、sbt上でJSXをコンパイルできるようになるプラグインを使います。
sbt-reactjs

plugins.sbtに下記を追記します。

plugins.sbt
addSbtPlugin("com.github.ddispaltro" % "sbt-reactjs" % "0.6.8")

これでsbt上でJSXのコンパイルが出来るようになります。
ちなみにデフォルトではnode.jsを使ってコンパイルしようとするようですが、入っていなくてもjs-engineのTriremeを使用するのでひとまず気にしなくて良さそうです。

プロジェクト設定

ちょっと大きなプロダクトになるとマルチプロジェクト構成にする場合がほとんどだと思います。
今回はPlayの標準の規約ではなくて、独自のパッケージのルールでソースコードを配置したいと思います。

build.sbt
organization := "my.company"

name := "PlayReact"

version := "1.0"

lazy val commonSettings = Seq(scalaVersion := "2.11.8")

lazy val web = (project in file("web"))
  .settings(commonSettings: _*)
  .enablePlugins(PlayScala)
  .disablePlugins(PlayLayoutPlugin)
  .settings(
    sourceDirectories in (Compile, TwirlKeys.compileTemplates) := Seq((scalaSource in Compile).value / "my" / "company" / "system"),
    sourceDirectories in (Test, TwirlKeys.compileTemplates) := Seq((scalaSource in Test).value / "my" / "company" / "system"),
    sourceDirectory in Assets := (scalaSource in Compile).value / "my" / "company" / "system" / "assets",
    sourceDirectory in TestAssets := (scalaSource in Test).value / "my" / "company" / "system" / "assets",
    resourceDirectory in Assets := baseDirectory.value / "public",
    ReactJsKeys.harmony := true,
    ReactJsKeys.es6module := true,
    ReactJsKeys.stripTypes := true
  )
  .dependsOn(common)

lazy val common = (project in file("common"))
  .settings(commonSettings: _*)

最終的に上のような感じにしました。
.disablePlugins(PlayLayoutPlugin)でPlay標準のレイアウトを解除します。(app下にソース置かなきゃいけないやつ)
また、Twirlのテンプレートの配置位置も調整しています。

.jsxファイルはAssets扱いなのでsourceDirectory in Assetsにて配置位置の調整を行います。
PlayではSbtWebを使用しているので、sbt-reactjsを使う際に改めてプラグイン有効化を行う必要はありません。
JSXのコンパイルオプションはReactJsKeysで指定できます。

ルーティング設定

routes
GET     /                           my.company.system.controllers.Application.index
GET     /api                        my.company.system.controllers.Application.api

GET     /assets/*file               controllers.Assets.at(path="/public", file)

FQCNでクラス名を指定しなければいけないところ以外は特に変わったことはありません。

コントローラーとJSXとビュー

パッケージ以外はいつも通りのコントローラーです。

Application.scala
package my.company.system.controllers

import my.company.common.Resource
import play.api.libs.json.Json
import play.api.mvc._

class Application extends Controller {

  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }

  def api = Action {
    Ok(Json.toJson(new Resource().data)) // Seq("hoge1", "hoge2", "hoge3")
  }

}

JSXの配置場所はbuild.sbtで指定したmy.company.system.assetsパッケージ下のjavascriptパッケージです。
コードの中身は何の変哲もないJSXファイルです。

app.jsx
const DataList = React.createClass({
    getInitialState: () => {
        return {data: []};
    },
    componentDidMount: function() {
        const self = this;
        superagent
            .get("/api")
            .end(function(err, res){
                self.setState({data: res.body});
            });
    },
    render: function() {
        const toListItem = x => <li>{x}</li>;
        return (
            <ul>
                {this.state.data.map(toListItem)}
            </ul>
        );
    }
});

ReactDOM.render(
    <DataList />,
    document.getElementById("main")
);

テンプレートは以下のようになります。
JSXでコンパイルされた物は@routes.Assets.at("javascripts/ファイル名.js")でパスが取得できます。

index.scala.hml
@(title: String)
<!DOCTYPE html>
<html>
    <head>
        <title>@title</title>
        <script src="//fb.me/react-with-addons-0.14.8.min.js"></script>
        <script src="//fb.me/react-dom-0.14.8.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/superagent/1.2.0/superagent.min.js"></script>
    </head>
    <body>
        Hello World!!
        <div id="main"></div>
        <script src="@routes.Assets.at("javascripts/app.js")"></script>
    </body>
</html>

実行結果

http://localhost:9000/にアクセスして得られるレスポンス

Hello World!!

  • hoge1
  • hoge2
  • hoge3

終わり

javascript側はもっといろいろ考えることがありそうですが、ひとまずsbtだけでScalaとJSXのコンパイルができるようになりました。
実際にやってみるとsbtだけでフロントエンドとバックエンドの両方がコンパイル&実行できてとても楽です。

4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8