Skip to main content

Scala.js: first impressions

·3 mins

I recently got curious about Scala.js and decided to give it a try. Here are a few personal considerations about my experience so far.

Tip: Count those ‘%’ in your build.sbt #

Scala.js dependencies should be defined using three % (unlike Scala’s, which use either one or two). As trivial as it may sound, it caused me to spend a good half hour trying to figure out why my tests were not being executed…

libraryDependencies ++= Seq(
  "org.scala-js" %%% "scalajs-dom" % "0.8.0",
  "com.lihaoyi"  %%% "utest" % "0.3.1"
)

Tooling #

I’ve been using Clojurescript for the last few months and as such I’ve been really spoiled by lein-figwheel: every time you save your code, figwheel automatically compiles it and sends it to the browser. This is incredibly better than having to switch window and manually refresh the page every time you save a file!

Q: Is there such a plugin for sbt?

A: Yes, we have Li Haoyi’s amazing workbench! workbench works remarkably like figwheel: it spins a local server to host your code and any time you save a file, your changes are automatically shipped to the browser. To see your code, visit index-dev.html (change index-dev.html to index-opt.html if you are compiling your code in FullOpt mode).

Testing #

Testing is made possible by Li Haoyi’s utest: its syntax is remarkably similar to the most common Scala testing libraries so I will not spend time discussing it. The website provides instructions on how to use it.

Code optimization #

Scala.js lets you choose between Fast and Full optimization: the first one is intended mostly for development mode (it takes a short time to compile and only applies some optimizations), while the second one is meant for production and will optimize your code using Google Closure Compiler in its Advanced Optimization mode.

In SBT, you can run ~fastOptJS to get fast optimization or ~fullOptJS to get full optimization.

Show me the code! #

In order to get a good feeling on Scala.js, I decided to implement Conway’s Game of Life. In general, it really feels like developing Scala, except for a few gotchas here and there (the @JSExport annotation, for example)… Here’s an excerpt:

@JSExport
def main(canvas: html.Canvas): Unit = {
  val ctx = canvas.getContext("2d").asInstanceOf[dom.CanvasRenderingContext2D]
  val cellSize = 30

  canvas.width = BoardSize * cellSize
  canvas.height = BoardSize * cellSize

  var seed = generateBoard
  var generation = 0

  ctx.fillStyle = "white"
  ctx.fillRect(0, 0, cellSize * BoardSize, cellSize * BoardSize)

  def run = {
    seed.map { cell =>
      val x = cell.x * cellSize
      val y = cell.y * cellSize
      val style = if (cell.alive) "blue" else "white"

      ctx.fillStyle = style
      ctx.fillRect(x, y, cellSize, cellSize)
    }

    ctx.font = "20px Georgia"
    ctx.fillStyle = "darkred"
    ctx.fillText(generation.toString, 0, cellSize / 2)

    seed = tick(seed)
    generation = generation + 1
  }

  dom.setInterval(() => run, 500)
}

The complete source code is available at gameoflife-scalajs.

Next steps #

  • Try out scalatags;
  • Learn how to manage state;
  • Look at libraries that provide integration with React.js.