如何使用 scala.js 编译器作为编译器插件,从而使其集成到 Gradle 或 maven 中?

How to use scala.js compiler as a compiler plugin, thus allowing it to integrate into Gradle or maven?

我有一个只能用 Gradle 编译的 Scala 项目,最近有人要求将它移植到 Scala.js,最好是通过交叉构建。

当我阅读 Scala.js 的代码时,我意识到大部分插件实际上是一个编译器 (scalac) 插件:

import scala.tools.nsc.plugins.{
  Plugin => NscPlugin, PluginComponent => NscPluginComponent
}
...
class ScalaJSPlugin(val global: Global) extends NscPlugin {
  import global._
...

但是所有文档都建议将它用作 sbt-plugin 的一部分,这对我来说是无用的。所以我尝试将它附加到我的 scalac 进程,通过 gradle:

调用
    dependencies {

        implementation("org.scala-js:scalajs-library_${vs.scalaBinaryV}:${vs.scalaJSV}")
        scalaCompilerPlugins("org.scala-js:scalajs-compiler_${vs.scalaV}:${vs.scalaJSV}")
...

不幸的是,这个实验不起作用。编译器抛出以下错误:

> Task :compileTestFixturesScala FAILED
## Exception when compiling 1 sources to /home/peng/git-scaffold/scaffold-gradle-kts/build/classes/scala/testFixtures
scala.reflect.internal.MissingRequirementError: object scala.scalajs.js.Dynamic in compiler mirror not found.
scala.reflect.internal.MissingRequirementError$.notFound(MissingRequirementError.scala:24)
scala.reflect.internal.Mirrors$RootsBase.$anonfun$getModuleOrClass(Mirrors.scala:66)
scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:66)
scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:56)
scala.reflect.internal.Mirrors$RootsBase.getRequiredClass(Mirrors.scala:56)
org.scalajs.nscplugin.JSDefinitions$JSDefinitionsClass.JSDynamicClass$lzycompute(JSDefinitions.scala:52)
org.scalajs.nscplugin.JSDefinitions$JSDefinitionsClass.JSDynamicClass(JSDefinitions.scala:52)
org.scalajs.nscplugin.JSDefinitions$JSDefinitionsClass.JSDynamicModule$lzycompute(JSDefinitions.scala:83)
org.scalajs.nscplugin.JSDefinitions$JSDefinitionsClass.JSDynamicModule(JSDefinitions.scala:83)
org.scalajs.nscplugin.JSDefinitions$JSDefinitionsClass.JSDynamic_newInstance$lzycompute(JSDefinitions.scala:84)
org.scalajs.nscplugin.JSDefinitions$JSDefinitionsClass.JSDynamic_newInstance(JSDefinitions.scala:84)
org.scalajs.nscplugin.JSPrimitives.initWithPrimitives(JSPrimitives.scala:89)
org.scalajs.nscplugin.JSPrimitives.initPrepJSPrimitives(JSPrimitives.scala:77)
org.scalajs.nscplugin.PrepJSInterop$JSInteropPhase.run(PrepJSInterop.scala:65)
scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1524)
scala.tools.nsc.Global$Run.compileUnits(Global.scala:1508)
scala.tools.nsc.Global$Run.compileSources(Global.scala:1500)
scala.tools.nsc.Global$Run.compile(Global.scala:1634)
xsbt.CachedCompiler0.run(CompilerInterface.scala:153)
xsbt.CachedCompiler0.run(CompilerInterface.scala:125)
xsbt.CompilerInterface.run(CompilerInterface.scala:39)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
sbt.internal.inc.AnalyzingCompiler.call(AnalyzingCompiler.scala:248)
sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:122)
sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:95)
sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile(MixedAnalyzingCompiler.scala:91)
scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:186)
sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile(MixedAnalyzingCompiler.scala:82)
sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$adapted(MixedAnalyzingCompiler.scala:77)
sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:215)
sbt.internal.inc.MixedAnalyzingCompiler.compileScala(MixedAnalyzingCompiler.scala:77)
sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:146)
sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal(IncrementalCompilerImpl.scala:343)
sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$adapted(IncrementalCompilerImpl.scala:343)
sbt.internal.inc.Incremental$.doCompile(Incremental.scala:120)
sbt.internal.inc.Incremental$.$anonfun$compile(Incremental.scala:100)
sbt.internal.inc.IncrementalCommon.recompileClasses(IncrementalCommon.scala:180)
sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:98)
sbt.internal.inc.Incremental$.$anonfun$compile(Incremental.scala:102)
sbt.internal.inc.Incremental$.manageClassfiles(Incremental.scala:155)
sbt.internal.inc.Incremental$.compile(Incremental.scala:92)
sbt.internal.inc.IncrementalCompile$.apply(Compile.scala:75)
sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:348)
sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally(IncrementalCompilerImpl.scala:301)
sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:168)
sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:248)
sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:74)
org.gradle.api.internal.tasks.scala.ZincScalaCompiler.execute(ZincScalaCompiler.java:157)
org.gradle.api.internal.tasks.scala.ZincScalaCompilerFacade.execute(ZincScalaCompilerFacade.java:47)
org.gradle.api.internal.tasks.scala.ZincScalaCompilerFacade.execute(ZincScalaCompilerFacade.java:32)
org.gradle.api.internal.tasks.compile.daemon.AbstractDaemonCompiler$CompilerWorkAction.execute(AbstractDaemonCompiler.java:135)
org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
org.gradle.workers.internal.AbstractClassLoaderWorker.create(AbstractClassLoaderWorker.java:49)
org.gradle.workers.internal.AbstractClassLoaderWorker.create(AbstractClassLoaderWorker.java:43)
org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:97)
org.gradle.workers.internal.AbstractClassLoaderWorker.executeInClassLoader(AbstractClassLoaderWorker.java:43)
org.gradle.workers.internal.IsolatedClassloaderWorker.run(IsolatedClassloaderWorker.java:49)
org.gradle.workers.internal.IsolatedClassloaderWorker.run(IsolatedClassloaderWorker.java:30)
org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:87)
org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:56)
org.gradle.process.internal.worker.request.WorkerAction.call(WorkerAction.java:138)
org.gradle.process.internal.worker.child.WorkerLogEventListener.withWorkerLoggingProtocol(WorkerLogEventListener.java:41)
org.gradle.process.internal.worker.request.WorkerAction.run(WorkerAction.java:135)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
org.gradle.internal.concurrent.ManagedExecutorImpl.run(ManagedExecutorImpl.java:48)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:748)
           

尽管如此,这个错误似乎是由微不足道的缺失引起的 class,并且它发生在编译的后期阶段,此时正在编译测试代码。

所以我的问题是:如何使 scalajs 成为编译器插件(没有 sbt)?什么可能导致此错误?

该错误通常是编译类路径中没有 scalajs-library 的典型症状。但是我看到你已经添加了

implementation("org.scala-js:scalajs-library_${vs.scalaBinaryV}:${vs.scalaJSV}")

根据我对 Gradle 的理解,应该这样做。

也许 double-check 该库确实在编译类路径中结束,使用 Gradle 提供的任何命令来检查它?


也就是说,完成此操作后,您将拥有的只是 .sjsir 个文件,无法 运行 或测试。您将需要 Scala.js 链接器来处理类路径中的 .sjsir 文件,并生成一个 .js 文件。