Mais conteúdo relacionado Semelhante a How You Convince Your Manager To Adopt Scala.js in Production (20) Mais de BoldRadius Solutions (12) How You Convince Your Manager To Adopt Scala.js in Production2. How to convince your Manager* to adopt scalajs
*Manager: boss | client | CTO | colleague | that clojurescript
guy
• Effective front-end development with the scalajs ecosystem
is viable (and preferable!).
• Here are some tools to enable you to persuade whoever
you need to.
© BoldRadius, 2015 2
3. Who are you?
1. You know and love scala
2. You have to deal with some non-trivial web front-end
3. You don't scalajs? Lets get you going.
4. You do scalajs? Here are some of our opinions
© BoldRadius, 2015 3
4. Who are we?
• Server Side scala/akka developers
• Relatively new to scalajs
• Have experience writing javascript for the front-end
© BoldRadius, 2015 4
5. Path to scalajs: shoulders of giants
Part 1
Like many others, our path to scalajs began with @lihaoyi
• scalatags
form(
div(cls := "form-group")(
label(color := GlobalStyles.textColor)("Cluster Name"),
input(tpe := "text", cls := "form-control", value := S.cluster.name, onChange ==> B.updateClusterName)
)
)
© BoldRadius, 2015 5
6. Path to scalajs: shoulders of giants
Part 2
• scalarx
import rx._
val a = Var(1)
val b = Var(2)
val c = Rx{ a() + b() }
println(c()) // 3
a() = 4
println(c()) // 6
© BoldRadius, 2015 6
8. Javascript, living the dream
• JS devs live and die by their setups*
• No different for scalajs... you need a setup
*setup: tooling, framework, module + dependency mgmt etc.
© BoldRadius, 2015 8
9. Javascript the language
(from lihaoyi.github.io/hands-on-scala-js)
• Its an OK language with some warts
• Not an easy language to work in at scale (refactoring)
© BoldRadius, 2015 9
11. A Javascript "setup"
• Newcomers are often coming from communities in which
full-stack solutions exist.
• JavaScript tooling often consists of small tools, utilities and
libraries that combined builds your code to be used in a
browser.
• Variety is huge
© BoldRadius, 2015 11
12. A Javascript "setup" - Part 1
1. Babel / CoffeeScript / Typescript / PureScript: transpilers
2. Webpack / Browserify : module bundlers
3. Gulp / Grunt : build systems, task runners, orchestrate
processes to work on some files
© BoldRadius, 2015 12
13. A Javascript "setup" - Part 2
1. npm: package manager, downloading packages, resolving
dependencies
2. Mocha / Jasmine / Chai / sinon: Test framework
3. AngularJS / Ember / Backbone / React etc.
© BoldRadius, 2015 13
14. A Scala "setup"
You are already a scala expert and familiar with SBT:
You already have 2/3 of your "setup"
© BoldRadius, 2015 14
16. The Final Third of your Setup
• scalajs-dom, scalatags
• scalarx
• scalajs-react
• autowire
• upickle
• sbt tasks and plugins
© BoldRadius, 2015 16
17. Scalajs really practical guide
https://github.com/katrinsharp/scalajs-rpg
• Anatomy of typical Scalajs app
• Each step contains minimal code and dependencies
• Client assets are independent from server
• Proposed architecture
© BoldRadius, 2015 17
18. 1. MAKE SURE YOU SHARE!
Server/client code sharing - done right
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.4")
//build.sbt
import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._
name := "scalajs-rpg"
lazy val root = project.in(file("."))
.aggregate(jsProject, jvmProject)
lazy val cross = crossProject.in(file("."))
.settings(
name := "scalajs-rpg",
version := "0.1-SNAPSHOT",
scalaVersion := "2.11.7")
.jvmSettings()// JVM-specific settings here
.jsSettings()// JS-specific settings here
© BoldRadius, 2015 18
19. 2. MANIPULATE THIS HTML DOM.
And use your first Scalajs facade
"org.scala-js" %%% "scalajs-dom" % "0.8.0"
val mainEl = dom.document.getElementById("main-el")
//option A
mainEl.innerHTML = s"""
|<div>some stuff</div>
...
""".stripMargin
//option B
val parNode = doc.createElement("p")
...
mainEl.appendChild(parNode)
© BoldRadius, 2015 19
20. 3. GOT DEPENDENCIES? SBT IT!
Use WebJars with sbt-web
addSbtPlugin("com.typesafe.sbt" % "sbt-web" % "1.1.1")
"org.webjars" % "jquery" % "1.11.1" / "jquery.js",
"org.webjars" % "bootstrap" % "3.3.2" / "bootstrap.js" dependsOn "jquery.js"
<!-- dep in index-fastopt.html -->
<link rel="stylesheet" type="text/css"
href="./js/target/web/web-modules/main/webjars/lib/bootstrap/css/bootstrap.min.css">
© BoldRadius, 2015 20
21. 4. SAFE HTML EDUCATION.
With scalatags (scalacss? out-of-scope this time)
"com.lihaoyi" %%% "scalatags" % "0.5.2"
divInMainEl.appendChild(
div(`class` := "col-md-8",
p(`class` := "red", s"From shared and type safe: $res")
).render
)
© BoldRadius, 2015 21
22. 5. DON'T RE-INVENT THE WHEEL!
jQuery, Angular, React, (Ionic, Electron) ...
"com.github.japgolly.scalajs-react" %%% "core" % "0.9.0"
val component = ReactComponentB[Unit]("TodoListComponent")
.initialState(State(List.empty[Todo], ""))
.backend(new Backend(_))
.render((_, S, B) =>
div(
h3("TODO"),
TodoList(S.items),
form(onSubmit ==> B.handleSubmit,
input(onChange ==> B.onChange, value := S.text),
button("Add")
)
)
).buildU
© BoldRadius, 2015 22
23. 6. KEEP YOUR DATA IN SYNC!
"com.lihaoyi" %%% "scalarx" % "0.2.8"
© BoldRadius, 2015 23
24. 7. TREAT YOUR AJAX CALLS WITH SOME SAFETY!
"com.lihaoyi" %%% "autowire" % "0.2.5"
//SHARED
trait Api {
def suggestions(s: String): Seq[Suggestion]
}
//SERVER: segments:
val req = autowire.Core.Request(segments, params)
AutowireServer.route[Api](ApiImpl)(req)
/* CLIENT:
** 1. Call statically typed API
** 2. Implement callback that will be called when your Future completes
** 3. Use Rx to automatically update the client state
*/
AjaxClient[Api].suggestions(text).call().foreach(r => currentSuggestions() = r)
© BoldRadius, 2015 24
25. 8. RELEASE YOUR CLIENT TO THE WILD. RAWWRR....
• IF your assets are hosted somewhere else:
lazy val ReleaseJsCmd = Command.command("releaseJs") {
state =>
"crossJS/fullOptJS" ::
"crossJS/webStage" ::
state
}
...
jsSettings(
pipelineStages := Seq(cssCompress),
commands += ReleaseJsCmd
)
• IF you host assets on your app server - package it
© BoldRadius, 2015 25
26. Now you have a setup, whats next?
The real (fun) work begins...
You need to show your prospect that this works.
© BoldRadius, 2015 26
27. You could...
• Find an internal project that requires a UI
• Something your people care about.
• Interactive visual representation of your best stuff.
• Remove all the friction associated with scalajs
• Own the problems
© BoldRadius, 2015 27
28. Tips
• Console / dashboard all the things.
• Use websockets and make that server push
• Use a dark background
© BoldRadius, 2015 28
29. Our experiment with akka cluster
A distributed application with akka cluster presents an
opportunity:
• What are the states of my clustered actors?
• What are the dependencies between them?
• What hardware are they on?
© BoldRadius, 2015 29
30. cluster-console
• Subscribe to any cluster's events
• Push events to UI with websockets + akka-http streams
• Safe client-server API with autowire + akka-http
• scalajs-react for ui components
• data binding with scalarx
© BoldRadius, 2015 30
32. Highlights
d3 facade
package Layout {
trait Layout extends js.Object {
def force(): ForceLayout = js.native
}
trait ForceLayout extends js.Function {
def size(mysize: js.Array[Double]): ForceLayout = js.native
def charge(number: Double): ForceLayout = js.native
def linkDistance(number: Double): ForceLayout = js.native
def friction(number: Double): ForceLayout = js.native
}
}
val force = d3.layout.force()
.size(List[Double](P.width, P.height).toJsArray)
.charge(-1500)
.linkDistance(1000)
.friction(0.9)
© BoldRadius, 2015 32
33. Highlights
d3 inside scalajs-react
val component = ReactComponentB[Props]("Graph").initialStateP { P =>
val force = ...
val (nodes, links) = // calculate Seq[GraphNode], Seq[GraphLink]
State(nodes, links, force)
}.backend(new Backend(_))
.render{(P, S, B) =>
svgtag(SvgAttrs.width := P.width, SvgAttrs.height := P.height)(
drawLinks(S.links, P.mode),
drawNodes(S.nodes, S.force, P.mode)
)
}.componentWillMount { scope => scope.backend.startfixed()}.build
© BoldRadius, 2015 33
34. Highlights
Back to arguing about more important things:
indexes.flatMap(index =>
indexes.filter(_ > index).map((index, _)))
vs
for {
index <- indexes
eachOther <- indexes.filter(_ > index)
tuple <- Some(index, eachOther)
} yield tuple
© BoldRadius, 2015 34