1. Introduction
We often use Scala to create the backend of web applications. However, there’s a plugin that allows us to also create the frontend of the applications. In this tutorial, we’re going to introduce the basics of Scala.js, an SBT plugin that can generate highly optimized JavaScript code from Scala.
2. Project Setup
To use the Scala.js plugin, we need to add it to our project/plugins.sbt file:
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.10.1")
After adding the plugin, we need to enable it in the build.sbt:
enablePlugins(ScalaJSPlugin)
To be able to use some of the features that we’ll learn in this article and test them correctly, we need to install Node.js and npm.
Usually, it’s best to install npm packages locally just for a single project. To do that, we need to init a private npm package. We do this by invoking a command in our project folder:
npm init private
3. Eliminating Dead Code
By default, Scala.js eliminates all unused Scala code during generation. To ensure that our code is not eliminated even if it’s not used, we can use the @JSExport annotation. All methods and objects annotated with @JSExport will end up in generated JavaScript code no matter if they’re used or not.
Additionally, we can add a line to our build.sbt to make sure our main() method is called automatically from generated JavaScript. It’ll also make sure that any code referenced in main() will not be eliminated:
scalaJSUseMainModuleInitializer := true
4. Generating JavaScript Code
After configuring the plugin, we can use it to generate JavaScript code from Scala code. We’re going to start with a basic hello world example:
def main(args: Array[String]): Unit = {
println("Hello Scala.js!")
}
Now, let’s use SBT to generate the optimized JavaScript code:
sbt fastLinkJS
It’s worth noting that the generated code is usually much more complex than the Scala code itself. For example, the generated .js file for the above code is around 2,000 lines long, and it’s also quite hard to read. This is because of the fact that, apart from the println(), we also need to generate a lot of common Scala methods like equals() and hashcode() to make sure that our code will work correctly.
5. Integrating With HTML
There are two ways of verifying if our code works correctly. We can either use Node.js runtime to run our JavaScript code or embed the generated code in an HTML website.
For this tutorial, we’re going to go with the latter, we’re going to use simple a HTML website that has our generated .js script linked. Whenever we open our website, it’ll execute the JavaScript code in the main.js file.
Let’s create a simple index.html file in our project root folder:
<html>
<head>
<meta charset="UTF-8">
<title>Introduction to Scala.js</title>
</head>
<body>
<script type="text/javascript" src="./target/scala-2.13/scala-js-tutorial-fastopt/main.js"></script>
</body>
</html>
If we try to open the HTML page with our browser, we should see “*Hello Scala.js!*” printed in the JavaScript console.
6. Generating HTML Content
Scala.js allows us to do more than simply print to the console. We can use it to generate HTML DOM content to modify the look of our website.
To be able to generate HTML content, we need to add the scalajs-dom library to our dependencies:
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.1.0"
Next, let’s add a text paragraph and add it to our HTML document:
def generateTextParagraph(): Unit = {
import org.scalajs.dom.document
val paragraph = document.createElement("p")
paragraph.textContent = "This is a test paragraph."
document.body.appendChild(paragraph)
}
Now, let’s invoke this from our main() method:
def main(args: Array[String]): Unit = {
generateTextParagraph()
}
The above code generates a simple text paragraph. If we now rebuild the JavaScript and refresh the HTML in our browser, we should be able to see the text, “This is a test paragraph“.
7. Testing
To be able to test our code, we need to add one more dependency to project/plugins.sbt:
libraryDependencies += "org.scala-js" %% "scalajs-env-jsdom-nodejs" % "1.0.0"
After adding the dependency, we can modify the jsEnv used to run our code:
jsEnv := new org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv()
We also need to install the jsdom package:
npm install jsdom
When we’re done with all the above steps, we can finally write a test that verifies if our code works correctly:
"Scala Js" should "generate test paragraph with expected text" in {
ScalaJsApp.generateTextParagraph()
val paragraphs = document.querySelectorAll("p")
val paragraphsWithText = paragraphs.count(_.textContent == "This is a test paragraph.")
assert(paragraphsWithText == 1)
}
8. Conclusion
In this tutorial, we’ve learned the basics of Scala.js and how to use it for JavaScript code generation.
More info can be found in the documentation. As always all the code can be found over on GitHub.