为JavaScript模块编写scalajs门面时如何使用JSImport [英] How to use JSImport when writing scalajs facade for javascript modules

查看:83
本文介绍了为JavaScript模块编写scalajs门面时如何使用JSImport的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用JSImport编写了外观,并且可以正常工作.不幸的是,我通过反复试验得出了解决方案,但我不完全理解为什么这种特定的解决方案有效,但是我尝试过的其他解决方案却没有.

I have written a facade using JSImport, and it works. Unfortunately, I arrived at the solution through trial and error, and I don't fully understand why this particular solution works but others I tried did not.

背景:我从一个使用sbt构建的工作项目开始,该项目是一个单页应用程序,该应用程序使用scala.js实现客户端代码,并使用scala和Play框架实现服务器端. javascript库与Web jar打包在一起,并使用sbt jsDependencies变量捆绑到客户端js文件中.我想实现一些新功能,这些功能需要库up rev,然后需要一些javascript库的up rev,这些JavaScript库仅以npm格式提供.因此,现在我将使用带有pmajs-bundler插件的npmDependencies包括客户端应用程序的所有javascript依赖项.这打破了一些斯拉杰斯的外墙,导致了我的问题.

Background: I'm starting with a working project, built with sbt, which is a single page application that implements the client side code with scala.js and the server side with scala and the Play framework. The javascript libraries were packaged with web jars and bundled into the client js file using the sbt jsDependencies variable. I wanted to implement some new features which required a library up rev, which then required an up rev of some javascript libs which were only available in npm format. So now I am including all the javascript dependencies for the client app using npmDependencies with the scalajs-bundler plugin. This broke some of the scalajs facades leading to my question.

我将使用立面来 log4javascript 作为该问题的示例.

I'll use the facade to log4javascript as an example for this question.

变量log4javascript是用于访问api其余部分的顶级对象.

The variable log4javascript is the top level object used to access the rest of the api.

当js库作为web jar包含时,这是实现log4javascript的外观的方式:

When the js libs were included as web jars, this is how the facade to log4javascript was implemented:

@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顶级对象,它都能正确绑定.

Following the scala.js docs for writing importing modules I expected the object name (Log4JavaScript in this case) would have to match the exported symbol name in order for the binding to work. However, the top level symbol in log4javascript.js is log4javascript. After experimenting, it seems the scala object name makes no difference for the binding. It binds correctly no matter what I name the scala top level object.

在使用命名空间" args到JSImport时,有人可以解释scala对象/类/def/val名称与javascript模块中的名称之间存在什么关系吗?

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文档,看来我应该能够提供js对象的实际名称(我也尝试过"Log4JavaScript")

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")
@js.native
object SomeOtherName extends js.Object {
  def resetConfiguration(): Unit = js.native
  def getLogger(name:js.UndefOr[String]): JSLogger = js.native
  ...
}

但是,此操作无法绑定.当我尝试访问任何成员函数时,都会出现运行时错误.

However, this fails to bind. I will get a runtime error when I try to access any of the member functions.

Log4JavaScript.resetConfiguration()

Uncaught TypeError: Cannot read property 'resetConfiguration' of undefined

有人可以解释为什么这行不通吗?

Can someone explain why this doesn't work?

log4javascript还定义了log4javascript范围内的一些类.当将lib包含为Web jar时,定义如下:

log4javascript also defines some classes inside the scope of log4javascript. When the lib was included as a web jar the definition looked like:

@js.native
@JSGlobal("log4javascript.AjaxAppender")
class AjaxAppender(url:String) extends Appender {
  def addHeader(header:String, value:String):Unit = js.native
}

切换到npm后,我不得不将类定义放在顶级对象中:

After switching to npm I had to put the class definition inside the top level object:

@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文档看来,应该可以在顶级对象之外以这种方式定义它

This seems sensible, but from the scala.js docs it seems like it should have been possible to define it this way outside of the top level object

@JSImport("log4javascript", "log4javascript.AjaxAppender")
@js.native
class AjaxAppender(url: String) extends Appender {
  def addHeader(name: String, value: String): Unit = js.native 
}

但是,这也无法绑定.有人可以解释定义上述类的正确方法吗?还是嵌套在Log4JavaScript对象内部的定义是执行此操作的唯一正确方法?

However, this also fails to bind. Could someone explain the correct way to define the class as above? Or is the definition nested inside the Log4JavaScript object the only correct way to do it?

推荐答案

在使用命名空间" args到JSImport时,有人可以解释scala对象/类/def/val名称与javascript模块中的名称之间存在什么关系吗?

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?

这在

This is explained in this part of the Scala.js documentation. The name of the Scala object defining the facade does not matter. What matter are the parameters of the @JSImport annotation. The first one indicates which module to import from, and the second one indicates what to import.

在您的情况下,log4javascript模块位于log4javascript.js文件的log4javascript软件包目录中.因此,您的第一个参数应该是:

In your case, the log4javascript module is in the log4javascript.js file, in the log4javascript package directory. So, your first parameter should be:

@JSImport("log4javascript/log4javascript.js", ...)
object Log4JavaScript ...

但是,log4javascript被定义为npm模块,其主文件引用log4javascript.js文件.这意味着您可以只使用软件包目录名称:

However, log4javascript is defined as an npm module whose main file refers to the log4javascript.js file. This means that you can just use the package directory name:

@JSImport("log4javascript", ...)
object Log4JavaScript ...

(请参阅

(See this article for more information on how NodeJS does resolve modules)

@JSImport批注的第二个参数指示要导入的内容.在您的情况下,您想导入整个模块,而不仅仅是模块的一部分,因此您想使用Namespace:

The second parameter of the @JSImport annotation indicates what to import. In your case, you want to import the whole module, not just a member of it, so you want to use Namespace:

@JSImport("log4javascript", Namespace)
object Log4JavaScript ...

这对应于以下EcmaScript导入语句:

This corresponds to the following EcmaScript import statement:

import * as Log4JavaScript from 'log4javascript'

请注意,尽管Scala对象名称(此处为Log4JavaScript)无关紧要,但其成员的名称​​却很重要,如

Note that, although the Scala object name (Log4JavaScript, here) does not matter, the names of its members does matter, as explained in this part of the Scala.js documentation.

根据scala.js文档,看来我应该能够提供js对象的实际名称(我也尝试过"Log4JavaScript")

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成员.但是该模块没有这样的成员.

When you write that, you try to access to the log4javascript member of the log4javascript module. But that module does not have such a member.

应该可以在顶级对象之外以这种方式定义

it should have been possible to define it this way outside of the top level object

@JSImport("log4javascript", "log4javascript.AjaxAppender")
...

但是,这也无法绑定.

同样,这意味着从log4javascript模块导入log4javascript.AjaxAppender成员",但是该模块没有这样的成员.以下应该可以工作:

Again, this means "import the log4javascript.AjaxAppender member from the log4javascript module", but that module does not have such a member. The following should work:

@JSImport("log4javascript", "AjaxAppender")

这篇关于为JavaScript模块编写scalajs门面时如何使用JSImport的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