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

quick note on scala.js, react hooks, monix, auth

attributes with react and typescript.md

zio environment and modules pattern: zio, scala.js, react, query management