TL;DR

Click here for the github project

An example project in July 2021 using sbt, scala 3, scala js, javascript, react hooks, axios and ag-grid. No typescript, but scala being used in the UI and on the server in a GCP environment.

Why?

Having to learn typescript and then implementing reactjs hooks, and so on to create crud type UI’s is fine. But since I have a scala team its actually boring having to train them all up into typescript. So, lets see if we can use scala.js.

As ever, this is a reminder/notes for myself, taken from other parts of the web and my own hacking. Maybe you will find it useful.

I will not be repeating set-up stuff from the Scala js site

Whats the target state

I have decided to stick with React Hooks, axios and scss, which means javascript reducer and context and so on. This is because it gives you component libraries, and I want to use fluentui as I mostly do data intensive single page apps. I will pull in ag-grid to confirm this choice, rather than fluentui but the principle is the same.

Scala for GCP functions, Scala.js for client logic, shared cross compiled code for the occasional shared logic. Javascript, React, sccs for the UI layout stuff.

This means I want an npm project as well as a client scala.js project.

Project structure

The question for me is where to stick the node and scala projects. I want one repo as its just simpler.

project
   client-js          -- client only logic, exporting javascript modules
       src/main/scala   -- scala 3 code
   shared             -- dto's and logic running in both client and server
       src/main/scala   -- scala 3 code
   gcp-functions      -- for serverless functionality
       src/main/scala   -- scala 3 code
   project            -- for sbt build stuff
   reactapp           -- My node project NOT part of the scala project

So in project/client-node I initialise the node project as here.

cd project
npm init react-app ./reactapp
cd reactapp
npm start

Adding the output to node

I am happy to have my client-js monitoring for changes using

sbt ~clientJs/fastLinkJS

This generates javascript in client-js\target\scala-3.0.0\client-js-fastopt. It took me ages to find this, but the incantation to make it generate into the reactapp is:

lazy val clientJs = (project in file("client-js"))
  .enablePlugins(ScalaJSPlugin)
  .settings(
    name := "client-js",
    scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.ESModule) },
    Compile / fastLinkJS / scalaJSLinkerOutputDirectory := new File( baseDirectory.value, "../reactapp/src/scalajs"),
  )

Making my new react app work

So I have npm start working, and it complains about BigInt undefined, which is an eslint issue apparently, so the next incantation in the reactapp dir is to add .eslintrc.json

{
  "env": {
    "es2020": true
  }
}

Having done this, every time I edit the client scala code, it generates the .js files in the reactapp, and npm then regenerates automatically and the page refreshes.

I also have an axios call, so I run the gcp functions locally in intellij, so the react app in Chrome gets refreshed, calls the gcp function, gets data and displays it in the ag-grid. Perfect.

No more typescipt for me.

As mentioned above, the working code is in my github project