copying scala.js linker artifacts after linking

copying scala.js linker artifacts after linking

There have been a few requests for a plugin to copy the scala.js linker artifacts to another location after the linker has run. While you could set the output path for the artifact to a different location, you may want to have the artifacts generated into the standard location then copy it to somewhere else to provide better compatibility with existing tooling.

Ad-hoc Approach

Here’s one way to add a copy process to a specific sub-project:

def copyTask(odir: String) = {
  lazy val copyJSOutput = taskKey[Unit]("copy scala.js linker outputs to another location")
  Seq(
    copyJSOutput := {
      println(s"Copying artifact ${scalaJSLinkedFile.in(Compile).value.path} to [${odir}]")
      val src = file(scalaJSLinkedFile.in(Compile).value.path)
      IO.copy(Seq(
        (src, file(odir) / src.name),
        (file(src.getCanonicalPath() + ".map"), file(odir) / (src.name + ".map"))
      ), CopyOptions(true, true, true))
    },
    fastOptJS / copyJSOutput := (copyJSOutput triggeredBy fastOptJS.in(Compile)).value,
    fullOptJS / copyJSOutput := (copyJSOutput triggeredBy fullOptJS.in(Compile)).value
  )
}

Notice that dev and prod linker tasks are modified. This does not show testing artifacts being changed.

Modify your project definition to use:

lazy val myproject = project.in(...)
   .settings(copyTask("../node-server/src"))

Create a Plugin

You can also create a plugin in projects/CopyScalaJS.scala

package ttg
package scalajs

import sbt._
import Keys._
import org.scalajs.sbtplugin.ScalaJSPlugin
import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._

/**
 * Copy JS linker artifacts to another location. Add to your project to enable.
 */
object CopyJSPlugin extends AutoPlugin {
  override def requires = ScalaJSPlugin

  final object autoImport {
    val copyTarget = SettingKey[String]("copyTarget", "scala.js linker artifact copy target directory")
    val copyJS = TaskKey[Unit]("copyJS", "Copy scala.js linker artifacts to another location after linking.")
  }
  import autoImport._

  override lazy val projectSettings = Seq(
    copyJS := copyJSTask.value,
    fastOptJS / copyJS := (copyJS triggeredBy fastOptJS.in(Compile)).value,
    fullOptJS / copyJS := (copyJS triggeredBy fullOptJS.in(Compile)).value
  )
  //define inline via `copyJS := {` or separately like this
  private def copyJSTask = Def.task {
      val odir = copyTarget.value
      println(s"Copying artifact ${scalaJSLinkedFile.in(Compile).value.path} to [${odir}]")
      val src = file(scalaJSLinkedFile.in(Compile).value.path)
      IO.copy(Seq(
        (src, file(odir) / src.name),
        (file(src.getCanonicalPath() + ".map"), file(odir) / (src.name + ".map"))
      ), CopyOptions(true, true, true))
    }
}

Enable like any other plugin:

lazy val myproject = ...
  .enablePlugins(CopyJSPlugin)
  .setting(copyTarget := "../somedir")

If you forget to set copyTarget you will have a sbt static compilation error when trying to load the project file.

Comments

Popular posts from this blog

zio layers and framework integration

typescript and react types

dotty+scala.js+async: interesting options