Getting Started with Scala.js and Vite
In this first tutorial, we learn how to get started with Scala.js and Vite. We use Vite to provide live-reloading of the Scala.js application in the browser for development. We also configure it to build a minimal bundle for production.
Going through this tutorial will make sure you understand the basic building blocks. If you prefer to skip this step and directly write Scala.js code, you may jump to Getting Started with Scala.js and Laminar.
If you prefer to look at the end result for this tutorial directly, checkout the scalajs-vite-end-state branch instead of creating everything from scratch.
Make sure to install the prerequisites before continuing further.
We bootstrap our setup using the vanilla Vite template. Navigate to a directory where you store projects, and run the command
Choose a project name (we choose
Our output gives:
As instructed, we follow up with
Exploring the template
In the generated folder, we find the following relevant files:
index.html: the main web page; it contains a
counter.js: it implements a counter functionality for a button.
package.json: the config file for
Remarkably, there is no
vite.config.js file, which would be the configuration for Vite itself.
Vite gives a decent experience out of the box, without any configuration.
One of the main selling points of Vite is its ability to automatically refresh the browser upon file changes.
Open the file
main.js and change the content of the
Observe that the page automatically and instantaneously refreshes to show the changes.
We use sbt as a build tool for Scala and Scala.js. We set it up as follows.
In the subdirectory
livechart/project/, we add two files:
project/build.properties: set the version of sbt
project/plugins.sbt: declare sbt plugins; in this case, only sbt-scalajs
At the root of our
livechart/ project, we add one file:
build.sbt: the main sbt build
Finally, we write the following content in the file
Note that the above is not idiomatic Scala, but rather a direct translation of the Vite template code into Scala.js. We will see in the next tutorial how to use Laminar to write it more idiomatically.
The definition of
which is actually a shorthand for
Many bundlers, Vite included, treat
imports with asset files such as
.svg as pseudo-modules whose
default import is the file path to the corresponding asset in the processed bundle.
Further down, we use it as the value for the
src attribute an
Read more about this mechanism in the Vite documentation on static asset handling.
The translation in Scala.js reads as
@js.native annotation tells Scala.js that
default import from the
Since it represents a file path, we declare
= js.native is a Scala.js idiosyncrasy: we need a concrete value to satisfy the Scala typechecker.
In an ideal world, it would not be required.
We can now build the Scala.js project by opening a new console, and entering sbt:
fastLinkJS task produces the
.js outputs from the Scala.js command.
~ prefix instructs sbt to re-run that task every time a source file changes.
We use the
@scala-js/vite-plugin-scalajs plugin to link Vite and Scala.js with minimal configuration.
We install it in the dev-dependencies with:
and instruct Vite to use it with the following configuration in a new file
Finally, open the file
main.js, remove almost everything to leave only the following two lines:
import a URI starting with
vite-plugin-scalajs resolves it to point to the output directory of Scala.js’
You may have to stop and restart the
npm run dev process, so that Vite picks up the newly created configuration file.
Vite will refresh the browser with our updated “Hello Scala.js!” message.
Live changes with Scala.js
Indeed it is. Let us change the message to
Once we save, we notice that the browser refreshes with the updated message.
There are two things happening behind the scenes:
~fastLinkJStask in sbt notices that a
.scalafile has changed, and therefore rebuilds the
npm run devprocess with Vite notices that a
.jsfile imported from
/main.jshas changed, and triggers a refresh with the updated files.
All these steps are incremental.
When we change a single Scala file, only that one gets recompiled by the Scala incremental compiler.
Then, only the affected small
.js modules produced by
fastLinkJS are regenerated.
Finally, Vite only reloads those small
.js files that were touched.
This ensures that the development cycle remains as short as possible.
fastLinkJS task of sbt and the
npm run dev task of Vite are optimized for incremental development.
For production, we want to perform more optimizations on the Scala.js side and bundle minimized files with
npm run build.
We stop Vite with
Ctrl+C and launch the following instead:
Since the built website uses an ECMAScript module, we need to serve it through an HTTP server to visualize it.
We can use Vite’s
preview mode for that purpose, as we can run it without any additional dependency:
Navigate to the mentioned URL to see your website.
In this tutorial, we saw how to configure Scala.js with Vite from the ground up using
We used sbt as our build tool, but the same effect can be achieved with any other Scala build tool, such as Mill or scala-cli.
Our setup features the following properties:
- Development mode with live reloading: changing Scala source files automatically triggers recompilation and browser refresh.
- Production mode taking the fully optimized output of Scala.js and producing a unique
In our next tutorial about Laminar, we will learn how to write UIs in idiomatic Scala code.