By Alvin Alexander. Last updated: June 15, 2022
This is part one of the most clever Scala/sbt build.sbt files I have ever seen:
val V = new { val Scala = "2.13.4" val ScalaGroup = "2.13" val cats = "2.4.1" val laminar = "0.13.0-M1" val http4s = "0.21.19" val sttp = "2.2.9" val circe = "0.13.0" } scalaVersion := V.Scala val Dependencies = new { private val http4sModules = Seq("dsl", "blaze-client", "blaze-server", "circe").map("http4s-" + _) private val sttpModules = Seq("core", "circe") lazy val frontend = Seq( libraryDependencies ++= sttpModules.map("com.softwaremill.sttp.client" %%% _ % V.sttp) ++ Seq("com.raquo" %%% "laminar" % V.laminar) ) lazy val backend = Seq( libraryDependencies ++= http4sModules.map("org.http4s" %% _ % V.http4s) ++ Seq("com.monovore" %% "decline" % V.decline) ) lazy val shared = Def.settings( libraryDependencies += "io.circe" %%% "circe-generic" % V.circe ) } inThisBuild( Seq( scalafixDependencies += "com.github.liancheng" %% "organize-imports" % V.organiseImports, semanticdbEnabled := true, semanticdbVersion := scalafixSemanticdb.revision, scalafixScalaBinaryVersion := V.ScalaGroup ) ) lazy val root = (project in file(".")).aggregate(frontend, backend, shared.js, shared.jvm) lazy val backend = (project in file("modules/backend")) .dependsOn(shared.jvm) .settings(Dependencies.backend) .settings(Dependencies.tests) .settings(commonBuildSettings) .enablePlugins(JavaAppPackaging) .enablePlugins(DockerPlugin) .settings( Test / fork := true, Universal / mappings += { val appJs = (frontend / Compile / fullOptJS).value.data appJs -> ("lib/prod.js") }, Universal / javaOptions ++= Seq( "--port 8080", "--mode prod" ), Docker / packageName := "laminar-http4s-example" ) lazy val shared = crossProject(JSPlatform, JVMPlatform) .crossType(CrossType.Pure) .in(file("modules/shared")) .jvmSettings(Dependencies.shared) .jsSettings(Dependencies.shared) .jsSettings(commonBuildSettings) .jvmSettings(commonBuildSettings) lazy val fastOptCompileCopy = taskKey[Unit]("") val jsPath = "modules/backend/src/main/resources" fastOptCompileCopy := { val source = (frontend / Compile / fastOptJS).value.data IO.copyFile( source, baseDirectory.value / jsPath / "dev.js" ) } lazy val fullOptCompileCopy = taskKey[Unit]("") fullOptCompileCopy := { val source = (frontend / Compile / fullOptJS).value.data IO.copyFile( source, baseDirectory.value / jsPath / "prod.js" ) } addCommandAlias("runDev", ";fastOptCompileCopy; backend/reStart --mode dev") addCommandAlias("runProd", ";fullOptCompileCopy; backend/reStart --mode prod") val scalafixRules = Seq( "OrganizeImports", "DisableSyntax", "LeakingImplicitClassVal", "ProcedureSyntax", "NoValInForComprehension" ).mkString(" ") val CICommands = Seq( "clean", "backend/compile", "backend/test", "frontend/compile", "frontend/fastOptJS", "frontend/test", "scalafmtCheckAll", s"scalafix --check $scalafixRules" ).mkString(";") addCommandAlias("ci", CICommands)
I didn’t include the entire build.sbt file here because the project doesn’t have a license file, so I don’t know what their license is, but you can see the complete file here at github.com/keynmol/http4s-laminar-stack/blob/master/build.sbt. I really like this because it has some really clever ideas for a large build.sbt file.