LoginSignup
3
3

More than 5 years have passed since last update.

Scala.jsのSPAチュートリアルの翻訳開始(Play2.5入門⑧)

Last updated at Posted at 2016-05-05

Play2.5+Scala.jsのSPAチュートリアル

フィンランドのochrons氏が下回りのライブラリを自ら開発しつつ作成した、Play2.5+Scala.jsのSPAチュートリアルに興味を持った。

Scala.jsは日本でBig...!?

こちら、git bookベースの解説もつけてくれていてとっかかりやすい。そして、READMEに気になる一文が。

あなたは日本語を話せますか?Scala.js is Big in Japan, so I'm looking for help to translate the tutorial documentation into Japanese.

はい、私は日本語を話せます・・・Scala.jsは日本でBigネーム・・・!?

もしや、やはり、これのことか:
kore.PNG
出典 : https://tototoshi.github.io/slides/tenka1altjs-scalajs/

どうやら、世界的にも検索上位に"Scala.jsさいきょうのAltJS"が来ている模様。さすがのインパクト。。

で、日本のJSer (のモノ好きな人) の多くは名前を知っているScala.js、"実際のところ"の印象は、@mizchi氏のエントリーScala.js v0.6試してみたあたりを見て、ふーん(そこそこ動きはするのね)、、といった程度なのではないかと思う。ここから1年ちょっとたった現時点での、Scala.jsのバージョンは0.69。node.jsと組み合わせた場合の印象はさほど変わりはないと思う。そもそも、サーバ側がnode.jsでクライアント側をscala.jsにするメリットは少ない(nodeのコードもscala.jsで書けるのだろうけど、たぶんいろいろとはまり道があるはず)。

※ node.jsな人でこのエントリーを見てしまった人は、末尾のfluxインスパイアなscala/scala.jsライブラリdiodeだけをチラ見しておこう。

Play ScalaとScala.jsの組み合わせ

さて、サーバ側のWAFとしてPlay Scalaを選択している場合はどうか?
Playのクライアント側といえば、少し前まで、coffeescriptが定番としておすすめされていた。ES6時代が始まりつつある今、coffeescriptの選択に微妙感を覚えるフロントエンドエンジニアは増えているはず。
coffeescriptという選択肢にイマイチ感が漂っている今(追記:これは魅力的かも)、ES6だろうがjavaScriptをガリガリ書きたくないサーバ側のエンジニアならば、型ありのAltJSとしてScala.jsでを選択するというものありかもしれない。ちゃんと動作するならば。

ちゃんと動作します。

冒頭のチュートリアルをcloneすると、即座に動作させることができる。
チュートリアルGitbookの"getting started"の下訳を以下に記す:


下訳:はじめに

このリポジトリをforkして、Gitを用いて、あなたのコンピュータにcloneしましょう。
プロジェクトフォルダでsbtを実行します。SBTがプロジェクトのロードを終えた後、Playサーバをrunして起動します。
次いで、Webブラウザーで、localhost:9000にアクセスすることで、ダッシュボード・ビューを開くことができます。
この時点で、Playは、クライアント側とサーバ側双方のScalaアプリケーションをコンパイルし、パッケージ化し、サーバ上で実行できるようになっています。

この過程は少し時間がかかり、その進捗はSBTのコンソールに表示されます。
(立ち上がった)ダッシュボードは以下のように見えます。

kore.PNG

このアプリケーションは非常にシンプルです、二つのビュー(Dashboard とTodo)のみを含みます。
メニュー上の該当するアイテムをクリックすることで、これらのビューにアクセスできます。
Todoビューは、以下のように見えます。

todos

これで、起動及び実行の準備がすべて整いました。いよいよ、このアプリケーション動作の詳細を知るために、実装の詳細に飛び込むべき時です。

