Intro to Scala.js
Marius Soutier
Freelance Software Engineer
@mariussoutier
Write JavaScript in Scala
What is Scala.js?
Scala.js compiles Scala to JavaScript
object HelloUg extends JSApp {

override def main(): Unit = {

// FP for the win

var res, i = 0

val values = js.Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

while (i < values.length) {

res = res + values(i)

i += 1

}

println(res)

}

}
$c_Lug_HelloUg$.prototype.main__V = (function() {

var res = 0;

var i = 0;

var values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

while ((i < $uI(values["length"]))) {

res = ((res + $uI(values[i])) | 0);

i = ((1 + i) | 0)

};

var x = res;

var this$2 = $m_s_Console$();

var this$3 = this$2.outVar$2;

$as_Ljava_io_PrintStream(this$3.tl$1.get__O()).println__O__V(x)

});
$e["ug"] = ($e["ug"] || {});
$e["ug"]["HelloUg"] = $m_Lug_HelloUg$;
But Why?
• Web development is moving to client-side apps,

JavaScript is the browser’s only language
• JavaScript is beyond broken
• Maintaining a large JavaScript project can be difficult
• Keeping up with JavaScript’s ecosystem is nigh-
impossible

(See JavaScript Drinking Game)
Obligatory JavaScript: The Good Parts
Reference
But that’s enough JavaScript bashing for today
Scala.js to the Rescue
• We all love Scala
• Type-safety, packages, traits, …
• Rich standard library
• Share code between backend and front-end
• Full editor support (same file suffix)
• Access to all JS libs and a lot of the Scala ecosystem
Scala.js’ Future
• Size of compiled JavaScript
• Compile Speed
• JS libraries must be wrapped
• Scala is developed with JVM in mind, some things
just don't work in JS land, some JDK parts missing
• Front-end developers might not want to learn Scala
(slackers!)
Drawbacks
• Scala libraries available for Scala.js
• Scalatags, ScalaCSS
• Shapeless, Scalaz, Cats, Monocle
• Sharing code inside a project via common cross-compiled

sbt sub-project
• Data exchange via JSON
• upickle
• JavaScript doesn't necessarily understand your JSON, 

e.g. Longs aren't that long in JavaScript
Sharing Code & Data
How Does It Work?
.scala
.class
.sjsir
run/test
~fastOptJS
fullOptJS
Google
Closure
-opt.js
-fastopt.js
Rhino / Node.js
Rhino / PhantomJS
No DOM
DOM
-jsdeps.min.js
jsDependencies ++= Seq(

"org.webjars" % "jquery" % "1.10.2" / "jquery.js",

"org.webjars" % "angularjs" % "1.4.8" / "angular.js" dependsOn "jquery.js"

)
Targeting JavaScript
Scala / JVM JavaScript
Byte, Short, Int, Float, Double Number
Unit Undefined
Char, Long Scala classes
Custom Scala classes JavaScript class with @JSExport
NullPointerException,
ArrayIndexOutOfBoundsException,
ClassCastException, StackOverflowError, …
Undefined
Reflection -
String.split JS RegEx is different
Pattern Matching on Byte, Short, Int, Float, Double Determined by runtime value, not type
JavaScript Native Types
JS-native Type Maps to Example JS
js.FunctionN scala.FunctioN val fn: js.Function1[Int, Int] =
(i: Int) => i * 2
var fn = function(i)
{

return i * 2;

};
js.Array[T] Seq[T] js.Array(1, 2, 3) [1, 2, 3]
js.Dictionary[T] mutable.Map[String, T] js.Dictionary("a" -> 1, "b" -> 2) {"a": 1, "b": 2}
js.UndefOr[T] Option[T]
val some: js.UndefOr[Int] = 1

val none: js.UndefOr[Int] =
js.undefined

Option(1).orUndefined
1

undefined


