tl; dr:像scalajs-java-time这样的库如何替换依赖项?
我遇到了Scala.js的依赖注入:
在共享代码中:
object Example {
def method(...) = { ... dependsOnPlatform ... }
val dependsOnPlatform = ???
}
这种天真的做法是:
val dependsOnPlatform = if(onJS) jsImplementation else jvmImplementaion
问题是人们经常无法为JVM编译jsImplementation
,因为它依赖于Scala.js类;如果它使用反射或引用Java类,则可能无法完成fastOptJS
的{{1}}。
鉴于jvmImplementaion
必须是静态的,不能使用构造函数注入。
使用反射解决问题很容易,但Scala.js中不允许这样做。
它可以通过副作用来解决,但由于物体是静止的,因此很脆弱
依赖关系可以是object Example
的隐式参数,但这需要额外的导入
这不是宏可以在不卷积构建过程的情况下解决的问题。
答案 0 :(得分:3)
推荐的解决方案是使用在js/src/
中以不同于jvm/src/
的方式实现的顶级对象,但同时向两者公开相同的接口。然后,该对象的API通常可以从shared/src/
代码中使用。此对象通常称为Platform
,并使包为私有。
js/src/.../Platform.scala
package foo
private[foo] object Platform {
def dependsOnPlatform(...) = {
jsImplementation
}
}
jvm/src/.../Platform.scala
package foo
private[foo] object Platform {
def dependsOnPlatform(...) = {
jvmImplementation
}
}
shared/src/.../Platform.scala
package foo
object Example {
def method(...) = {
...
Platform.dependsOnPlatform(...)
...
}
}
没有必要使用丑陋的阴影" hack也不写.java源文件,如@ acdenh的回答中所述。
答案 1 :(得分:0)
正确的解决方案是创建一个Java类和"阴影"它与Scala.js类。
在共享代码中:
method
然后在项目的Scala.js部分:
val dependsOnPlatform = new Injection
class InjectionForJVM { ... } //InjectionForJVM.scala
public class Injection extends InjectionForJVM { } //Injection.java
这两个class Injection { ... } //Injection.scala
类必须位于同一个包中并具有相同的接口
不要将Injection
包装在任何对象或类中,因为InjectionForJVM.scala
可能无法正确编译。 Injection.java
可以使用反射和Java方法,因为InjectionForJVM.scala
无法访问该类。也可以直接在Java中实现fastOptJS
,但是谁可能想要这样做呢?
(确切地说,这并不是真正的影子,因为在任何情况下Scala.js都不存在Injection.java
。在JVM上实际的类阴影是可能的,但通常是不可取的。)