scalajs-esbuild is a module bundler for Scala.js projects that use npm packages: it bundles the .js files emitted by the Scala.js compiler with their npm dependencies into a single .js file using esbuild.
Compared to scalajs-vite, the historical difference was build performance. Before Vite 8, Vite used two different bundlers internally: esbuild for its dev server and Rollup for production builds. This meant that any workflow that needed a bundle went through Rollup — which is significantly slower than esbuild. This is a problem for certain workflows, like running tests implemented with Scala testing frameworks, which are iterative and thus more sensitive to build performance. scalajs-esbuild uses esbuild for all builds, giving consistent, fast build times across every stage of the Scala.js development workflow.
Since Vite 8, Vite has unified on Rolldown, a Rust-based bundler that replaces both esbuild and Rollup and runs at native speed, on par with esbuild. This largely closes the production-build performance gap that used to distinguish scalajs-esbuild from scalajs-vite.
Plugin should feel quite familiar to the users of well known scalajs-bundler,
with the main difference being that there is no special handling of npmDependencies - they must be provided through
package.json placed within esbuild directory in project's base.
Implementation intentionally exposes only a few settings for configuration - provided scripts should be enough to get started with typical projects,
but any advanced configuration should be provided by modifying said scripts through their sbt settings - esbuildBundleScript and esbuildServeScript.
All sbt tasks that depend on Scala.js stages can be scoped both implicitly and explicitly, for example esbuildBundle will use scalaJSStage or the stage
can be provided within the command - fastLinkJS/esbuildBundle/fullLinkJS/esbuildBundle.
Base plugin is designed for Node or browser libraries, CLIs or standalone scripts - for web apps please use web plugin.
-
Setup project layout, following is a minimal example:
src main scala example Main.scala # Scala.js entry point esbuild package.json # devDependencies must provide esbuild package -
Add plugin to sbt project:
addSbtPlugin("me.ptrdom" % "sbt-scalajs-esbuild" % pluginVersion)
-
Enable plugin in
build.sbt:enablePlugins(ScalaJSEsbuildPlugin) -
Specify that Scala.js project is an application with an entry point:
scalaJSUseMainModuleInitializer := true -
Use sbt tasks to compile Scala.js code and run esbuild:
esbuildBundle- Bundles are produced in
/target/${scalaVersion}/esbuild/main/outdirectory.
- Bundles are produced in
run/testesbuildBundleoutput will be fed tojsEnvInput.
See examples for project templates.
Web plugin is designed for web apps. Because esbuild does not have a full-fledged build-in dev server and HTML entry point transformations like Vite, this plugin attempts to provide good enough stand-ins to enable typical workflows.
-
Setup project layout, following is a minimal example:
src main scala example Main.scala # Scala.js entry point esbuild index.html # esbuild HTML entry point package.json # devDependencies must provide esbuild and parse5 packages -
Add plugin to sbt project:
addSbtPlugin("me.ptrdom" % "sbt-scalajs-esbuild-web" % pluginVersion)
-
Enable plugin in
build.sbt:enablePlugins(ScalaJSEsbuildWebPlugin) -
Specify that Scala.js project is an application with an entry point:
scalaJSUseMainModuleInitializer := true
Such configuration would allow
main.jsbundle to be used in esbuild HTML entry point:<script src="/main.js"></script>
Entry points can be configured with
esbuildBundleHtmlEntryPointssetting. -
Use sbt tasks to compile Scala.js code and run esbuild:
esbuildBundle- In addition to base plugin behavior, web implementation also does HTML entry point transformation - injection Scala.js entry points and CSS files into HTML.
~esbuildServe- Starts dev server on port
3000.- Port can be configured with
esbuildServe / serverPortsetting.
- Port can be configured with
- Watches for updates to Scala.js code and any resources in
esbuilddirectory. - CSS can be hot reloaded, changes to Scala.js code will cause a page reload.
- Starts dev server on port
esbuildServeStart;~esbuildStage;esbuildServeStop- Starting of dev server and watching of sources can be done in separate commands too.
See examples for project templates.
Electron plugin is designed to enable Electron app development with Scala.js. Besides bundling for tests and production builds, the plugin also provides a dev server implementation.
-
Setup project layout, following is a minimal example:
src main scala example Main.scala # main process Preload.scala # preload script Renderer.scala # renderer process esbuild index.html # esbuild HTML entry point package.json # devDependencies must provide esbuild, parse5 and electron packages -
Add plugin to sbt project:
addSbtPlugin("me.ptrdom" % "sbt-scalajs-esbuild-electron" % pluginVersion)
-
Enable plugin in
build.sbt:enablePlugins(ScalaJSEsbuildElectronPlugin) -
Configure Scala.js entry points and Electron process model components:
scalaJSModuleInitializers := Seq( ModuleInitializer .mainMethodWithArgs("example.Main", "main") .withModuleID("main"), ModuleInitializer .mainMethodWithArgs("example.Preload", "main") .withModuleID("preload"), ModuleInitializer .mainMethodWithArgs("example.Renderer", "main") .withModuleID("renderer") ) Compile / esbuildElectronProcessConfiguration := new EsbuildElectronProcessConfiguration( "main", Set("preload"), Set("renderer") )
Such configuration would allow
renderer.jsbundle to be used in esbuild HTML entry point:<script src="./renderer.js"></script>
Entry points can be configured with
esbuildBundleHtmlEntryPointssetting. -
Use web plugin sbt tasks to compile Scala.js code and run esbuild.
See examples for project templates.
-
Add plugin to sbt project:
addSbtPlugin("me.ptrdom" % "sbt-web-scalajs-esbuild" % pluginVersion)
-
Enable plugin in
build.sbt:lazy val server = project .settings( scalaJSProjects := Seq(client), pipelineStages := Seq(scalaJSPipeline) ) .enablePlugins(SbtWebScalaJSEsbuildPlugin) lazy val client = project.enablePlugins(ScalaJSEsbuildPlugin)
See examples for project templates.
Plugins use npm by default, but provided PackageManager abstraction allows configuration of other
package managers.
// for yarn
esbuildPackageManager := new PackageManager {
override def name = "yarn"
override def lockFile = "yarn.lock"
override def installCommand = "install"
}
// for pnpm
esbuildPackageManager := new PackageManager {
override def name = "pnpm"
override def lockFile = "pnpm-lock.yaml"
override def installCommand = "install"
}This software is licensed under the MIT license