ここで、ちょっとだけコードを書き換えてみる実験をするために、BSTの`~runコマンドを使ってみるのも良いでしょう。
このコマンドにより、Playはあなたが書き換えたソースコードを自動的にリコンパイルします。
例えば、Dashboard.scala 内のチャートデータを変更してみて、webページをリロードしてみましょう。

下訳終わり


Java 8が入っている環境ならば、実際にここに書かれている通り、"sbt runのみ"で動作する(Play2.5コードとscala.jsコード双方の依存性解決を全てsbtがやってくれる)

本チュートリアルの魅力 :

コードの委細の解説は、gitbookの方を見ていただくか、(近い将来に出る)その日本語訳を見ていただくとして、このSPAチュートリアルに私が感じた魅力を少しだけ書いておく。ちゃんとした考察は翻訳後に書きたい。

①Ajax通信周りのライブラリAutowireとBooPickle

本チュートリアルでは、サーバ側のScalaコードとクライアント側のScala.jsコードとの通信を簡潔に書けるライブラリが導入されている。
こちらも下訳を引用しておく:


下訳:AutowireとBooPickle

Webクライアントとサーバ間での通信では、Ajaxが広く用いられています。Ajaxは非常にゆるく定義された技術の集合体です。

JQueryのように非常に有名なJavaScriptライブラリは、高レベルのアクセス手段から、ブラウザが開示している低レベルのプロトコルへのアクセス手段までを提供しています。
Scala.jsは、 dom.extensions.Ajax (もしくは、scalajs-dom 0.8+においては、dom.ext.Ajax) において、良いAjaxラッパーを提供しています。今のところ、このラッパーは非常に冗長(tedious)なシリアライズ/デシリアライズ オブジェクトの集まりであり、いくつものつまらない些細な事柄(all the dirty little details)に注意しなければなりません。

しかし、こうした委細の全てに一人で立ち向かう必要はありません。
我らがLi Haoyi (lihaoyi)が、 Autowireという素晴らしいライブラリを作成し、公開してくれています。
私が作った、BooPickleライブラリと組み合わせると、クライアント-サーバ間の通信を容易に行うことができます。

ただし、BooPickleではバイナリでのシリアライズ化フォーマットを用いられます。JSONフォーマットを使いたい場合には、uPickleを選択肢としてみてください。
SPAチュートリアルにおいては、当初、シリアライズにuPickleをを用いていたため、リポジトリのヒストリのここ
ここにおいて、uPickleによる参照コードを見ることができます。

クライアント-サーバ間通信の経路をビルドするにあたっては、クライアント側及びサーバ側にそれぞれ単一のオブジェクトを定義することだけが必要とされます。

import boopickle.Default._

// クライアント側
object AjaxClient extends autowire.Client[ByteBuffer, Pickler, Pickler] {
  override def doCall(req: Request): Future[ByteBuffer] = {
    dom.ext.Ajax.post(
      url = "/api/" + req.path.mkString("/"),
      data = Pickle.intoBytes(req.args),
      responseType = "arraybuffer",
      headers = Map("Content-Type" -> "application/octet-stream")
    ).map(r => TypedArrayBuffer.wrap(r.response.asInstanceOf[ArrayBuffer]))
  }

  override def read[Result: Pickler](p: ByteBuffer) = Unpickle[Result].fromBytes(p)
  override def write[Result: Pickler](r: Result) = Pickle.intoBytes(r)
}

アプリケーションにおいて指定する必要のある変数は、用いたいサーバのURLのみです。他のすべては、マクロの魔法を通じ、自動的に生成されます。

サーバ側はさらにシンプルで、単にAutowireにBooPickleをシリアライズに用いることを知らせるだけです。

import boopickle.Default._

// サーバ側
object Router extends autowire.Server[ByteBuffer, Pickler, Pickler] {
  override def read[R: Pickler](p: ByteBuffer) = Unpickle[R].fromBytes(p)
  override def write[R: Pickler](r: R) = Pickle.intoBytes(r)
}

これで、AjaxClientのセットアップは終了です。 サーバの呼び出し方は以下のようにシンプルです。

import scala.concurrent.ExecutionContext.Implicits.global
import boopickle.Default._
import autowire._

AjaxClient[Api].getTodos().call().foreach { todos =>
  println(s"Got some things to do $todos")
}

下訳終わり


②FluxとElmに触発されたライブラリdiodeも開発中。

上のチュートリアルでも一部登場している、"immutable application model"を管理するためのscalaライブラリDiodeが良さ気。

こちらは、チュートリアル作者のochrons氏が同じく開発者で、FluxとElmに触発されたとのこと。とにかく、ochrons氏は、scala.jsを"現場"に投入できるように尽力してくれている。diodeの理解はこれからなのだけど、このdiodeのgitbookをななめ読みして、Scala.jsのSPAチュートリアルの翻訳をお手伝いしようと決めた。
http://ochrons.github.io/diode/index.html

Diode was born out of the need of having something similar to Redux or Om for Scala applications. It's a very simple but powerful library with three basic tenets:
1.Model is your state, keep no other state
2.Thou shall not directly modify the state
3.State is always replaced with the next state
If you are interested in the motivation, or prior art for Diode, we recommend reading through Redux introduction and Flux architecture.

Diodeが安定版となった場合、サーバ側とクライアント側の双方で、同じやり方で"immutable application model"を管理できるというのは大きい。近い将来(1年後くらい?)、play scala+scala.jsが実用的な選択肢になるのかもしれないという夢を見た感じ。

3
3
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
3
3