Я написал фасад, используя JSImport, и он работает. К сожалению, я пришел к решению методом проб и ошибок, и я не до конца понимаю, почему это конкретное решение работает, а другие, которые я пробовал, - нет.
Справочная информация: я начинаю с рабочего проекта, созданного с использованием sbt, который представляет собой одностраничное приложение, которое реализует код на стороне клиента с scala.js, а на стороне сервера - scala и инфраструктуру Play. Библиотеки javascript были упакованы с веб-файлами jar и упакованы в файл js клиента с помощью переменной sbt jsDependencies. Я хотел реализовать некоторые новые функции, для которых требовалась библиотека до версии, а затем требовалась версия некоторых библиотек JavaScript, которые были доступны только в формате npm. Поэтому теперь я включаю все зависимости javascript для клиентского приложения, используя npmDependencies, с плагином scalajs-bundler. Это сломало некоторые фасады скалайдов, которые привели к моему вопросу.
Я буду использовать фасад для log4javascript в качестве примера для этого вопроса.
Переменная log4javascript
- это объект верхнего уровня, используемый для доступа к остальной части API.
Когда js-библиотеки были включены в качестве веб-файлов, вот как был реализован фасад к 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.
Может ли кто-нибудь объяснить, какая связь существует, если таковая имеется, между именами объектов / классов / def / val scala и именами в модуле javascript при использовании аргумента «Пространство имен» для JSImport?
В соответствии с документацией 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
. Когда библиотека была включена в качестве веб-файла, определение выглядело так:
@js.native
@JSGlobal("log4javascript.AjaxAppender")
class AjaxAppender(url:String) extends Appender {
def addHeader(header:String, value:String):Unit = js.native
}
После перехода на npm мне пришлось поместить определение класса в объект верхнего уровня:
@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
}
Однако это также не связывает. Может ли кто-нибудь объяснить правильный способ определения класса, как указано выше? Или определение, вложенное в объект Log4JavaScript
, является единственным правильным способом сделать это?