Skip to content

Instantly share code, notes, and snippets.

@japgolly
Last active October 1, 2019 12:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save japgolly/0d651c34d1e02145e3fb4e4a7d84c7ef to your computer and use it in GitHub Desktop.
Save japgolly/0d651c34d1e02145e3fb4e4a7d84c7ef to your computer and use it in GitHub Desktop.
Scala.JS & SBT
// Assumptions:
// 1. You have one or more Scala.JS modules named jsModule1, jsModule2, ...
// 2. You have a web-serving (or otherwise JVM) module that will serve the JS assets
// The only "webby"/JS plugin I use apart from Scala.JS itself, is xsbt-web-plugin,
// and even that, only on my pre-http4s projects.
// xsbt-web-plugin allows me to quickly stop/start a servlet container from SBT.
// The snippet below is for "webappPostProcess" which is an xsbt-web-plugin task but
// if you aren't using it, you can just create a task with the same content and make
// "package" depend on it.
webappPostProcess := {
implicit val log = streams.value.log
val outputOfJsModule1 = (scalaJSLinkedFile in Compile in jsModule1).value
val outputOfJsModule2 = (scalaJSLinkedFile in Compile in jsModule2).value
// ...
(target: File) => {
// Copy Scala.JS assets
def copyScalaJs(jsf: VirtualJSFile, to: String): Unit =
jsf match {
case f: FileVirtualJSFile => fileSync(f.file, target / to, mandatory = true)
case other => sys.error("Unsupported virtual file type: " + other)
}
copyScalaJs(outputOfJsModule1, targetForJsModule1)
copyScalaJs(outputOfJsModule2, targetForJsModule2)
// ...
// <copy other assets here too>
}
}
// Little helper. Is it still needed in SBT 1.3.x? Who knows?? It was definately helpful in the 0.13.x days.
def fileSync(from: File, to: File, mandatory: Boolean)(implicit log: Logger): Unit =
if (from.exists()) {
log.info(s"Copying $from → $to")
IO.copyFile(from, to, preserveLastModified = true)
} else if (mandatory)
sys.error("File not found: " + from.absolutePath)
else if (to.exists()) {
log.info(s"Deleting $to")
IO.delete(to)
}
// SBT doesn't have a standard concept of dev/prod builds so however you decide to
// specify that, you can use settings similar to below.
// The `scalaJSLinkedFile in Compile` setting referenced in the snippet above will
// choose fast/full opt via the `scalaJSStage` below.
def jsDevSettings: Project => Project =
_.settings(emitSourceMaps := true)
def jsProdSettings: Project => Project =
_.settings(
emitSourceMaps := false,
scalaJSStage := FullOptStage,
scalaJSSemantics in fullOptJS ~= (_
.withProductionMode(true)
.withRuntimeClassNameMapper(Semantics.RuntimeClassNameMapper.discardAll())
.withArrayIndexOutOfBounds(CheckedBehavior.Unchecked)
.withAsInstanceOfs(CheckedBehavior.Unchecked)))
scalaJSOptimizerOptions ~= (_
.withBatchMode(true)
.withCheckScalaJSIR(true)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment