如何交叉编译ScalaJS 0.6/1.0.0顶层sbt项目及解决编译错误
针对Scala.js 0.6.x与1.x交叉编译及
sjsDefinedByDefault错误的解决方案 一、sjsDefinedByDefault错误的核心原因与修复
你碰到的Option not understood: sjsDefinedByDefault报错,本质是Scala.js 1.x系列彻底重构了编译器/链接器的配置逻辑,旧的配置方式在新版本中不再兼容:
- 在Scala.js 0.6.x(比如你用的0.6.28)中,
-P:scalajs:sjsDefinedByDefault是有效的scalac参数,作用是默认把所有非原生JS类型标记为@js.native @JSDefined,所以这个版本下构建正常。 - 到了Scala.js 1.x(包括1.0.0-M8),这个默认标记的配置已经从scalac参数迁移到了链接器设置里,不再通过
scalacOptions传递,直接用旧参数自然会被识别为无效选项。
修复方案:按版本条件化配置
完全不需要把项目拆成子项目,只需要根据当前使用的Scala.js版本,针对性地设置对应配置即可:
- 在
build.sbt中先添加版本判断的辅助变量:
val isScalaJS1x = scalaJSVersion.startsWith("1.")
- 分别处理0.6.x和1.x的配置:
// 给0.6.x版本保留旧的scalac参数 scalacOptions ++= { if (!isScalaJS1x) Seq("-P:scalajs:sjsDefinedByDefault") else Nil } // 给1.x版本设置新的链接器配置 scalaJSLinkerConfig ~= { config => if (isScalaJS1x) config.withUseJSDirective("definedByDefault") else config }
二、顶层项目实现Scala.js 0.6.x与1.x交叉编译
要在顶层项目中支持两个版本的交叉编译,核心是通过环境变量动态切换Scala.js版本,并对所有版本差异做条件化处理:
1. 插件配置(project/plugins.sbt)
保留你当前的动态版本逻辑,确保能通过SCALAJS_VERSION环境变量切换版本:
val scalaJSVersion = Option(System.getenv("SCALAJS_VERSION")).getOrElse("0.6.28") addSbtPlugin("org.scala-js" % "sbt-scalajs" % scalaJSVersion)
2. 项目核心配置(build.sbt)
除了上面提到的scalac参数和链接器配置,还要处理其他可能的版本差异(比如依赖版本):
name := "scala-js-d3v4" version := "master-SNAPSHOT" scalaVersion := "2.12.8" enablePlugins(ScalaJSPlugin) // 版本判断辅助变量 val isScalaJS1x = scalaJSVersion.startsWith("1.") // 条件化配置scalac参数 scalacOptions ++= { val baseOpts = Seq("-deprecation", "-feature") val jsOpts = if (!isScalaJS1x) Seq("-P:scalajs:sjsDefinedByDefault") else Nil baseOpts ++ jsOpts } // 条件化配置链接器 scalaJSLinkerConfig ~= { config => if (isScalaJS1x) config.withUseJSDirective("definedByDefault") else config } // 示例:如果有跨版本差异的依赖,也做条件化处理 libraryDependencies ++= { if (isScalaJS1x) Seq( "org.scala-js" %%% "scalajs-dom" % "2.0.0" ) else Seq( "org.scala-js" %%% "scalajs-dom" % "0.9.8" ) }
3. 编译测试
- 编译0.6.28版本:
SCALAJS_VERSION=0.6.28 sbt fastOptJS
- 编译1.0.0-M8版本:
SCALAJS_VERSION=1.0.0-M8 sbt fastOptJS
补充说明
关于「是否必须作为子项目才能仅将该选项作为ScalaJS设置应用」——答案是否定的。子项目是多版本交叉编译的一种常见方案(比如用CrossProject),但顶层项目通过条件化配置同样可以实现。子项目的优势是能同时构建两个版本,而顶层项目通过环境变量切换更轻量化,适合不需要同时构建两个版本的场景。
内容的提问来源于stack exchange,提问作者Felix Dietze
相关产品推荐
相关产品推荐

