intro to scala.js - scala ug cologne

18
Intro to Scala.js Marius Soutier Freelance Software Engineer @mariussoutier Write JavaScript in Scala

Upload: marius-soutier

Post on 18-Mar-2018

643 views

Category:

Technology


6 download

TRANSCRIPT

Page 1: Intro to Scala.js - Scala UG Cologne

Intro to Scala.js

Marius SoutierFreelance Software Engineer

@mariussoutier

Write JavaScript in Scala

Page 2: Intro to Scala.js - Scala UG Cologne

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$;

Page 3: Intro to Scala.js - Scala UG Cologne

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)

Page 4: Intro to Scala.js - Scala UG Cologne

Obligatory JavaScript: The Good Parts Reference

But that’s enough JavaScript bashing for today

Page 5: Intro to Scala.js - Scala UG Cologne

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

Page 6: Intro to Scala.js - Scala UG Cologne

Scala.js’ Future

Page 7: Intro to Scala.js - Scala UG Cologne

• 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

Page 8: Intro to Scala.js - Scala UG Cologne

• 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

Page 9: Intro to Scala.js - Scala UG Cologne

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")

Page 10: Intro to Scala.js - Scala UG Cologne

Targeting JavaScriptScala / 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

Page 11: Intro to Scala.js - Scala UG Cologne

JavaScript Native TypesJS-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.undefinedOption(1).orUndefined

1 undefined

1

js.TupleN TupleN js.Tuple2(42, “Scala UG") [42, "Scala UG"]

Page 12: Intro to Scala.js - Scala UG Cologne

Dynamic JSWhen 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 interfacetrait 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.documentval p = dom.createElement("p") p.innerHTML = s"Hi ${guest.name}!"dom.getElementById("main").appendChild(p)

Page 13: Intro to Scala.js - Scala UG Cologne

Wrapping JS Libs (1)Read documentation and infer types

Page 14: Intro to Scala.js - Scala UG Cologne

Wrapping JS Libs (2)

import scala.scalajs.jsimport scala.scalajs.js.annotation.JSNameobject Numeral { def apply(n: Double): Numeral = new Numeral(n) def apply(): Numeral = new Numeral(0) } @JSName("numeral") @js.nativeclass 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")

Page 15: Intro to Scala.js - Scala UG Cologne

Manipulating the DOMlibraryDependencies ++= 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)

Page 16: Intro to Scala.js - Scala UG Cologne

AJAXimport 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] } }

Page 17: Intro to Scala.js - Scala UG Cologne

• Export classes to JS for use from other JS code

• Can even publish as NPM module

Using Scala.js from JS

@JSExportcase class ExportedUser( @(JSExport@field) name: String, @(JSExport@field) email: String )

@JSExport@ScalaJSDefinedclass Foo extends js.Object { val x: Int = 4 def bar(x: Int): Int = x + 1 }

Page 18: Intro to Scala.js - Scala UG Cologne

Questions?