You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala.js共享类依赖JVM/JS分平台实现的场景及问题咨询

什么时候Shared目录的类需要依赖分平台实现的Core类?

简单来说,当Shared目录的代码需要触及平台专属的原生特性、API或行为时,就必须依赖一个抽象的Core类,并在JVM/JS端分别实现。具体常见场景包括:

  • 与底层系统交互:比如文件IO、网络请求、资源加载——JVM依赖Java标准库(java.io, java.net),而JS依赖浏览器API(fetch, FileReader)或Node.js模块(fs),这些逻辑无法在Shared中统一实现,必须通过Core类做抽象隔离。
  • 处理平台特有数据/行为:比如时间处理(JVM的java.util.Date vs JS的Date)、并发模型(JVM的线程 vs JS的事件循环)、系统信息获取(JVM的System.getProperty vs JS的navigator),Shared代码要使用这些能力时,必须依赖Core类做适配。
  • 对接平台专属第三方库:如果你的JVM端依赖某个Java库,JS端依赖对应的npm包,Shared代码要统一调用这些库的功能,就需要Core类作为桥接层,两边分别实现调用逻辑。
针对你场景的解决方案

你的Shared核心代码依赖Core类是完全合理的——这正是Scala.js交叉编译的标准“抽象-实现”模式。下面是具体的落地步骤:

1. 在Shared目录定义抽象Core Trait

先把需要的能力抽象成Trait,只声明方法签名,不写具体实现:

// shared/src/main/scala/com/example/Core.scala
import scala.concurrent.Future

trait Core {
  // 抽象资源读取方法
  def readResource(path: String): Future[String]
  // 抽象时间戳获取方法
  def getCurrentTimestamp(): Long
}

这里用Future统一异步逻辑,避免JS端异步、JVM端同步的差异影响Shared代码。

2. 在JVM/JS目录分别实现Core Trait

根据各自平台的特性,实现Trait中的方法:

// jvm/src/main/scala/com/example/JvmCore.scala
import scala.concurrent.Future
import scala.io.Source

class JvmCore extends Core {
  override def readResource(path: String): Future[String] = Future {
    // JVM端用类加载器读取资源文件
    Source.fromResource(path).mkString
  }

  override def getCurrentTimestamp(): Long = System.currentTimeMillis()
}
// js/src/main/scala/com/example/JsCore.scala
import scala.concurrent.Future
import scala.scalajs.js
import scala.scalajs.js.Promise

class JsCore extends Core {
  override def readResource(path: String): Future[String] = {
    // JS端用fetch API读取资源,转成Scala Future
    Promise.apply[String] { (resolve, reject) =>
      js.Dynamic.global.fetch(path).then { response: js.Dynamic =>
        response.text().then(resolve.asInstanceOf[js.Function1[String, Unit]])
      }.catch(reject.asInstanceOf[js.Function1[js.Any, Unit]])
    }.toFuture
  }

  override def getCurrentTimestamp(): Long = js.Date.now().toLong
}

3. 在Shared中获取Core实例

通过Scala.js的平台检测,在Shared代码中动态获取对应平台的Core实现:

// shared/src/main/scala/com/example/CoreFactory.scala
object CoreFactory {
  def getCore(): Core = {
    // 判断当前运行平台,返回对应实现
    if (scala.scalajs.runtime.linkingInfo.semantics.isInstanceOf[scala.scalajs.runtime.Semantics.JS]) {
      new com.example.JsCore()
    } else {
      new com.example.JvmCore()
    }
  }
}

之后你的Shared核心代码就可以直接调用CoreFactory.getCore()来使用平台专属能力了。

关键注意事项
  • 绝对不要在Shared代码中直接引用平台专属类型(比如java.io.File或js.Date),所有平台相关逻辑必须通过Core抽象层隔离。
  • 如果涉及复杂的平台差异,也可以用Scala的条件编译注解(比如@scala.scalajs.annotation.JSOnly或@scala.annotation.nowarn("msg=JVM-only"))来辅助,但抽象Trait的方式更清晰。
  • 确保你的sbt交叉编译配置正确,让JVM/JS源集能正确依赖Shared源集,并且各自的Core实现能被Shared代码访问到。

内容的提问来源于stack exchange,提问作者Ben McKenneby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:31:14