Mathieu Mathieu - 4 days ago 6
Scala Question

Build JS from SJSIR `manually`

I need to build a js file from sjsir files at runtime to implement a system of plugins, so that it can't be done at compile time with the rest of my compilation. I used to implement the same process in 0.6.3 with the following code, but it seems to be deprecated. What algorithm do you recommand to achieve the same action with 0.6.13 ?
Thanks

val scalajsLib = copyJar("scalajs-library_2.11-0.6.3")

val semantics = org.scalajs.core.tools.sem.Semantics.Defaults

val partialClasspath =
PartialClasspathBuilder.build(collection.immutable.Seq(scalajsLib, src))

val completeClasspath = partialClasspath.resolve()

val optimizer = new ScalaJSOptimizer(semantics)

val logger = new ScalaConsoleLogger

val out = WritableFileVirtualJSFile(
new java.io.File(target, JS_FILE))
if (optimized) {
val sems = semantics.optimized

new ScalaJSClosureOptimizer(sems).optimizeCP(
new ScalaJSOptimizer(sems),
completeClasspath,
ScalaJSClosureOptimizer.Config(out),
logger
)
} else {
optimizer.optimizeCP(
completeClasspath,
ScalaJSOptimizer.Config(out, checkIR = false, wantSourceMap = !optimized),
logger
)
}

Answer

The Tools API has dramatically changed in 0.6.5, indeed. It became much simpler and more able to evolve in non-breaking ways in the future.

Your code above can be written with the new API as follows:

import java.io.File

import org.scalajs.core.tools.io._
import org.scalajs.core.tools.sem._
import org.scalajs.core.tools.linker.backend.{OutputMode, ModuleKind}
import org.scalajs.core.tools.linker.Linker
import org.scalajs.core.tools.logging.ScalaConsoleLogger

def link(inputClasspath: Seq[File], outputJSFile: File): Unit = {
  // Obtain VirtualScalaJSIRFile's from the input classpath
  val irCache = new IRFileCache().newCache
  val irContainers = IRFileCache.IRContainer.fromClasspath(inputClasspath)
  val sjsirFiles = irCache.cached(irContainers)

  // A bunch of options. Here we use all the defaults
  val semantics = Semantics.Defaults
  val outputMode = OutputMode.Default
  val moduleKind = ModuleKind.NoModule
  val linkerConfig = Linker.Config()

  // Actual linking
  val linker = Linker(semantics, outputMode, moduleKind, linkerConfig)
  val logger = new ScalaConsoleLogger
  linker.link(sjsirFiles, WritableFileVirtualJSFile(outputJSFile), logger)
}

And you can call that link function with the following arguments, to exactly match your above snippet:

link(Seq(scalajsLib, src), new java.io.File(target, JS_FILE))

If you intend to call this method several times on the same classpath within the same process, it is advised to cache and reuse the instances irCache and linker across runs, as this will considerably speed up the process.

See also the Scaladoc of the Tools API.

Comments