SlideShare une entreprise Scribd logo
1  sur  23
Télécharger pour lire hors ligne
Isomorphic Web
development 
with Scala & Scala.js
TanUkkii
isomorphic tokyo meetup
2015/4/30
I am ...
• @TanUkkii007 on Twitter
• Web frontend engineer
• だったけどゲーム開発が辛くてサーバーサイドを
Scalaで開発する人に
• Scala業務歴4ヶ月
Agenda
1. 開発環境を共有する
2. コードを共有する
3. アーキテクチャを共有する
クライアントーサーバー間で
Motivation
• Scala + Akka + SprayでAPIサーバーを開発
• StrongLoopのApi Exprolerみたいなのを作りたい
• Scala.jsでisomorphicにつくる!
REST/HTTP server build on Akka Actors
Why Scala.js?
• クライアントーサーバーで同一の開発環境
• クライアントーサーバーでコードの共有
• 片手間クライアント開発
1. Sharing development
environment: 
Building applications with sbt
• プロジェクト定義
• Scalaのバージョン
• 依存ライブラリ
• コンパイルオプション
Java/Scalaのビルドツール
設定 タスク
name := “your_project_name”



scalaVersion := "2.11.6"



libraryDependencies ++= Seq(

"com.typesafe.akka" %% “akka-actor" % "2.3.10"

)
!
scalacOptions in ThisBuild ++= Seq("-feature")
build.sbt
• 依存ライブラリの解決
• コンパイル
• テスト
• REPLの起動
Multi-project build
- client
- server
- root
import sbt._

import Keys._