1
js.TupleN TupleN js.Tuple2(42, “Scala UG") [42, "Scala UG"]
Dynamic JS
When interacting with JavaScript libraries, its dynamic

nature can’t always be ignored
val guest = js.Dynamic.literal(

name = "Scala User Group"

)
But we can give it a nicer interface
trait Guest extends js.Object {

val name: String = js.native

}



object Guest {

def apply(name: String): Guest =

js.Dynamic.literal(name = name).asInstanceOf[Guest]

}
import js.Dynamic.{global => g}

g.console.log(guest)



val dom = g.document

val p = dom.createElement("p")

p.innerHTML = s"Hi ${guest.name}!"

dom.getElementById("main").appendChild(p)
Wrapping JS Libs (1)
Read documentation and infer types
Wrapping JS Libs (2)
import scala.scalajs.js

import scala.scalajs.js.annotation.JSName



object Numeral {

def apply(n: Double): Numeral = new Numeral(n)

def apply(): Numeral = new Numeral(0)

}



@JSName("numeral")

@js.native

class Numeral(n: Double) extends js.Object {

def format(formatString: String): String = js.native

def unformat(formatString: String): Double = js.native



def add(number: Double): Double = js.native

def subtract(number: Double): Double = js.native

def multiply(number: Double): Double = js.native

def divide(number: Double): Double = js.native



def value(): Double = js.native



def difference(number: Double): Double = js.native

}
jsDependencies ++= Seq(

"org.webjars" % "numeral-js" % "1.5.3-1" / "numeral.js" minified "min/numeral.min.js"

)
Numeral(totalValue).format("0,0.00")
Manipulating the DOM
libraryDependencies ++= Seq(

"org.scala-js" %%% "scalajs-dom" % "0.8.2"

)
import org.scalajs.dom._

val main = document.getElementById("main")

val p = document.createElement("p")

val text = document.createTextNode("Hi Scala User Group!")

p.appendChild(text)

main.appendChild(p)
AJAX
import org.scalajs.dom.ext.Ajax
import scala.scalajs.concurrent.JSExecutionContext.Implicits.queue


val eventualUsers =

Ajax

.get(url = "/users/")

.map { xmlHttp =>

xmlHttp.status match {

case 200 =>

import upickle.default._

read[Seq[User]](xmlHttp.responseText)

case other =>

Seq.empty[User]

}

}
• Export classes to JS for use from other JS code
• Can even publish as NPM module
Using Scala.js from JS
@JSExport

case class ExportedUser(

@(JSExport@field) name: String,

@(JSExport@field) email: String

)
@JSExport

@ScalaJSDefined

class Foo extends js.Object {

val x: Int = 4

def bar(x: Int): Int = x + 1

}
Questions?

Intro to Scala.js - Scala UG Cologne

  • 1.
    Intro to Scala.js MariusSoutier Freelance Software Engineer @mariussoutier Write JavaScript in Scala
  • 2.
    What is Scala.js? Scala.jscompiles Scala to JavaScript object HelloUg extends JSApp {
 override def main(): Unit = {
 // FP for the win
 var res, i = 0
 val values = js.Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 while (i < values.length) {
 res = res + values(i)
 i += 1
 }
 println(res)
 }
 } $c_Lug_HelloUg$.prototype.main__V = (function() {
 var res = 0;
 var i = 0;
 var values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 while ((i < $uI(values["length"]))) {
 res = ((res + $uI(values[i])) | 0);
 i = ((1 + i) | 0)
 };
 var x = res;
 var this$2 = $m_s_Console$();
 var this$3 = this$2.outVar$2;
 $as_Ljava_io_PrintStream(this$3.tl$1.get__O()).println__O__V(x)
 }); $e["ug"] = ($e["ug"] || {}); $e["ug"]["HelloUg"] = $m_Lug_HelloUg$;
  • 3.
    But Why? • Webdevelopment is moving to client-side apps,
 JavaScript is the browser’s only language • JavaScript is beyond broken • Maintaining a large JavaScript project can be difficult • Keeping up with JavaScript’s ecosystem is nigh- impossible
 (See JavaScript Drinking Game)
  • 4.
    Obligatory JavaScript: TheGood Parts Reference But that’s enough JavaScript bashing for today
  • 5.
    Scala.js to theRescue • We all love Scala • Type-safety, packages, traits, … • Rich standard library • Share code between backend and front-end • Full editor support (same file suffix) • Access to all JS libs and a lot of the Scala ecosystem
  • 6.
  • 7.
    • Size ofcompiled JavaScript • Compile Speed • JS libraries must be wrapped • Scala is developed with JVM in mind, some things just don't work in JS land, some JDK parts missing • Front-end developers might not want to learn Scala (slackers!) Drawbacks
  • 8.
    • Scala librariesavailable for Scala.js • Scalatags, ScalaCSS • Shapeless, Scalaz, Cats, Monocle • Sharing code inside a project via common cross-compiled
 sbt sub-project • Data exchange via JSON • upickle • JavaScript doesn't necessarily understand your JSON, 
 e.g. Longs aren't that long in JavaScript Sharing Code & Data
  • 9.
    How Does ItWork? .scala .class .sjsir run/test ~fastOptJS fullOptJS Google Closure -opt.js -fastopt.js Rhino / Node.js Rhino / PhantomJS No DOM DOM -jsdeps.min.js jsDependencies ++= Seq(
 "org.webjars" % "jquery" % "1.10.2" / "jquery.js",
 "org.webjars" % "angularjs" % "1.4.8" / "angular.js" dependsOn "jquery.js"
 )
  • 10.
    Targeting JavaScript Scala /JVM JavaScript Byte, Short, Int, Float, Double Number Unit Undefined Char, Long Scala classes Custom Scala classes JavaScript class with @JSExport NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException, StackOverflowError, … Undefined Reflection - String.split JS RegEx is different Pattern Matching on Byte, Short, Int, Float, Double Determined by runtime value, not type
  • 11.
    JavaScript Native Types JS-nativeType Maps to Example JS js.FunctionN scala.FunctioN val fn: js.Function1[Int, Int] = (i: Int) => i * 2 var fn = function(i) {
 return i * 2;
 }; js.Array[T] Seq[T] js.Array(1, 2, 3) [1, 2, 3] js.Dictionary[T] mutable.Map[String, T] js.Dictionary("a" -> 1, "b" -> 2) {"a": 1, "b": 2} js.UndefOr[T] Option[T] val some: js.UndefOr[Int] = 1
 val none: js.UndefOr[Int] = js.undefined
 Option(1).orUndefined 1
 undefined 
 1 js.TupleN TupleN js.Tuple2(42, “Scala UG") [42, "Scala UG"]
  • 12.
    Dynamic JS When interactingwith JavaScript libraries, its dynamic
 nature can’t always be ignored val guest = js.Dynamic.literal(
 name = "Scala User Group"
 ) But we can give it a nicer interface trait Guest extends js.Object {
 val name: String = js.native
 }
 
 object Guest {
 def apply(name: String): Guest =
 js.Dynamic.literal(name = name).asInstanceOf[Guest]
 } import js.Dynamic.{global => g}
 g.console.log(guest)
 
 val dom = g.document
 val p = dom.createElement("p")
 p.innerHTML = s"Hi ${guest.name}!"
 dom.getElementById("main").appendChild(p)
  • 13.
    Wrapping JS Libs(1) Read documentation and infer types
  • 14.
    Wrapping JS Libs(2) import scala.scalajs.js
 import scala.scalajs.js.annotation.JSName
 
 object Numeral {
 def apply(n: Double): Numeral = new Numeral(n)
 def apply(): Numeral = new Numeral(0)
 }
 
 @JSName("numeral")
 @js.native
 class Numeral(n: Double) extends js.Object {
 def format(formatString: String): String = js.native
 def unformat(formatString: String): Double = js.native
 
 def add(number: Double): Double = js.native
 def subtract(number: Double): Double = js.native
 def multiply(number: Double): Double = js.native
 def divide(number: Double): Double = js.native
 
 def value(): Double = js.native
 
 def difference(number: Double): Double = js.native
 } jsDependencies ++= Seq(
 "org.webjars" % "numeral-js" % "1.5.3-1" / "numeral.js" minified "min/numeral.min.js"
 ) Numeral(totalValue).format("0,0.00")
  • 15.
    Manipulating the DOM libraryDependencies++= Seq(
 "org.scala-js" %%% "scalajs-dom" % "0.8.2"
 ) import org.scalajs.dom._
 val main = document.getElementById("main")
 val p = document.createElement("p")
 val text = document.createTextNode("Hi Scala User Group!")
 p.appendChild(text)
 main.appendChild(p)
  • 16.
    AJAX import org.scalajs.dom.ext.Ajax import scala.scalajs.concurrent.JSExecutionContext.Implicits.queue 
 valeventualUsers =
 Ajax
 .get(url = "/users/")
 .map { xmlHttp =>
 xmlHttp.status match {
 case 200 =>
 import upickle.default._
 read[Seq[User]](xmlHttp.responseText)
 case other =>
 Seq.empty[User]
 }
 }
  • 17.
    • Export classesto JS for use from other JS code • Can even publish as NPM module Using Scala.js from JS @JSExport
 case class ExportedUser(
 @(JSExport@field) name: String,
 @(JSExport@field) email: String
 ) @JSExport
 @ScalaJSDefined
 class Foo extends js.Object {
 val x: Int = 4
 def bar(x: Int): Int = x + 1
 }
  • 18.