com-lihaoyi / mill

Mill is a fast JVM build tool that supports Java and Scala. 2-3x faster than Gradle and 5-10x faster than Maven for common workflows, Mill aims to make your project’s build process performant, maintainable, and flexible
https://mill-build.org/
MIT License
2.05k stars 337 forks source link

UnsupportedInputException on ScalaJS project while running tests after update to 0.10.11 #2300

Closed carlosedp closed 1 year ago

carlosedp commented 1 year ago

I have a project using Scalajs and tests fail when bumping to mill from 0.10.10 to 0.10.11:

object versions {
  val scala3          = "3.3.0-RC2"
  val scalajs         = "1.13.0"
  val sttp            = "3.8.9"
  val organizeimports = "0.6.0"
  val scalajsdom      = "2.3.0"
  val scalatest       = "3.2.15"
}

trait Common extends ScalaModule with TpolecatModule with ScalafmtModule with ScalafixModule {
  def sources = T.sources(
    millSourcePath / "src",
    millSourcePath / os.up / "shared" / "src",
  )
  def scalafixIvyDeps = Agg(ivy"com.github.liancheng::organize-imports:${versions.organizeimports}")
  def repositoriesTask = T.task { // Add snapshot repositories in case needed
    super.repositoriesTask() ++ Seq("oss", "s01.oss")
      .map(r => s"https://$r.sonatype.org/content/repositories/snapshots")
      .map(MavenRepository(_))
  }
}

object frontend extends ScalaJSModule with Common {
  def scalaVersion   = versions.scala3
  def scalaJSVersion = versions.scalajs
  def ivyDeps = super.ivyDeps() ++ Agg(
    ivy"org.scala-js::scalajs-dom::${versions.scalajsdom}",
    ivy"com.softwaremill.sttp.client3::core::${versions.sttp}",
  )

  def scalaJSUseMainModuleInitializer = true
  def moduleKind                      = T(ModuleKind.ESModule)
  def moduleSplitStyle                = T(ModuleSplitStyle.SmallModulesFor(List("com.carlosedp.zioscalajs.frontend")))

  // These two tasks are used by Vite to get update path
  def fastLinkOut() = T.command(println(fastLinkJS().dest.path))
  def fullLinkOut() = T.command(println(fullLinkJS().dest.path))

  object test extends Tests with Common with TestModule.ScalaTest {
    // Test dependencies
    def ivyDeps = Agg(
      ivy"org.scalatest::scalatest::${versions.scalatest}",
    )
    def jsEnvConfig = T(JsEnvConfig.JsDom())
  }
}
# On mill 0.10.10:

❯ ./mill frontend.test
[98/98] frontend.test.test
Starting process: node
Querying backend: http://localhost:8080/greet?name=Stranger...
FrontEndSpec:
Frontend App
- should contain a button in its body
- should append 'You clicked the button!' text when the user clicks on the 'Click me' button

❯ millupd
Latest mill version is 0.10.11-1-8ef23d...
Will stick to major version 0.10.11
Version differs, updating .mill-version.
❯ ./mill frontend.test
Mill version changed (0.10.10 -> 0.10.11), re-starting server

❯ ./mill frontend.test
[102/102] frontend.test.test
1 targets failed
frontend.test.test org.scalajs.jsenv.UnsupportedInputException: Unsupported input: List(ESModule(/Users/cdepaula/repos/scala-playground/zio-scalajs-stack/out/frontend/test/fastLinkJSTest.dest/main.js))
    org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv.$anonfun$validateInput$1(JSDOMNodeJSEnv.scala:59)
    scala.collection.immutable.List.map(List.scala:246)
    scala.collection.immutable.List.map(List.scala:79)
    org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv.validateInput(JSDOMNodeJSEnv.scala:54)
    org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv.startWithCom(JSDOMNodeJSEnv.scala:47)
    org.scalajs.testing.adapter.JSEnvRPC.<init>(JSEnvRPC.scala:46)
    org.scalajs.testing.adapter.TestAdapter.startManagedRunner(TestAdapter.scala:128)
    org.scalajs.testing.adapter.TestAdapter.$anonfun$getRunnerForThread$1(TestAdapter.scala:120)
    scala.collection.concurrent.TrieMap.getOrElseUpdate(TrieMap.scala:962)
    org.scalajs.testing.adapter.TestAdapter.getRunnerForThread(TestAdapter.scala:120)
    org.scalajs.testing.adapter.TestAdapter.loadFrameworks(TestAdapter.scala:56)
    mill.scalajslib.worker.ScalaJSWorkerImpl.getFramework(ScalaJSWorkerImpl.scala:273)
    mill.scalajslib.worker.ScalaJSWorker.getFramework(ScalaJSWorker.scala:178)
    mill.scalajslib.TestScalaJSModule.$anonfun$testTask$1(ScalaJSModule.scala:346)
    mill.define.Task$TraverseCtx.evaluate(Task.scala:380)

https://github.com/carlosedp/zio-scalajs-stack/blob/feb20bbfdbc8b8ef754071ea48b00893b7cb1f6c/build.sc#L152

lolgab commented 1 year ago

Since Mill 0.10.11 ScalaJSModules Tests inherits more settings from its parent. So before mill frontend.test.moduleKind would return NoModule but now it returns ESModule. The fix here would be to manually change the test's moduleKind to ModuleKind.NoModule and also set the ModuleSplitStyle to the default. Not sure which one is the most appropriate. For example by:

def moduleSplitStyle = T(ModuleSplitStyle.FewestModules)
def moduleKind = T(ModuleKind.NoModule)

Another possible solution would be to use:

def moduleKind = T(ModuleKind.CommonJSModule)
def jsEnvConfig = T(JsEnvConfig.ExoegoJsDomNodeJs())

but I couldn't make it work yet.

carlosedp commented 1 year ago

Thanks, I'll go with the overriding the options in the test object like the first option.

object frontend extends ScalaJSModule with Common {
  def scalaVersion   = versions.scala3
  def scalaJSVersion = versions.scalajs
  def ivyDeps = super.ivyDeps() ++ Agg(
    ivy"org.scala-js::scalajs-dom::${versions.scalajsdom}",
    ivy"com.softwaremill.sttp.client3::core::${versions.sttp}",
  )

  def scalaJSUseMainModuleInitializer = true
  def moduleSplitStyle                = T(ModuleSplitStyle.SmallModulesFor(List("com.carlosedp.zioscalajs.frontend")))
  def moduleKind                      = T(ModuleKind.ESModule)

  object test extends Tests with Common with TestModule.ScalaTest {
    // Test dependencies
    def ivyDeps = Agg(
      ivy"org.scalatest::scalatest::${versions.scalatest}",
    )
    def moduleKind       = T(ModuleKind.NoModule)
    def moduleSplitStyle = T(ModuleSplitStyle.FewestModules)
    def jsEnvConfig      = T(JsEnvConfig.JsDom())
  }
}
lefou commented 1 year ago

I think, we should add a note to the changelog. There is a chance that other users stumble over the same issue. (In the hope that users read changelogs.)