Scala.js
A safer way to build robust front-end web applications!
http://www.scala-js.org/
In this blog, we are gonna utilizing a whole lot of features of Scala to build a simple front-end application using Scala.js.
So, let’s get it started-
Step-1: – Creating an sbt project
Create a folder named scala-js-example and inside it create a build.sbt.
build.sbt
lazy val root = project.in(file("."))
.settings(
name := "scala-js-example",
version := "0.0.1",
scalaVersion := "2.13.3")
Now, create a new folder named as a project inside the scala-js-example folder and add these three files: –
build.properties
sbt.version = 1.4.1
plugins.sbt
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.2.0")
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0")
Dependencies.scala
import org.portablescala.sbtplatformdeps.PlatformDepsPlugin.autoImport._
import sbt._
object Dependencies {
private object versions {
lazy val scalaJsDom: String = "1.1.0"
}
object js {
lazy val scalaJsDom = Def.setting("org.scala-js" %%% "scalajs-dom" % versions.scalaJsDom)
}
}
As you can see above, the Scala version for the project is 2.13.3, SBT version is 1.4.1 and to run the SBT I am using JVM-14.
The next step would be to execute sbt clean compile
For now, a basic sbt project has created, the next step would be to edit the build.sbt again.
build.sbt
import Dependencies._
import sbtcrossproject.CrossPlugin.autoImport.{crossProject => sbtCrossProject}
lazy val root = project.in(file("."))
.aggregate(crossProjectJS, crossProjectJVM)
.settings(
name := "scala-js-example",
version := "0.0.1",
scalaVersion := "2.13.4")
lazy val crossProject = sbtCrossProject(JSPlatform, JVMPlatform).in(file("."))
.settings(
version := "0.0.1",
scalaVersion := "2.13.3")
lazy val crossProjectJVM = crossProject.jvm
lazy val crossProjectJS = crossProject.js.settings(
libraryDependencies ++= Seq(js.scalaJsDom.value),
crossTarget in fastOptJS := baseDirectory.value / "src/main/resources/web/scala-js"
)
So, let’s try to understand build.sbt
We have added a cross-project plugin, to create a cross-project, this is done to better organize the code, which means, the code which will be designed to run Js Virtual machine will go inside js/src/main/scala, the code which will be designed to run Java Virtual machine will go inside jvm/src/main/scala and the common code between two of them will go inside the shared/src/main/scala.
For more info on cross-project, please visit: – https://www.scala-js.org/doc/project/cross-build.html
So, the project structure will gonna look like
scala-js-example
+- jvm
| +- src/main/scala
| +- app
| +- Main.scala
+- js
| +- src/main/resources
| +- web
| +- css
| +- main.css
| +- scala-js
| +- index.html
| +- src/main/scala
| +- handler
| +- ContainerEventHandler.scala
| +- WindowEventHandler.scala
| +- css
| +- classes
| +- package.scala
+- shared
| +- src/main/resources
| +- src/main/scala
| +- logger
| +- Logger.scala
+- project
| +- build.properties
| +- Dependencies.scala
| +- plugins.sbt
+- build.sbt
Now, if you notice we have something like this inside build.sbt
crossTarget in fastOptJS := baseDirectory.value / "src/main/resources/web/scala-js"
This piece of block says to generate the resultant Js file inside js/src/main/resources/web/scala-js and from there we would be using this Js file to our HTML code.
The project structure is created now and let’s move towards the code
Step-2: – Writing scala code
jvm
src\main\scala\app\Main.scala
package app
import com.knoldus.logger.Logger
/**
* Main from jvm.
*/
object Main extends App {
val message = "SCALA-JS-EXAMPLE"
Logger.info(message)
}
js
src\main\scala\handler\ContainerEventHandler.scala
package handler
import css.classes._
import com.knoldus.logger.Logger
import org.scalajs.dom._
import scala.scalajs.js.annotation.JSExportTopLevel
/**
* This event handler will handle events generated from `container`.
*
* Note:- `container` is the id assigned to `div` element inside `src\main\resources\web\index.html`.
*/
object ContainerEventHandler {
@JSExportTopLevel("handleContainerButtonClickEvent")
def handleButtonClickEvent(): Unit = {
val bodyClassList = document.querySelector("body").classList
bodyClassList.toggle(LINER_GRADIENT_DESIGN_BOTTOM_LEFT)
bodyClassList.toggle(LINER_GRADIENT_DESIGN_TOP_RIGHT)
Logger.info("Gradient designed changed")
}
}
src\main\scala\handler\WindowEventHandler.scala
package handler
import css.classes._
import com.knoldus.logger.Logger
import org.scalajs.dom._
import scala.scalajs.js.annotation.JSExportTopLevel
/**
* This Event handler will handle events from `window` object.
* Ex:- window.onload = onLoadHandler
*/
object WindowEventHandler {
@JSExportTopLevel("onLoadHandler")
def onLoadHandler(): Unit = {
val webPageLoadedMessage = "Web page loaded successfully."
window.alert(webPageLoadedMessage)
document.querySelector("#container").classList.remove(DISPLAY_NONE)
Logger.info(webPageLoadedMessage)
}
}
src\main\scala\css\classes\package.scala
package css
/**
* This object contains all name of the global css classes present inside
* `src\main\resources\web\css\main.css`.
*/
package object classes {
lazy val DISPLAY_NONE: String = "display-none"
lazy val LINER_GRADIENT_DESIGN_BOTTOM_LEFT: String = "linear-gradient-design-bottom-left"
lazy val LINER_GRADIENT_DESIGN_TOP_RIGHT: String = "linear-gradient-design-top-right"
lazy val COLUMN_FLEX_CONTAINER: String = "column-flex-container"
lazy val FULL_WIDTH_HEIGHT: String = "full-width-height"
}
src\main\resources\web\css\main.css
html {
width: 100%;
height: 100%;
}
body {
overflow:hidden;
}
.linear-gradient-design-bottom-left {
background-image: linear-gradient(to bottom left, #66ffff, #ff66ff);
}
.linear-gradient-design-top-right {
background-image: linear-gradient(to top right, #66ffff, #ff66ff);
}
.display-none {
display:none
}
.column-flex-container {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.full-width-height {
width: 100%;
height: 100%;
}
#container > button {
margin: auto;
font-size: xx-large;
background-color: white;
}
src\main\resources\web\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>scala-js-example</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body class="linear-gradient-design-bottom-left">
<div id="container" class="display-none column-flex-container full-width-height">
<h1>Welcome to <b>scala-js</b></h1>
<button onclick="handleContainerButtonClickEvent()">Click Me</button>
</div>
http://scala-js/scala-js-example-fastopt.js
<script>
window.onload = onLoadHandler
</script>
</body>
</html>
shared
src\main\scala\logger\Logger.scala
package logger
/**
* Sample Logger to log output in browser for scala-js and on console for scala-jvm.
*/
object Logger {
def info(messages: Any*): Unit = println(messages.map(_.toString).mkString(","))
}
Now we are all set and let’s go ahead and run this
Step-2: – Executing the project
jvm
Steps to execute
sbt "project crossProjectJVM" run
Output
SCALA-JS-EXAMPLE
js
Steps to execute
sbt fastOptJS
After this, you can see that the scala-js folder inside js/src/main/resources/web will contain a Js file named scala-js-example-fastopt.js
Now let just go to your index.html file inside js/src/main/resources/web and update the src attribute of the script tag to point to the generated Js file
Like for example, as mentioned above inside index.html
http://scala-js/scala-js-example-fastopt.js
Open index.html file with a web browser and you can see that
- A alert box at start-up
- Background color change on every button click
- Open the Js console inside browser inspect and there you can see the output of
println
.
Hope this blog helps you to understand the basic concepts of Scala.js.

Nice intro, I think scala will put back other front-end frameworks. Too good!