object IsomorphicBuild extends Build {



lazy val root = project.in(file(“."))


lazy val server = Project(“server", file(“server"))



lazy val client = Project("client", file(“client”))
!
}
project/Build.scala
sbtではサブプロジェクトを複数定義できる
↓サーバーもクライアントも
サブプロジェクトとして定義
相似のプロジェクト構造ができる→
import sbt._

import Keys._

import org.scalajs.sbtplugin.ScalaJSPlugin

import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._





object IsomorphicBuild extends Build {



lazy val root = project.in(file(".")).aggregate(server, client)



lazy val server = Project(“server", file(“server"))





lazy val client = Project("client", file(“client")).enablePlugins(ScalaJSPlugin)
.settings(

persistLauncher in Compile := true,

skip in packageJSDependencies := false

)

}
project/Build.scala
Make Scala.js project
!
addSbtPlugin(“org.scala-js" % "sbt-scalajs" % "0.6.2")
project/plugins.sbt
Scala.jsプラグインを追加
clientプロジェクトで
Scala.jsプラグインを有効化
Make Scala.js project
isomorphic
!
import sbt._

import Keys._

import org.scalajs.sbtplugin.ScalaJSPlugin

import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._



object IsomorphicBuild extends Build {



lazy val root = project.in(file(".")).aggregate(server, client)



lazy val server = Project(“server", file(“server"))





lazy val client = Project("client", file(“client")).dependsOn(server).enablePlugins(ScalaJSPlugin)
.settings(

unmanagedSourceDirectories in Compile +=
(sourceDirectory in server).value/"main"/"scala"/"jp.isomorphic.example" / “shared",
packageJSDependencies in Compile := {

val base = (packageJSDependencies in Compile).value

IO.copyFile(base, (baseDirectory in server).value / "src/main/resources/js" / base.getName)

base

},

persistLauncher in Compile := true,

skip in packageJSDependencies := false

).settings(Seq(fastOptJS, fullOptJS) map { packageJSKey =>

crossTarget in (Compile, packageJSKey) :=

(baseDirectory in server).value / "src/main/resources/js"

})

}
project/Build.scala
サーバーからクライアントに
クラスパスを通す
(Scalaコンパイルが可能に)
コンパイル対象に
サーバー側のソースの一部を追加
(Scala.jsコンパイルが可能に)
Scala.jsのコンパイル結果を
サーバー側にコピー
Using CrossProject to build
isomorphic project structure
-shared
- js
- jvm
import sbt.Keys._

import sbt._
import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._

!
!
object ApplicationBuild extends Build {



lazy val root = project.in(file("."))





lazy val sharedProject = crossProject.in(file("."))

.settings()

.jvmSettings()

.jsSettings()

)





lazy val js: Project = sharedProject.js.settings()





lazy val jvm: Project = sharedProject.jvm.settings()

}

!
ScalaJSPluginの
CrossProjectを使えば
簡単にisomorphicな
プロジェクト構造を作れる
scalajs-spa-tutorialを参照scalajs-cross-compile-example,
2. Sharing codes between
Client and Server
• Scala.jsで利用可能なライブラリ
• シリアライゼーションによるScalaデータ型の通信
• 型安全なAPIの呼び出し
• マクロ
Available Libraries
• DOM
• jQuery
• React.js
• AngularJS
www.scala-js.orgにもっと多く載っている
JSライブラリの
型付けされたインターフェース
• Scalaz
• NICTA/rng
Scalaライブラリのポート
• Scala.Rx
• Monifu
• autowire
• uPickle
最初からクロスコンパイル前提で
作られたライブラリ※Scalaは型だけ提供。実装はJS。
※本家のクロスコンパイルできない
部分を修正してJSを提供
※ScalaとJSを提供
Pickling (serialization)
• クラス階層情報の喪失
Scala.jsの大問題:可逆的なJSONのシリアライズ
リフレクションを使わずにコンパイル時に少ないコードで解決しなければならない。
サーバー クライアント
JSON
{"fruits": [{"color": "yellow"}, {"color": "red"}]}
{"points": [{"x": 1, "y": 2}, {"x": 1, "y": 2}]}
null [[]]
val fruits: List[Fruit] = List(Banana("yellow"), Apple("red"))
val p = Point(1,2); val points = List(p, p)
val option: Option[Option[Int]] = None
通信
• 参照同一性の喪失
• Optionの扱い
Scalaデータ型 Scalaデータ型
Cross-compiled 
pickling libraries
きれいな
JSON形式
クラス階
層の保持
参照同一
性の保持
Anyの解
決
uPickle ○
難しいことは忘れて
きれいなJSONを吐くことに注力
Optionが配列として表現される
Prickle ○ ○
可逆性を高めるため
メタ情報をJSONに保持させている
Scala.js
Pickling
○ ○
型の登録処理が事前に必要
サポートがあまりよくない
Binary serialization with
BooPickle and XHR2
def request(method: String, url: String, body: ArrayBuffer): Future[ByteBuffer] = {

val promise = Promise[ByteBuffer]

val xhr = new XMLHttpRequest()

xhr.onreadystatechange = { (e: Event) =>

if (xhr.readyState == 4) { if (xhr.status >= 200 && xhr.status < 300) {

val byteBuffer = TypedArrayBuffer.wrap(xhr.response.asInstanceOf[ArrayBuffer])

promise.success(byteBuffer)

} else promise.failure(AjaxException(xhr))

}}

xhr.open(method, url)

xhr.responseType = "arraybuffer"

xhr.setRequestHeader("Content-Type", "application/octet-stream")

xhr.setRequestHeader("Accept", "application/octet-stream")

xhr.send(body)

promise.future

}
val byteBuffer = Pickle.intoBytes(SampleRequest("Hello"))

request(method, url, byteBuffer.arrayBuffer()).map(Unpickle[SampleResponse].fromBytes(_))
• JSONではなく、バイナリにシリアライズ
• XHR level2のバイナリサポートを利用
• JSのArrayBufferを使う
• メディアタイプは application/octet-stream
• クラス階層、参照の同一性も復元可能
Client-server communication
with Autowire
object AutowireClient extends autowire.Client[String, Reader, Writer]{

override def doCall(req: Request): Future[String]

}
trait MyApi {

def sampleRequest(id: Int): SampleResponse

}
object MyApiImpl extends MyApi{

def sampleRequest(id: Int) = SampleResponse(id)

}
AutowireClient[MyApi].sampleRequest(1).call().map(println)
path("api" / Segments){ s =>

extract(_.request.entity.asString) { e =>

complete {

AutowireServer.route[MyApi](MyApiImpl)(

autowire.Core.Request(s, upickle.read[Map[String, String]](e)))

}}}
object AutowireServer extends autowire.Server[String, Reader, Writer]{

val routes = AutowireServer.route[MyApi](MyApiImpl)

}
Autowire
マクロマジック!!
AutowireはAjaxにおける
クライアントーサーバー間のAPIの煩雑さを
RPCスタイルのメソッド呼び出しで
解決するライブラリ
• なぜかRPCは自動で解決される
• API呼び出しにおける間違いは
コンパイル時に発見される
1. sharedでRPCインターフェースを定義
2. serverでRPCインターフェースを実装
3. serverでルーティング部分関数をマクロにより生成
4. serverでルーティング部分関数を呼び出してレスポンスを返す
5. clientでAjaxの通信の仕方を実装
6. clientでRPC関数を呼び出す
Macro
performing macro expansion AutowireServer.route[jp.isomorphic.example.MyApi]
(<empty> match {

case autowire.Core.Request(Seq("jp", "isomorphic", "example", "MyApi", "sampleRequest"), (args$macro$1 @
_)) => autowire.Internal.doValidate({

<synthetic> <artifact> val x$2 = autowire.Internal.read[String, Int](args$macro$1,
scala.util.Left(autowire.Error.Param.Missing("id")), "id", ((x$1) => AutowireServer.read[Int](x$1)));

Nil.$colon$colon(x$2)

}) match {

case scala.$colon$colon((id @ (_: Int @unchecked)), Nil) =>
scala.concurrent.Future.successful(MyApiImpl.sampleRequest(id)).map(((x$3) => AutowireServer.write(x$3)))

case _ => $qmark$qmark$qmark

}

}: autowire.Core.Router[String])
種明かし:-Ymacro-debug-liteコンパイルオプションでマクロを展開する
package jp.isomorphic.example
trait MyApi {

def sampleRequest(id: Int): SampleResponse

}
マクロは
←から、関数のシグニチャに対して
パターンマッチをかける部分関数
を作っていた
※Scalaのマクロは抽象構文木を操るすごいやつです
3. Sharing Application
Architecture
Scalaでフロントエンドのアプリケーションをいざ書くときに
今までやってきたことをScalaでどう表現するとよいか迷う
オブザーバーパターン → ?
アーキテクチャをシェアして
コンテクストスイッチのコストを減らそう!
Common Practice:
Unidirectional Data Flow
• Tell, don t ask.
• Fire and forget.
Flux
Scalajs SPA Tutorialがこの共通点からアプローチしている
• unidirectional data flow
• message passing
複雑さに対抗する手段のコンセプトは同じ
Flux in Scala
つまりStoreがActorになった
Scalajs SPA Tutorial* image from
trait Actor {

type Receive = PartialFunction[Any, Unit]



def receive: Receive



def !(message: Any) = {

receive(message)

}

}
trait Dispatcher {

var actors = Set.empty[Actor]



def dispatch(message: Any) = {

actors.foreach { actor =>

actor ! message

}

}



def register(actor: Actor) = {

actors = actors + actor

}



def unregister(actor: Actor) = {

if (actors.contains(actor)) {

actors - actor

}

}

}
Dispatcherは
Actorプログラミングにおける
Recipient Listパターン
var Dispatcher = {
_listeners: [],
register: function(callback) {
this._listeners.push(callback);
return this;
},
unregister: function(callback) {
var index = this._listeners.indexOf(callback);
if (index !== -1) {
delete this._listeners[index];
}
return this;
},
dispatch: function(...args) {
this._listeners.forEach(callback =>
callback.apply(this, args)
);
return this;
}
};
※Recipient List: メッセージを複数のアクターに拡散
し仕事を分散して処理する際に、拡散先の受信者である
アクター参照の一覧を保持しているもの
object SampleDispatcher extends Dispatcher



object SampleActorProtocol {

case class Foo(message: String)

case class Bar(message: String)

}



object SampleActor extends Actor {

import SampleActorProtocol._



SampleDispatcher.register(this)



def receive: Receive = {

case Foo(message) => println(message)

case Bar(message) => println(message)

}

}
!
import SampleActorProtocol._

SampleDispatcher.dispatch(Foo("Hello"))
Dispatcher.register(function(payload) {
if (payload.type === "FOO") {
console.log(payload.message);
} else if (payload.type === "BAR") {
console.log(payload.message);
}
});
!
Dispatcher.dispatch({type: "FOO", message: "Hello"});
!
!
!
!
!
!
!
!
!
!
!
• Dispatcherに関数ではなくActorオブジェクトを登録する
• payloadを処理する関数はActorのReceive部分関数に相当
• payloadはメッセージ
Conclusion
• Scala + Scala.jsでクライアントーサーバーを高度
に統合できる
• (ただし他のシステムとのinteropが犠牲になるかも
• みんなScala.jsを使おう!!!

Contenu connexe

Tendances

Flux react現状確認会
Flux react現状確認会Flux react現状確認会
Flux react現状確認会VOYAGE GROUP
 
ECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングTanUkkii
 
Closure Compiler Updates for ES6
Closure Compiler Updates for ES6Closure Compiler Updates for ES6
Closure Compiler Updates for ES6Teppei Sato
 
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略Teppei Sato
 
アメブロ2016 アメブロフロント刷新にみる ひかりとつらみ
アメブロ2016 アメブロフロント刷新にみる ひかりとつらみアメブロ2016 アメブロフロント刷新にみる ひかりとつらみ
アメブロ2016 アメブロフロント刷新にみる ひかりとつらみKazunari Hara
 
React+TypeScriptもいいぞ
React+TypeScriptもいいぞReact+TypeScriptもいいぞ
React+TypeScriptもいいぞMitsuru Ogawa
 
ReactをRailsとどっぷり使ってみた話と、フロントエンド×AWSのこれから
ReactをRailsとどっぷり使ってみた話と、フロントエンド×AWSのこれからReactをRailsとどっぷり使ってみた話と、フロントエンド×AWSのこれから
ReactをRailsとどっぷり使ってみた話と、フロントエンド×AWSのこれからYusuke Murata
 
2016/12/17 ASP.NET フロントエンドタスク入門
 2016/12/17 ASP.NET フロントエンドタスク入門 2016/12/17 ASP.NET フロントエンドタスク入門
2016/12/17 ASP.NET フロントエンドタスク入門miso- soup3
 
capybara で快適なテスト生活を
capybara で快適なテスト生活をcapybara で快適なテスト生活を
capybara で快適なテスト生活をRyunosuke SATO
 
Service worker が拓く mobile web の新しいかたち
Service worker が拓く mobile web の新しいかたちService worker が拓く mobile web の新しいかたち
Service worker が拓く mobile web の新しいかたちKinuko Yasuda
 
PHP Application E2E with Capybara
PHP Application E2E with CapybaraPHP Application E2E with Capybara
PHP Application E2E with CapybaraYoshiaki Yoshida
 
SIROK技術勉強会 #1 「Reactってなんだ?」
SIROK技術勉強会 #1 「Reactってなんだ?」SIROK技術勉強会 #1 「Reactってなんだ?」
SIROK技術勉強会 #1 「Reactってなんだ?」Naoyuki Kataoka
 
RailsでReact.jsを動かしてみた話
RailsでReact.jsを動かしてみた話RailsでReact.jsを動かしてみた話
RailsでReact.jsを動かしてみた話yoshioka_cb
 
angular1脳で見るangular2
angular1脳で見るangular2angular1脳で見るangular2
angular1脳で見るangular2Moriyuki Arakawa
 
Ember コミュニティとわたし
Ember コミュニティとわたしEmber コミュニティとわたし
Ember コミュニティとわたしRyunosuke SATO
 
おれおれブログシステムにServiceWorkerを導入してみた #serviceworker
おれおれブログシステムにServiceWorkerを導入してみた #serviceworkerおれおれブログシステムにServiceWorkerを導入してみた #serviceworker
おれおれブログシステムにServiceWorkerを導入してみた #serviceworkerToshiaki Maki
 
なぜ人は必死でjQueryを捨てようとしているのか
なぜ人は必死でjQueryを捨てようとしているのかなぜ人は必死でjQueryを捨てようとしているのか
なぜ人は必死でjQueryを捨てようとしているのかYoichi Toyota
 

Tendances (19)

Flux react現状確認会
Flux react現状確認会Flux react現状確認会
Flux react現状確認会
 
ECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミング
 
Closure Compiler Updates for ES6
Closure Compiler Updates for ES6Closure Compiler Updates for ES6
Closure Compiler Updates for ES6
 
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略
 
アメブロ2016 アメブロフロント刷新にみる ひかりとつらみ
アメブロ2016 アメブロフロント刷新にみる ひかりとつらみアメブロ2016 アメブロフロント刷新にみる ひかりとつらみ
アメブロ2016 アメブロフロント刷新にみる ひかりとつらみ
 
React+TypeScriptもいいぞ
React+TypeScriptもいいぞReact+TypeScriptもいいぞ
React+TypeScriptもいいぞ
 
ReactをRailsとどっぷり使ってみた話と、フロントエンド×AWSのこれから
ReactをRailsとどっぷり使ってみた話と、フロントエンド×AWSのこれからReactをRailsとどっぷり使ってみた話と、フロントエンド×AWSのこれから
ReactをRailsとどっぷり使ってみた話と、フロントエンド×AWSのこれから
 
20160927 reactmeetup
20160927 reactmeetup20160927 reactmeetup
20160927 reactmeetup
 
2016/12/17 ASP.NET フロントエンドタスク入門
 2016/12/17 ASP.NET フロントエンドタスク入門 2016/12/17 ASP.NET フロントエンドタスク入門
2016/12/17 ASP.NET フロントエンドタスク入門
 
capybara で快適なテスト生活を
capybara で快適なテスト生活をcapybara で快適なテスト生活を
capybara で快適なテスト生活を
 
Service worker が拓く mobile web の新しいかたち
Service worker が拓く mobile web の新しいかたちService worker が拓く mobile web の新しいかたち
Service worker が拓く mobile web の新しいかたち
 
PHP Application E2E with Capybara
PHP Application E2E with CapybaraPHP Application E2E with Capybara
PHP Application E2E with Capybara
 
SIROK技術勉強会 #1 「Reactってなんだ?」
SIROK技術勉強会 #1 「Reactってなんだ?」SIROK技術勉強会 #1 「Reactってなんだ?」
SIROK技術勉強会 #1 「Reactってなんだ?」
 
RailsでReact.jsを動かしてみた話
RailsでReact.jsを動かしてみた話RailsでReact.jsを動かしてみた話
RailsでReact.jsを動かしてみた話
 
angular1脳で見るangular2
angular1脳で見るangular2angular1脳で見るangular2
angular1脳で見るangular2
 
Ember コミュニティとわたし
Ember コミュニティとわたしEmber コミュニティとわたし
Ember コミュニティとわたし
 
おれおれブログシステムにServiceWorkerを導入してみた #serviceworker
おれおれブログシステムにServiceWorkerを導入してみた #serviceworkerおれおれブログシステムにServiceWorkerを導入してみた #serviceworker
おれおれブログシステムにServiceWorkerを導入してみた #serviceworker
 
Swagger 入門
Swagger 入門Swagger 入門
Swagger 入門
 
なぜ人は必死でjQueryを捨てようとしているのか
なぜ人は必死でjQueryを捨てようとしているのかなぜ人は必死でjQueryを捨てようとしているのか
なぜ人は必死でjQueryを捨てようとしているのか
 

En vedette

React Canvasで作るFlappy Bird
React Canvasで作るFlappy BirdReact Canvasで作るFlappy Bird
React Canvasで作るFlappy BirdTakuya Tejima
 
ng-japan 2015 TypeScript+AngularJS 1.3
ng-japan 2015 TypeScript+AngularJS 1.3ng-japan 2015 TypeScript+AngularJS 1.3
ng-japan 2015 TypeScript+AngularJS 1.3Masahiro Wakame
 
AngularとOnsen UIで作る最高のHTML5ハイブリッドアプリ
AngularとOnsen UIで作る最高のHTML5ハイブリッドアプリAngularとOnsen UIで作る最高のHTML5ハイブリッドアプリ
AngularとOnsen UIで作る最高のHTML5ハイブリッドアプリアシアル株式会社
 
アメブロの大規模システム刷新と それを支えるSpring
アメブロの大規模システム刷新と それを支えるSpringアメブロの大規模システム刷新と それを支えるSpring
アメブロの大規模システム刷新と それを支えるSpringTakuya Hattori
 
32 Strategies for Building a Positive Learning Environment
32 Strategies for Building a Positive Learning Environment32 Strategies for Building a Positive Learning Environment
32 Strategies for Building a Positive Learning EnvironmentEdutopia
 
Scala.js: Next generation front end development in Scala
Scala.js:  Next generation front end development in ScalaScala.js:  Next generation front end development in Scala
Scala.js: Next generation front end development in ScalaOtto Chrons
 
Scala.js for large and complex frontend apps
Scala.js for large and complex frontend appsScala.js for large and complex frontend apps
Scala.js for large and complex frontend appsOtto Chrons
 
プログラミング言語Scala
プログラミング言語Scalaプログラミング言語Scala
プログラミング言語ScalaTanUkkii
 
Rendr入門: サーバサイドで(も)動かす、Backbone.js
Rendr入門: サーバサイドで(も)動かす、Backbone.jsRendr入門: サーバサイドで(も)動かす、Backbone.js
Rendr入門: サーバサイドで(も)動かす、Backbone.jsMasahiko Tachizono
 
CRDT in 15 minutes
CRDT in 15 minutesCRDT in 15 minutes
CRDT in 15 minutesShingo Omura
 
Railsのエラーログとの付き合い方
Railsのエラーログとの付き合い方Railsのエラーログとの付き合い方
Railsのエラーログとの付き合い方Taisuke Kawahara
 
Rails5とAPIモードについての解説
Rails5とAPIモードについての解説Rails5とAPIモードについての解説
Rails5とAPIモードについての解説Fumiya Sakai
 
チームでつくるUIデザイン
チームでつくるUIデザインチームでつくるUIデザイン
チームでつくるUIデザインSadaaki HIRAI
 
WebID and eCommerce
WebID and eCommerceWebID and eCommerce
WebID and eCommerceHenry Story
 
Akka Clusterの耐障害設計
Akka Clusterの耐障害設計Akka Clusterの耐障害設計
Akka Clusterの耐障害設計TanUkkii
 
ReactとImmutable.jsで関数型を体験してみて思ったこと #scripty06
ReactとImmutable.jsで関数型を体験してみて思ったこと #scripty06ReactとImmutable.jsで関数型を体験してみて思ったこと #scripty06
ReactとImmutable.jsで関数型を体験してみて思ったこと #scripty06Yahoo!デベロッパーネットワーク
 
これからのJavaScriptー関数型プログラミングとECMAScript6
これからのJavaScriptー関数型プログラミングとECMAScript6これからのJavaScriptー関数型プログラミングとECMAScript6
これからのJavaScriptー関数型プログラミングとECMAScript6TanUkkii
 

En vedette (20)

React Canvasで作るFlappy Bird
React Canvasで作るFlappy BirdReact Canvasで作るFlappy Bird
React Canvasで作るFlappy Bird
 
ng-japan 2015 TypeScript+AngularJS 1.3
ng-japan 2015 TypeScript+AngularJS 1.3ng-japan 2015 TypeScript+AngularJS 1.3
ng-japan 2015 TypeScript+AngularJS 1.3
 
AngularとOnsen UIで作る最高のHTML5ハイブリッドアプリ
AngularとOnsen UIで作る最高のHTML5ハイブリッドアプリAngularとOnsen UIで作る最高のHTML5ハイブリッドアプリ
AngularとOnsen UIで作る最高のHTML5ハイブリッドアプリ
 
アメブロの大規模システム刷新と それを支えるSpring
アメブロの大規模システム刷新と それを支えるSpringアメブロの大規模システム刷新と それを支えるSpring
アメブロの大規模システム刷新と それを支えるSpring
 
32 Strategies for Building a Positive Learning Environment
32 Strategies for Building a Positive Learning Environment32 Strategies for Building a Positive Learning Environment
32 Strategies for Building a Positive Learning Environment
 
Scala.js
Scala.jsScala.js
Scala.js
 
Scala.js: Next generation front end development in Scala
Scala.js:  Next generation front end development in ScalaScala.js:  Next generation front end development in Scala
Scala.js: Next generation front end development in Scala
 
Scala.js for large and complex frontend apps
Scala.js for large and complex frontend appsScala.js for large and complex frontend apps
Scala.js for large and complex frontend apps
 
プログラミング言語Scala
プログラミング言語Scalaプログラミング言語Scala
プログラミング言語Scala
 
Rendr入門: サーバサイドで(も)動かす、Backbone.js
Rendr入門: サーバサイドで(も)動かす、Backbone.jsRendr入門: サーバサイドで(も)動かす、Backbone.js
Rendr入門: サーバサイドで(も)動かす、Backbone.js
 
CRDT in 15 minutes
CRDT in 15 minutesCRDT in 15 minutes
CRDT in 15 minutes
 
Railsのエラーログとの付き合い方
Railsのエラーログとの付き合い方Railsのエラーログとの付き合い方
Railsのエラーログとの付き合い方
 
minne の API 改善
minne の API 改善minne の API 改善
minne の API 改善
 
Rails5とAPIモードについての解説
Rails5とAPIモードについての解説Rails5とAPIモードについての解説
Rails5とAPIモードについての解説
 
チームでつくるUIデザイン
チームでつくるUIデザインチームでつくるUIデザイン
チームでつくるUIデザイン
 
Deploy to Lobi
Deploy to LobiDeploy to Lobi
Deploy to Lobi
 
WebID and eCommerce
WebID and eCommerceWebID and eCommerce
WebID and eCommerce
 
Akka Clusterの耐障害設計
Akka Clusterの耐障害設計Akka Clusterの耐障害設計
Akka Clusterの耐障害設計
 
ReactとImmutable.jsで関数型を体験してみて思ったこと #scripty06
ReactとImmutable.jsで関数型を体験してみて思ったこと #scripty06ReactとImmutable.jsで関数型を体験してみて思ったこと #scripty06
ReactとImmutable.jsで関数型を体験してみて思ったこと #scripty06
 
これからのJavaScriptー関数型プログラミングとECMAScript6
これからのJavaScriptー関数型プログラミングとECMAScript6これからのJavaScriptー関数型プログラミングとECMAScript6
これからのJavaScriptー関数型プログラミングとECMAScript6
 

Similaire à Isomorphic web development with scala and scala.js

Jjug springセッション
Jjug springセッションJjug springセッション
Jjug springセッションYuichi Hasegawa
 
多分モダンなWebアプリ開発
多分モダンなWebアプリ開発多分モダンなWebアプリ開発
多分モダンなWebアプリ開発tak-nakamura
 
サンプルアプリケーションで学ぶApache Cassandraを使ったJavaアプリケーションの作り方
サンプルアプリケーションで学ぶApache Cassandraを使ったJavaアプリケーションの作り方サンプルアプリケーションで学ぶApache Cassandraを使ったJavaアプリケーションの作り方
サンプルアプリケーションで学ぶApache Cassandraを使ったJavaアプリケーションの作り方Yuki Morishita
 
Javaヂカラ #Java最新動向 -Java 11 の新機能やOracle Code One 2018 発の最新技術トレンドを一気にキャッチアップ-
Javaヂカラ #Java最新動向 -Java 11 の新機能やOracle Code One 2018 発の最新技術トレンドを一気にキャッチアップ-Javaヂカラ #Java最新動向 -Java 11 の新機能やOracle Code One 2018 発の最新技術トレンドを一気にキャッチアップ-
Javaヂカラ #Java最新動向 -Java 11 の新機能やOracle Code One 2018 発の最新技術トレンドを一気にキャッチアップ-PE-BANK
 
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版あります
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版ありますElixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版あります
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版ありますfukuoka.ex
 
Rails初心者レッスン lesson1 3rd edition
Rails初心者レッスン lesson1 3rd editionRails初心者レッスン lesson1 3rd edition
Rails初心者レッスン lesson1 3rd editionGoh Matsumoto
 
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」fukuoka.ex
 
試して学べるクラウド技術! OpenShift
試して学べるクラウド技術! OpenShift試して学べるクラウド技術! OpenShift
試して学べるクラウド技術! OpenShiftEtsuji Nakai
 
Backlogでの Perlのつかいかた
Backlogでの PerlのつかいかたBacklogでの Perlのつかいかた
Backlogでの PerlのつかいかたRyuzo Yamamoto
 
成長を加速する minne の技術基盤戦略
成長を加速する minne の技術基盤戦略成長を加速する minne の技術基盤戦略
成長を加速する minne の技術基盤戦略Hiroshi SHIBATA
 
scala+liftで遊ぼう
scala+liftで遊ぼうscala+liftで遊ぼう
scala+liftで遊ぼうyouku
 
Visual Studio 2012 で実現する HTML5 & マルチ デバイス時代の Web 開発
Visual Studio 2012 で実現する HTML5 & マルチ デバイス時代の Web 開発Visual Studio 2012 で実現する HTML5 & マルチ デバイス時代の Web 開発
Visual Studio 2012 で実現する HTML5 & マルチ デバイス時代の Web 開発Akira Inoue
 
Windows 開発者のための Dev&Ops on AWS
Windows 開発者のための Dev&Ops on AWSWindows 開発者のための Dev&Ops on AWS
Windows 開発者のための Dev&Ops on AWSAmazon Web Services Japan
 
コンテナ環境でJavaイメージを小さくする方法!
コンテナ環境でJavaイメージを小さくする方法!コンテナ環境でJavaイメージを小さくする方法!
コンテナ環境でJavaイメージを小さくする方法!オラクルエンジニア通信
 
LambdaとMobileの美味しいかもしれない関係
LambdaとMobileの美味しいかもしれない関係LambdaとMobileの美味しいかもしれない関係
LambdaとMobileの美味しいかもしれない関係Hiraku Komuro
 
How to Make Own Framework built on OWIN
How to Make Own Framework built on OWINHow to Make Own Framework built on OWIN
How to Make Own Framework built on OWINYoshifumi Kawai
 
Featuring Project Silk & Liike: 楽しい "モダン" Web 開発のちょっとディープなお話
Featuring Project Silk & Liike: 楽しい "モダン" Web 開発のちょっとディープなお話Featuring Project Silk & Liike: 楽しい "モダン" Web 開発のちょっとディープなお話
Featuring Project Silk & Liike: 楽しい "モダン" Web 開発のちょっとディープなお話Akira Inoue
 
Azure Cosmos DB を使った高速分散アプリケーションの設計パターン
Azure Cosmos DB を使った高速分散アプリケーションの設計パターンAzure Cosmos DB を使った高速分散アプリケーションの設計パターン
Azure Cosmos DB を使った高速分散アプリケーションの設計パターンKazuyuki Miyake
 

Similaire à Isomorphic web development with scala and scala.js (20)

Jjug springセッション
Jjug springセッションJjug springセッション
Jjug springセッション
 
多分モダンなWebアプリ開発
多分モダンなWebアプリ開発多分モダンなWebアプリ開発
多分モダンなWebアプリ開発
 
サンプルアプリケーションで学ぶApache Cassandraを使ったJavaアプリケーションの作り方
サンプルアプリケーションで学ぶApache Cassandraを使ったJavaアプリケーションの作り方サンプルアプリケーションで学ぶApache Cassandraを使ったJavaアプリケーションの作り方
サンプルアプリケーションで学ぶApache Cassandraを使ったJavaアプリケーションの作り方
 
Javaヂカラ #Java最新動向 -Java 11 の新機能やOracle Code One 2018 発の最新技術トレンドを一気にキャッチアップ-
Javaヂカラ #Java最新動向 -Java 11 の新機能やOracle Code One 2018 発の最新技術トレンドを一気にキャッチアップ-Javaヂカラ #Java最新動向 -Java 11 の新機能やOracle Code One 2018 発の最新技術トレンドを一気にキャッチアップ-
Javaヂカラ #Java最新動向 -Java 11 の新機能やOracle Code One 2018 発の最新技術トレンドを一気にキャッチアップ-
 
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版あります
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版ありますElixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版あります
Elixir入門「第3回:Phoenix 1.2で高速Webアプリ & REST APIをサクッと書いてみる」【旧版】※新版あります
 
Rails初心者レッスン lesson1 3rd edition
Rails初心者レッスン lesson1 3rd editionRails初心者レッスン lesson1 3rd edition
Rails初心者レッスン lesson1 3rd edition
 
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」
Elixir入門「第3回:Phoenix 1.3で高速webアプリ & REST APIアプリをサクッと書いてみる」
 
試して学べるクラウド技術! OpenShift
試して学べるクラウド技術! OpenShift試して学べるクラウド技術! OpenShift
試して学べるクラウド技術! OpenShift
 
Backlogでの Perlのつかいかた
Backlogでの PerlのつかいかたBacklogでの Perlのつかいかた
Backlogでの Perlのつかいかた
 
成長を加速する minne の技術基盤戦略
成長を加速する minne の技術基盤戦略成長を加速する minne の技術基盤戦略
成長を加速する minne の技術基盤戦略
 
scala+liftで遊ぼう
scala+liftで遊ぼうscala+liftで遊ぼう
scala+liftで遊ぼう
 
HTML5&API総まくり
HTML5&API総まくりHTML5&API総まくり
HTML5&API総まくり
 
Visual Studio 2012 で実現する HTML5 & マルチ デバイス時代の Web 開発
Visual Studio 2012 で実現する HTML5 & マルチ デバイス時代の Web 開発Visual Studio 2012 で実現する HTML5 & マルチ デバイス時代の Web 開発
Visual Studio 2012 で実現する HTML5 & マルチ デバイス時代の Web 開発
 
Windows 開発者のための Dev&Ops on AWS
Windows 開発者のための Dev&Ops on AWSWindows 開発者のための Dev&Ops on AWS
Windows 開発者のための Dev&Ops on AWS
 
Mvc conf session_1_osada
Mvc conf session_1_osadaMvc conf session_1_osada
Mvc conf session_1_osada
 
コンテナ環境でJavaイメージを小さくする方法!
コンテナ環境でJavaイメージを小さくする方法!コンテナ環境でJavaイメージを小さくする方法!
コンテナ環境でJavaイメージを小さくする方法!
 
LambdaとMobileの美味しいかもしれない関係
LambdaとMobileの美味しいかもしれない関係LambdaとMobileの美味しいかもしれない関係
LambdaとMobileの美味しいかもしれない関係
 
How to Make Own Framework built on OWIN
How to Make Own Framework built on OWINHow to Make Own Framework built on OWIN
How to Make Own Framework built on OWIN
 
Featuring Project Silk & Liike: 楽しい "モダン" Web 開発のちょっとディープなお話
Featuring Project Silk & Liike: 楽しい "モダン" Web 開発のちょっとディープなお話Featuring Project Silk & Liike: 楽しい "モダン" Web 開発のちょっとディープなお話
Featuring Project Silk & Liike: 楽しい "モダン" Web 開発のちょっとディープなお話
 
Azure Cosmos DB を使った高速分散アプリケーションの設計パターン
Azure Cosmos DB を使った高速分散アプリケーションの設計パターンAzure Cosmos DB を使った高速分散アプリケーションの設計パターン
Azure Cosmos DB を使った高速分散アプリケーションの設計パターン
 

Plus de TanUkkii

Distributed ID generator in ChatWork
Distributed ID generator in ChatWorkDistributed ID generator in ChatWork
Distributed ID generator in ChatWorkTanUkkii
 
Non-blocking IO to tame distributed systems ー How and why ChatWork uses async...
Non-blocking IO to tame distributed systems ー How and why ChatWork uses async...Non-blocking IO to tame distributed systems ー How and why ChatWork uses async...
Non-blocking IO to tame distributed systems ー How and why ChatWork uses async...TanUkkii
 
Architecture of Falcon, a new chat messaging backend system build on Scala
Architecture of Falcon,  a new chat messaging backend system  build on ScalaArchitecture of Falcon,  a new chat messaging backend system  build on Scala
Architecture of Falcon, a new chat messaging backend system build on ScalaTanUkkii
 
スケールするシステムにおけるエンティティの扱いと 分散ID生成
スケールするシステムにおけるエンティティの扱いと 分散ID生成スケールするシステムにおけるエンティティの扱いと 分散ID生成
スケールするシステムにおけるエンティティの扱いと 分散ID生成TanUkkii
 
すべてのアクター プログラマーが知るべき 単一責務原則とは何か
すべてのアクター プログラマーが知るべき 単一責務原則とは何かすべてのアクター プログラマーが知るべき 単一責務原則とは何か
すべてのアクター プログラマーが知るべき 単一責務原則とは何かTanUkkii
 
ディープニューラルネット入門
ディープニューラルネット入門ディープニューラルネット入門
ディープニューラルネット入門TanUkkii
 
プログラミング言語のパラダイムシフト(ダイジェスト)ーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフト(ダイジェスト)ーScalaから見る関数型と並列性時代の幕開けープログラミング言語のパラダイムシフト(ダイジェスト)ーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフト(ダイジェスト)ーScalaから見る関数型と並列性時代の幕開けーTanUkkii
 
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けープログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けーTanUkkii
 
Scalaによる型安全なエラーハンドリング
Scalaによる型安全なエラーハンドリングScalaによる型安全なエラーハンドリング
Scalaによる型安全なエラーハンドリングTanUkkii
 

Plus de TanUkkii (12)

Distributed ID generator in ChatWork
Distributed ID generator in ChatWorkDistributed ID generator in ChatWork
Distributed ID generator in ChatWork
 
Non-blocking IO to tame distributed systems ー How and why ChatWork uses async...
Non-blocking IO to tame distributed systems ー How and why ChatWork uses async...Non-blocking IO to tame distributed systems ー How and why ChatWork uses async...
Non-blocking IO to tame distributed systems ー How and why ChatWork uses async...
 
Architecture of Falcon, a new chat messaging backend system build on Scala
Architecture of Falcon,  a new chat messaging backend system  build on ScalaArchitecture of Falcon,  a new chat messaging backend system  build on Scala
Architecture of Falcon, a new chat messaging backend system build on Scala
 
JSON CRDT
JSON CRDTJSON CRDT
JSON CRDT
 
WaveNet
WaveNetWaveNet
WaveNet
 
スケールするシステムにおけるエンティティの扱いと 分散ID生成
スケールするシステムにおけるエンティティの扱いと 分散ID生成スケールするシステムにおけるエンティティの扱いと 分散ID生成
スケールするシステムにおけるエンティティの扱いと 分散ID生成
 
Akka HTTP
Akka HTTPAkka HTTP
Akka HTTP
 
すべてのアクター プログラマーが知るべき 単一責務原則とは何か
すべてのアクター プログラマーが知るべき 単一責務原則とは何かすべてのアクター プログラマーが知るべき 単一責務原則とは何か
すべてのアクター プログラマーが知るべき 単一責務原則とは何か
 
ディープニューラルネット入門
ディープニューラルネット入門ディープニューラルネット入門
ディープニューラルネット入門
 
プログラミング言語のパラダイムシフト(ダイジェスト)ーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフト(ダイジェスト)ーScalaから見る関数型と並列性時代の幕開けープログラミング言語のパラダイムシフト(ダイジェスト)ーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフト(ダイジェスト)ーScalaから見る関数型と並列性時代の幕開けー
 
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けープログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
 
Scalaによる型安全なエラーハンドリング
Scalaによる型安全なエラーハンドリングScalaによる型安全なエラーハンドリング
Scalaによる型安全なエラーハンドリング
 

Isomorphic web development with scala and scala.js

  • 1. Isomorphic Web development with Scala & Scala.js TanUkkii isomorphic tokyo meetup 2015/4/30
  • 2. I am ... • @TanUkkii007 on Twitter • Web frontend engineer • だったけどゲーム開発が辛くてサーバーサイドを Scalaで開発する人に • Scala業務歴4ヶ月
  • 3. Agenda 1. 開発環境を共有する 2. コードを共有する 3. アーキテクチャを共有する クライアントーサーバー間で
  • 4. Motivation • Scala + Akka + SprayでAPIサーバーを開発 • StrongLoopのApi Exprolerみたいなのを作りたい • Scala.jsでisomorphicにつくる! REST/HTTP server build on Akka Actors
  • 5. Why Scala.js? • クライアントーサーバーで同一の開発環境 • クライアントーサーバーでコードの共有 • 片手間クライアント開発
  • 6. 1. Sharing development environment: Building applications with sbt • プロジェクト定義 • Scalaのバージョン • 依存ライブラリ • コンパイルオプション Java/Scalaのビルドツール 設定 タスク name := “your_project_name”
 
 scalaVersion := "2.11.6"
 
 libraryDependencies ++= Seq(
 "com.typesafe.akka" %% “akka-actor" % "2.3.10"
 ) ! scalacOptions in ThisBuild ++= Seq("-feature") build.sbt • 依存ライブラリの解決 • コンパイル • テスト • REPLの起動
  • 7. Multi-project build - client - server - root import sbt._
 import Keys._
 
 object IsomorphicBuild extends Build {
 
 lazy val root = project.in(file(“.")) 
 lazy val server = Project(“server", file(“server"))
 
 lazy val client = Project("client", file(“client”)) ! } project/Build.scala sbtではサブプロジェクトを複数定義できる ↓サーバーもクライアントも サブプロジェクトとして定義 相似のプロジェクト構造ができる→
  • 8. import sbt._
 import Keys._
 import org.scalajs.sbtplugin.ScalaJSPlugin
 import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._
 
 
 object IsomorphicBuild extends Build {
 
 lazy val root = project.in(file(".")).aggregate(server, client)
 
 lazy val server = Project(“server", file(“server"))
 
 
 lazy val client = Project("client", file(“client")).enablePlugins(ScalaJSPlugin) .settings(
 persistLauncher in Compile := true,
 skip in packageJSDependencies := false
 )
 } project/Build.scala Make Scala.js project ! addSbtPlugin(“org.scala-js" % "sbt-scalajs" % "0.6.2") project/plugins.sbt Scala.jsプラグインを追加 clientプロジェクトで Scala.jsプラグインを有効化
  • 9. Make Scala.js project isomorphic ! import sbt._
 import Keys._
 import org.scalajs.sbtplugin.ScalaJSPlugin
 import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._
 
 object IsomorphicBuild extends Build {
 
 lazy val root = project.in(file(".")).aggregate(server, client)
 
 lazy val server = Project(“server", file(“server"))
 
 
 lazy val client = Project("client", file(“client")).dependsOn(server).enablePlugins(ScalaJSPlugin) .settings(
 unmanagedSourceDirectories in Compile += (sourceDirectory in server).value/"main"/"scala"/"jp.isomorphic.example" / “shared", packageJSDependencies in Compile := {
 val base = (packageJSDependencies in Compile).value
 IO.copyFile(base, (baseDirectory in server).value / "src/main/resources/js" / base.getName)
 base
 },
 persistLauncher in Compile := true,
 skip in packageJSDependencies := false
 ).settings(Seq(fastOptJS, fullOptJS) map { packageJSKey =>
 crossTarget in (Compile, packageJSKey) :=
 (baseDirectory in server).value / "src/main/resources/js"
 })
 } project/Build.scala サーバーからクライアントに クラスパスを通す (Scalaコンパイルが可能に) コンパイル対象に サーバー側のソースの一部を追加 (Scala.jsコンパイルが可能に) Scala.jsのコンパイル結果を サーバー側にコピー
  • 10. Using CrossProject to build isomorphic project structure -shared - js - jvm import sbt.Keys._
 import sbt._ import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._
 ! ! object ApplicationBuild extends Build {
 
 lazy val root = project.in(file("."))
 
 
 lazy val sharedProject = crossProject.in(file("."))
 .settings()
 .jvmSettings()
 .jsSettings()
 )
 
 
 lazy val js: Project = sharedProject.js.settings()
 
 
 lazy val jvm: Project = sharedProject.jvm.settings()
 }
 ! ScalaJSPluginの CrossProjectを使えば 簡単にisomorphicな プロジェクト構造を作れる scalajs-spa-tutorialを参照scalajs-cross-compile-example,
  • 11. 2. Sharing codes between Client and Server • Scala.jsで利用可能なライブラリ • シリアライゼーションによるScalaデータ型の通信 • 型安全なAPIの呼び出し • マクロ
  • 12. Available Libraries • DOM • jQuery • React.js • AngularJS www.scala-js.orgにもっと多く載っている JSライブラリの 型付けされたインターフェース • Scalaz • NICTA/rng Scalaライブラリのポート • Scala.Rx • Monifu • autowire • uPickle 最初からクロスコンパイル前提で 作られたライブラリ※Scalaは型だけ提供。実装はJS。 ※本家のクロスコンパイルできない 部分を修正してJSを提供 ※ScalaとJSを提供
  • 13. Pickling (serialization) • クラス階層情報の喪失 Scala.jsの大問題:可逆的なJSONのシリアライズ リフレクションを使わずにコンパイル時に少ないコードで解決しなければならない。 サーバー クライアント JSON {"fruits": [{"color": "yellow"}, {"color": "red"}]} {"points": [{"x": 1, "y": 2}, {"x": 1, "y": 2}]} null [[]] val fruits: List[Fruit] = List(Banana("yellow"), Apple("red")) val p = Point(1,2); val points = List(p, p) val option: Option[Option[Int]] = None 通信 • 参照同一性の喪失 • Optionの扱い Scalaデータ型 Scalaデータ型
  • 14. Cross-compiled pickling libraries きれいな JSON形式 クラス階 層の保持 参照同一 性の保持 Anyの解 決 uPickle ○ 難しいことは忘れて きれいなJSONを吐くことに注力 Optionが配列として表現される Prickle ○ ○ 可逆性を高めるため メタ情報をJSONに保持させている Scala.js Pickling ○ ○ 型の登録処理が事前に必要 サポートがあまりよくない
  • 15. Binary serialization with BooPickle and XHR2 def request(method: String, url: String, body: ArrayBuffer): Future[ByteBuffer] = {
 val promise = Promise[ByteBuffer]
 val xhr = new XMLHttpRequest()
 xhr.onreadystatechange = { (e: Event) =>
 if (xhr.readyState == 4) { if (xhr.status >= 200 && xhr.status < 300) {
 val byteBuffer = TypedArrayBuffer.wrap(xhr.response.asInstanceOf[ArrayBuffer])
 promise.success(byteBuffer)
 } else promise.failure(AjaxException(xhr))
 }}
 xhr.open(method, url)
 xhr.responseType = "arraybuffer"
 xhr.setRequestHeader("Content-Type", "application/octet-stream")
 xhr.setRequestHeader("Accept", "application/octet-stream")
 xhr.send(body)
 promise.future
 } val byteBuffer = Pickle.intoBytes(SampleRequest("Hello"))
 request(method, url, byteBuffer.arrayBuffer()).map(Unpickle[SampleResponse].fromBytes(_)) • JSONではなく、バイナリにシリアライズ • XHR level2のバイナリサポートを利用 • JSのArrayBufferを使う • メディアタイプは application/octet-stream • クラス階層、参照の同一性も復元可能
  • 16. Client-server communication with Autowire object AutowireClient extends autowire.Client[String, Reader, Writer]{
 override def doCall(req: Request): Future[String]
 } trait MyApi {
 def sampleRequest(id: Int): SampleResponse
 } object MyApiImpl extends MyApi{
 def sampleRequest(id: Int) = SampleResponse(id)
 } AutowireClient[MyApi].sampleRequest(1).call().map(println) path("api" / Segments){ s =>
 extract(_.request.entity.asString) { e =>
 complete {
 AutowireServer.route[MyApi](MyApiImpl)(
 autowire.Core.Request(s, upickle.read[Map[String, String]](e)))
 }}} object AutowireServer extends autowire.Server[String, Reader, Writer]{
 val routes = AutowireServer.route[MyApi](MyApiImpl)
 } Autowire マクロマジック!! AutowireはAjaxにおける クライアントーサーバー間のAPIの煩雑さを RPCスタイルのメソッド呼び出しで 解決するライブラリ • なぜかRPCは自動で解決される • API呼び出しにおける間違いは コンパイル時に発見される 1. sharedでRPCインターフェースを定義 2. serverでRPCインターフェースを実装 3. serverでルーティング部分関数をマクロにより生成 4. serverでルーティング部分関数を呼び出してレスポンスを返す 5. clientでAjaxの通信の仕方を実装 6. clientでRPC関数を呼び出す
  • 17. Macro performing macro expansion AutowireServer.route[jp.isomorphic.example.MyApi] (<empty> match {
 case autowire.Core.Request(Seq("jp", "isomorphic", "example", "MyApi", "sampleRequest"), (args$macro$1 @ _)) => autowire.Internal.doValidate({
 <synthetic> <artifact> val x$2 = autowire.Internal.read[String, Int](args$macro$1, scala.util.Left(autowire.Error.Param.Missing("id")), "id", ((x$1) => AutowireServer.read[Int](x$1)));
 Nil.$colon$colon(x$2)
 }) match {
 case scala.$colon$colon((id @ (_: Int @unchecked)), Nil) => scala.concurrent.Future.successful(MyApiImpl.sampleRequest(id)).map(((x$3) => AutowireServer.write(x$3)))
 case _ => $qmark$qmark$qmark
 }
 }: autowire.Core.Router[String]) 種明かし:-Ymacro-debug-liteコンパイルオプションでマクロを展開する package jp.isomorphic.example trait MyApi {
 def sampleRequest(id: Int): SampleResponse
 } マクロは ←から、関数のシグニチャに対して パターンマッチをかける部分関数 を作っていた ※Scalaのマクロは抽象構文木を操るすごいやつです
  • 19. Common Practice: Unidirectional Data Flow • Tell, don t ask. • Fire and forget. Flux Scalajs SPA Tutorialがこの共通点からアプローチしている • unidirectional data flow • message passing 複雑さに対抗する手段のコンセプトは同じ
  • 21. trait Actor {
 type Receive = PartialFunction[Any, Unit]
 
 def receive: Receive
 
 def !(message: Any) = {
 receive(message)
 }
 } trait Dispatcher {
 var actors = Set.empty[Actor]
 
 def dispatch(message: Any) = {
 actors.foreach { actor =>
 actor ! message
 }
 }
 
 def register(actor: Actor) = {
 actors = actors + actor
 }
 
 def unregister(actor: Actor) = {
 if (actors.contains(actor)) {
 actors - actor
 }
 }
 } Dispatcherは Actorプログラミングにおける Recipient Listパターン var Dispatcher = { _listeners: [], register: function(callback) { this._listeners.push(callback); return this; }, unregister: function(callback) { var index = this._listeners.indexOf(callback); if (index !== -1) { delete this._listeners[index]; } return this; }, dispatch: function(...args) { this._listeners.forEach(callback => callback.apply(this, args) ); return this; } }; ※Recipient List: メッセージを複数のアクターに拡散 し仕事を分散して処理する際に、拡散先の受信者である アクター参照の一覧を保持しているもの
  • 22. object SampleDispatcher extends Dispatcher
 
 object SampleActorProtocol {
 case class Foo(message: String)
 case class Bar(message: String)
 }
 
 object SampleActor extends Actor {
 import SampleActorProtocol._
 
 SampleDispatcher.register(this)
 
 def receive: Receive = {
 case Foo(message) => println(message)
 case Bar(message) => println(message)
 }
 } ! import SampleActorProtocol._
 SampleDispatcher.dispatch(Foo("Hello")) Dispatcher.register(function(payload) { if (payload.type === "FOO") { console.log(payload.message); } else if (payload.type === "BAR") { console.log(payload.message); } }); ! Dispatcher.dispatch({type: "FOO", message: "Hello"}); ! ! ! ! ! ! ! ! ! ! ! • Dispatcherに関数ではなくActorオブジェクトを登録する • payloadを処理する関数はActorのReceive部分関数に相当 • payloadはメッセージ
  • 23. Conclusion • Scala + Scala.jsでクライアントーサーバーを高度 に統合できる • (ただし他のシステムとのinteropが犠牲になるかも • みんなScala.jsを使おう!!!