为 javascript 模块编写 scalajs facade 时如何使用 JSImport
How to use JSImport when writing scalajs facade for javascript modules
我已经使用 JSImport 编写了一个外观,并且可以正常工作。不幸的是,我通过反复试验找到了解决方案,我不完全理解为什么这个特定的解决方案有效,但我尝试过的其他解决方案却没有。
背景:我从一个使用 sbt 构建的工作项目开始,它是一个单页应用程序,使用 scala.js 实现客户端代码,使用 scala 和 Play 框架实现服务器端。 javascript 库与 web jar 打包在一起,并使用 sbt jsDependencies 变量捆绑到客户端 js 文件中。我想实现一些新功能,这些功能需要库更新,然后需要一些 javascript 库的更新,这些库仅以 npm 格式提供。所以现在我使用 npmDependencies 和 scalajs-bundler 插件包括客户端应用程序的所有 javascript 依赖项。这打破了导致我的问题的一些 scalajs 门面。
这个问题我会以log4javascript的门面为例
变量 log4javascript
是用于访问其余 api 的顶级对象。
当 js 库作为 web jar 包含时,log4javascript
的外观是这样实现的:
@js.native
@js.annotation.JSGlobalScope
object Log4JavaScript extends js.Object {
val log4javascript:Log4JavaScript = js.native
}
更改为 npm 后:
import scala.scalajs.js.annotation.JSImport.Namespace
@JSImport("log4javascript", Namespace)
@js.native
object Log4JavaScript extends js.Object {
def resetConfiguration(): Unit = js.native
def getLogger(name:js.UndefOr[String]): JSLogger = js.native
...
}
按照 scala.js docs 编写导入模块,我希望对象名称(在本例中为 Log4JavaScript)必须与导出的符号名称匹配才能使绑定工作。但是,log4javascript.js 中的顶级符号是 log4javascript
。经过试验,scala 对象名称似乎对绑定没有影响。无论我将 scala 顶级对象命名为什么,它都能正确绑定。
有人可以解释一下当使用 'Namespace' arg 到 JSImport 时,scala object/class/def/val 名称和 javascript 模块中的名称之间存在什么关系吗?
根据scala.js文档,看来我应该能够提供js对象的实际名称(我也试过"Log4JavaScript")
@JSImport("log4javascript", "log4javascript")
@js.native
object SomeOtherName extends js.Object {
def resetConfiguration(): Unit = js.native
def getLogger(name:js.UndefOr[String]): JSLogger = js.native
...
}
但是,绑定失败。当我尝试访问任何成员函数时,我将收到运行时错误。
Log4JavaScript.resetConfiguration()
Uncaught TypeError: Cannot read property 'resetConfiguration' of undefined
有人可以解释为什么这不起作用吗?
log4javascript 还在 log4javascript
的范围内定义了一些 classes。当 lib 作为 web jar 包含时,定义如下:
@js.native
@JSGlobal("log4javascript.AjaxAppender")
class AjaxAppender(url:String) extends Appender {
def addHeader(header:String, value:String):Unit = js.native
}
切换到 npm 后,我不得不将 class 定义放在顶级对象中:
@js.native
trait Appender extends js.Object {
...
}
@JSImport("log4javascript", "log4javascript")
@js.native
object Log4JavaScript extends js.Object {
...
class AjaxAppender(url: String) extends Appender {
def addHeader(name: String, value: String): Unit = js.native
}
...
}
这似乎是明智的,但从 scala.js 文档来看,似乎应该可以在顶级对象之外以这种方式定义它
@JSImport("log4javascript", "log4javascript.AjaxAppender")
@js.native
class AjaxAppender(url: String) extends Appender {
def addHeader(name: String, value: String): Unit = js.native
}
然而,这也无法绑定。有人可以解释上面定义 class 的正确方法吗?或者嵌套在 Log4JavaScript
对象中的定义是唯一正确的方法吗?
Can someone explain what relationship exists, if any, between the scala object/class/def/val names and the names in the javascript module when using the 'Namespace' arg to JSImport?
这在 Scala.js 文档的 this part 中有解释。定义外观的 Scala 对象的名称无关紧要。重要的是 @JSImport
注释的参数。第一个表示从哪个模块导入,第二个表示导入什么。
在您的例子中,log4javascript 模块位于 log4javascript.js
文件中,在 log4javascript
包目录中。所以,你的第一个参数应该是:
@JSImport("log4javascript/log4javascript.js", ...)
object Log4JavaScript ...
然而,log4javascript 被定义为一个 npm 模块,其 main file 引用 log4javascript.js
文件。这意味着您可以只使用包目录名称:
@JSImport("log4javascript", ...)
object Log4JavaScript ...
(有关 NodeJS 如何解析模块的更多信息,请参阅 this article)
@JSImport
注解的第二个参数表示要导入的内容。在你的例子中,你想导入整个模块,而不仅仅是它的一个成员,所以你想使用 Namespace
:
@JSImport("log4javascript", Namespace)
object Log4JavaScript ...
这对应于以下 EcmaScript 导入语句:
import * as Log4JavaScript from 'log4javascript'
请注意,尽管 Scala 对象名称(Log4JavaScript
,此处)并不重要,但其成员的名称确实很重要,如 [=34] 中所述=] Scala.js 文档。
According to the scala.js docs, it seems I should be able to provide the actual name of the js object (I also tried "Log4JavaScript")
@JSImport("log4javascript", "log4javascript")
...
However, this fails to bind. I will get a runtime error when I try to access any of the member functions.
当你写那个的时候,你试图访问 log4javascript
模块的 log4javascript
成员。但是那个模块没有这样的成员。
it should have been possible to define it this way outside of the top level object
@JSImport("log4javascript", "log4javascript.AjaxAppender")
...
However, this also fails to bind.
同样,这意味着“从 log4javascript
模块导入 log4javascript.AjaxAppender
成员”,但该模块没有这样的成员。以下应该有效:
@JSImport("log4javascript", "AjaxAppender")
我已经使用 JSImport 编写了一个外观,并且可以正常工作。不幸的是,我通过反复试验找到了解决方案,我不完全理解为什么这个特定的解决方案有效,但我尝试过的其他解决方案却没有。
背景:我从一个使用 sbt 构建的工作项目开始,它是一个单页应用程序,使用 scala.js 实现客户端代码,使用 scala 和 Play 框架实现服务器端。 javascript 库与 web jar 打包在一起,并使用 sbt jsDependencies 变量捆绑到客户端 js 文件中。我想实现一些新功能,这些功能需要库更新,然后需要一些 javascript 库的更新,这些库仅以 npm 格式提供。所以现在我使用 npmDependencies 和 scalajs-bundler 插件包括客户端应用程序的所有 javascript 依赖项。这打破了导致我的问题的一些 scalajs 门面。
这个问题我会以log4javascript的门面为例
变量 log4javascript
是用于访问其余 api 的顶级对象。
当 js 库作为 web jar 包含时,log4javascript
的外观是这样实现的:
@js.native
@js.annotation.JSGlobalScope
object Log4JavaScript extends js.Object {
val log4javascript:Log4JavaScript = js.native
}
更改为 npm 后:
import scala.scalajs.js.annotation.JSImport.Namespace
@JSImport("log4javascript", Namespace)
@js.native
object Log4JavaScript extends js.Object {
def resetConfiguration(): Unit = js.native
def getLogger(name:js.UndefOr[String]): JSLogger = js.native
...
}
按照 scala.js docs 编写导入模块,我希望对象名称(在本例中为 Log4JavaScript)必须与导出的符号名称匹配才能使绑定工作。但是,log4javascript.js 中的顶级符号是 log4javascript
。经过试验,scala 对象名称似乎对绑定没有影响。无论我将 scala 顶级对象命名为什么,它都能正确绑定。
有人可以解释一下当使用 'Namespace' arg 到 JSImport 时,scala object/class/def/val 名称和 javascript 模块中的名称之间存在什么关系吗?
根据scala.js文档,看来我应该能够提供js对象的实际名称(我也试过"Log4JavaScript")
@JSImport("log4javascript", "log4javascript")
@js.native
object SomeOtherName extends js.Object {
def resetConfiguration(): Unit = js.native
def getLogger(name:js.UndefOr[String]): JSLogger = js.native
...
}
但是,绑定失败。当我尝试访问任何成员函数时,我将收到运行时错误。
Log4JavaScript.resetConfiguration()
Uncaught TypeError: Cannot read property 'resetConfiguration' of undefined
有人可以解释为什么这不起作用吗?
log4javascript 还在 log4javascript
的范围内定义了一些 classes。当 lib 作为 web jar 包含时,定义如下:
@js.native
@JSGlobal("log4javascript.AjaxAppender")
class AjaxAppender(url:String) extends Appender {
def addHeader(header:String, value:String):Unit = js.native
}
切换到 npm 后,我不得不将 class 定义放在顶级对象中:
@js.native
trait Appender extends js.Object {
...
}
@JSImport("log4javascript", "log4javascript")
@js.native
object Log4JavaScript extends js.Object {
...
class AjaxAppender(url: String) extends Appender {
def addHeader(name: String, value: String): Unit = js.native
}
...
}
这似乎是明智的,但从 scala.js 文档来看,似乎应该可以在顶级对象之外以这种方式定义它
@JSImport("log4javascript", "log4javascript.AjaxAppender")
@js.native
class AjaxAppender(url: String) extends Appender {
def addHeader(name: String, value: String): Unit = js.native
}
然而,这也无法绑定。有人可以解释上面定义 class 的正确方法吗?或者嵌套在 Log4JavaScript
对象中的定义是唯一正确的方法吗?
Can someone explain what relationship exists, if any, between the scala object/class/def/val names and the names in the javascript module when using the 'Namespace' arg to JSImport?
这在 Scala.js 文档的 this part 中有解释。定义外观的 Scala 对象的名称无关紧要。重要的是 @JSImport
注释的参数。第一个表示从哪个模块导入,第二个表示导入什么。
在您的例子中,log4javascript 模块位于 log4javascript.js
文件中,在 log4javascript
包目录中。所以,你的第一个参数应该是:
@JSImport("log4javascript/log4javascript.js", ...)
object Log4JavaScript ...
然而,log4javascript 被定义为一个 npm 模块,其 main file 引用 log4javascript.js
文件。这意味着您可以只使用包目录名称:
@JSImport("log4javascript", ...)
object Log4JavaScript ...
(有关 NodeJS 如何解析模块的更多信息,请参阅 this article)
@JSImport
注解的第二个参数表示要导入的内容。在你的例子中,你想导入整个模块,而不仅仅是它的一个成员,所以你想使用 Namespace
:
@JSImport("log4javascript", Namespace)
object Log4JavaScript ...
这对应于以下 EcmaScript 导入语句:
import * as Log4JavaScript from 'log4javascript'
请注意,尽管 Scala 对象名称(Log4JavaScript
,此处)并不重要,但其成员的名称确实很重要,如 [=34] 中所述=] Scala.js 文档。
According to the scala.js docs, it seems I should be able to provide the actual name of the js object (I also tried "Log4JavaScript")
@JSImport("log4javascript", "log4javascript") ...
However, this fails to bind. I will get a runtime error when I try to access any of the member functions.
当你写那个的时候,你试图访问 log4javascript
模块的 log4javascript
成员。但是那个模块没有这样的成员。
it should have been possible to define it this way outside of the top level object
@JSImport("log4javascript", "log4javascript.AjaxAppender") ...
However, this also fails to bind.
同样,这意味着“从 log4javascript
模块导入 log4javascript.AjaxAppender
成员”,但该模块没有这样的成员。以下应该有效:
@JSImport("log4javascript", "AjaxAppender")