ScalaJS Getting Started
npm create vite@4.1.0
✔ Project name: … myapp
✔ Select a framework: > Vanilla
✔ Select a variant: > JavaScript
Scaffolding project in /.../myapp...
Done. Now run:
cd myapp
npm install
npm run dev
In the subdirectory myapp/project
, we add two files: build.properties
and plugins.sbt
Create build.properties and plugins files mkdir project
touch project/build.properties
touch project/plugins.sbt
addSbtPlugin( "org.scala-js" % "sbt-scalajs" % "1.16.0" )
import org . scalajs . linker . interface . ModuleSplitStyle
lazy val myapp = project
.in(file( "." ))
.enablePlugins( ScalaJSPlugin )
.settings(
scalaVersion := "3.3.3" ,
scalaJSUseMainModuleInitializer := true ,
scalaJSLinkerConfig ~= {
_.withModuleKind( ModuleKind . ESModule )
.withModuleSplitStyle(
ModuleSplitStyle . SmallModulesFor ( List ( "myapp" ))
)
},
libraryDependencies ++= Seq (
"org.scala-js" %%% "scalajs-dom" % "2.4.0" ,
)
)
Create src/main/scala/myapp/App.scala
file:
mkdir -p src/main/scala/myapp && touch $_ /App.scala
package myapp
import scala . scalajs . js
import scala . scalajs . js . annotation . *
import org . scalajs . dom
// import javascriptLogo from "/javascript.svg"
@ js.native @ JSImport ( "/javascript.svg" , JSImport . Default )
val javascriptLogo : String = js.native
@ main
def MyApp () : Unit =
dom.document.querySelector( "#app" ).innerHTML = s """
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" target="_blank">
<img src=" $javascriptLogo " class="logo vanilla" alt="JavaScript logo" />
</a>
<h1>Hello Scala.js!</h1>
<div class="card">
<button id="counter" type="button"></button>
</div>
<p class="read-the-docs">
Click on the Vite logo to learn more
</p>
</div>
"""
setupCounter(dom.document.getElementById( "counter" ))
end MyApp
def setupCounter ( element : dom. Element ) : Unit =
var counter = 0
def setCounter ( count : Int ) : Unit =
counter = count
element.innerHTML = s "count is $counter "
element.addEventListener( "click" , e => setCounter(counter + 1 ))
setCounter( 0 )
end setupCounter
Compile scala code to javascript and also watch for changes:
$ sbt
[...]
sbg:myapp > ~fastLinkJS
npm pnpm yarn bun
npm install @scala-js/vite-plugin-scalajs@1.0.0
import { defineConfig } from "vite" ;
import scalaJSPlugin from "@scala-js/vite-plugin-scalajs" ;
export default defineConfig ({
plugins: [ scalaJSPlugin ()],
});
Update main.js
file as follow:
import "./style.css" ;
import "scalajs:main.js" ;
Now, start the dev server:
Visit: http://localhost:5173
npm run build
npm run preview
Your project structure should look like this:
You can run the following command to create a new project using the template:
$ sbt new scala-js/vite.g8
Source code on github: https://github.com/scala-js/vite.g8
Update the build.sbt
file to add laminar
dependency:
import org . scalajs . linker . interface . ModuleSplitStyle
lazy val myapp = project
.in(file( "." ))
.enablePlugins( ScalaJSPlugin )
.settings(
scalaVersion := "3.3.3" ,
scalaJSUseMainModuleInitializer := true ,
scalaJSLinkerConfig ~= {
_.withModuleKind( ModuleKind . ESModule )
.withModuleSplitStyle(
ModuleSplitStyle . SmallModulesFor ( List ( "myapp" ))
)
},
libraryDependencies ++= Seq (
"org.scala-js" %%% "scalajs-dom" % "2.4.0" ,
"com.raquo" %%% "laminar" % "16.0.0"
)
)
Then, update our App.scala
file to use Laminar:
package myapp
import org . scalajs . dom
import com . raquo . laminar . api . L .{ * , given }
@ main
def MyApp () : Unit =
lazy val root = dom.document.querySelector( "#app" )
renderOnDomContentLoaded(root, div( "Hello world" ))
Run concurrently $ sbt "~fastLinkJS"
and $ npm run dev
to see the changes.
Update the build.sbt
file to add scalajs-react
dependency:
import org . scalajs . linker . interface . ModuleSplitStyle
lazy val myapp = project
.in(file( "." ))
.enablePlugins( ScalaJSPlugin )
.settings(
scalaVersion := "3.3.3" ,
scalaJSUseMainModuleInitializer := true ,
scalaJSLinkerConfig ~= {
_.withModuleKind( ModuleKind . ESModule )
.withModuleSplitStyle(
ModuleSplitStyle . SmallModulesFor ( List ( "myapp" ))
)
},
libraryDependencies ++= Seq (
"org.scala-js" %%% "scalajs-dom" % "2.4.0" ,
"com.github.japgolly.scalajs-react" %%% "core" % "2.1.1"
)
)
npm pnpm yarn bun
npm install react@17.0.2 react-dom@17.0.2
Update our App.scala
file to use ScalaJS-React:
package myapp
import japgolly . scalajs . react . _
import japgolly . scalajs . react . vdom . html_<^ . _
@ main
def MyApp () : Unit =
val root = dom.document.querySelector( "#app" )
val HelloWorld = ScalaComponent
.builder[ Unit ]
.renderStatic( < .div( "Hello world" ))
.build
HelloWorld ().renderIntoDOM(root)
Run concurrently $ sbt "~fastLinkJS"
and $ npm run dev
to see the changes.
npm pnpm yarn bun
npm install tailwindcss postcss autoprefixer
Initialize Tailwindcss config $ npx tailwindcss init -p
Update style.css
file:
@tailwind base;
@tailwind components;
@tailwind utilities;
Update tailwind.config.js
file:
/** @type {import('tailwindcss').Config} */
export default {
content: [ "./index.html" , "./src/**/*.scala" ],
theme: {
extend: {},
},
plugins: [],
};
Update App.scala
file:
package myapp
import org . scalajs . dom
import com . raquo . laminar . api . L .{ * , given }
@ main
def MyApp () : Unit =
lazy val root = dom.document.querySelector( "#app" )
renderOnDomContentLoaded(root, div( "Hello world" , cls := "text-red-600" ))
package myapp
import org . scalajs . dom
import japgolly . scalajs . react . _
import japgolly . scalajs . react . vdom . html_<^ . _
@ main
def MyApp () : Unit =
val root = dom.document.querySelector( "#app" )
val HelloWorld = ScalaComponent
.builder[ Unit ]
.renderStatic( < .div( "Hello world" , ^.cls := "text-red-600" ))
.build
HelloWorld ().renderIntoDOM(root)