如何解决如何将 Javascript 导出类转换为 Kotlin/JS? 无法解决obsidian对多个 @JsModule 声明进行分组Kotlin 的 ES5 与 Obsidian 的 ES6
我是 JS 和 Kotlin/JS 的新手。我从示例中为 Obsidian 的插件提供了以下最少的工作 Javascript 代码。它按预期工作:
var obsidian = require('obsidian');
class SomePlugin extends obsidian.Plugin {
onload() {
new obsidian.Notice('This is a notice!');
}
}
module.exports = Plugin;
我希望使用 Kotlin 来扩展这个插件,因为我知道这门语言,但是我在将它转换为 Kotlin/JS 时遇到了一些问题。到目前为止我的方法:
可以在 here on Github 中找到可运行的项目。运行 gradle build
以生成构建文件夹。它会在浏览器步骤中失败,但该步骤不是必需的。构建后生成的js文件可以在build\js\packages\main\kotlin\main.js
中找到。
main.kt
@JsExport
class SomePlugin: Plugin() {
override fun onload() {
Notice("This is a notice!")
}
}
@JsModule("obsidian")
@JsNonModule // required by the umd moduletype
external open class Component {
open fun onload()
}
@JsModule("obsidian")
@JsNonModule
external open class Plugin : Component {
}
@JsModule("obsidian")
@JsNonModule
external open class Notice(message: String,timeout: Number = definedExternally) {
open fun hide()
}
编辑:感谢@S.Janssen 的评论,我将模块类型切换为 umd
build.gradle.kts
plugins {
kotlin("js") version "1.5.20"
}
group = "de.example"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation(npm("obsidian","0.12.5",false))
}
kotlin {
js(IR) {
binaries.executable()
browser {
webpackTask {
output.libraryTarget = "umd"
}
}
}
}
tasks.withType<KotlinjsCompile>().configureEach {
kotlinoptions.moduleKind = "umd"
}
我实际上并不需要可以在 browser
中运行的结果,但是如果没有 browser
定义,它甚至不会生成 js 文件。对于 browser
部分,会抛出一个异常,表示 Can't resolve 'obsidian' in 'path\kotlin'
。但至少在 build/js/packages/test/kotlin/test.js
下创建了一个 .js 文件。然而,该代码与我预期的代码完全不同,也不被黑曜石接受为有效的插件代码。我还尝试了其他一些 gradle 选项。像“umd”、“amd”、“plain”、传统编译器而不是 IR、nodejs 而不是浏览器。但是没有任何东西可以创建可运行的 js 文件。错误信息不同。使用旧版编译器时,它需要 kotlin.js 文件,即使我将它放在文件夹旁边或将内容复制到脚本中,它也找不到。
如何获得与上面发布的 Javascript 代码功能类似的代码?我知道它会有开销,但目前生成的代码根据我的理解甚至没有定义或导出我的类。
我从 obisidan 调试器得到的错误信息:
Plugin failure: obsidian-sample-plugin TypeError: Object prototype may only be an Object or null: undefined
(function (root,factory) {
if (typeof define === 'function' && define.amd)
define(['exports','obsidian','obsidian'],factory);
else if (typeof exports === 'object')
factory(module.exports,require('obsidian'),require('obsidian'));
else {
if (typeof Component === 'undefined') {
throw new Error("Error loading module 'main'. Its dependency 'obsidian' was not found. Please,check whether 'obsidian' is loaded prior to 'main'.");
}if (typeof Plugin === 'undefined') {
throw new Error("Error loading module 'main'. Its dependency 'obsidian' was not found. Please,check whether 'obsidian' is loaded prior to 'main'.");
}if (typeof Notice === 'undefined') {
throw new Error("Error loading module 'main'. Its dependency 'obsidian' was not found. Please,check whether 'obsidian' is loaded prior to 'main'.");
}root.main = factory(typeof main === 'undefined' ? {} : main,Component,Plugin,Notice);
}
}(this,function (_,Notice) {
'use strict';
SomePlugin.prototype = Object.create(Plugin.prototype);
SomePlugin.prototype.constructor = SomePlugin;
function Unit() {
Unit_instance = this;
}
Unit.$Metadata$ = {
simpleName: 'Unit',kind: 'object',interfaces: []
};
var Unit_instance;
function Unit_getInstance() {
if (Unit_instance == null)
new Unit();
return Unit_instance;
}
function SomePlugin() {
Plugin.call(this);
}
SomePlugin.prototype.onload_sv8swh_k$ = function () {
new Notice('This is a notice!');
Unit_getInstance();
};
SomePlugin.prototype.onload = function () {
return this.onload_sv8swh_k$();
};
SomePlugin.$Metadata$ = {
simpleName: 'SomePlugin',kind: 'class',interfaces: []
};
_.somePlugin = SomePlugin;
return _;
}));
解决方法
您可以找到一个工作示例来说明您要做什么here。我将逐一介绍需要对您的代码进行的一些更改-此回复中的一个。
无法解决obsidian
Can't resolve 'obsidian' in 'path\kotlin'
的出现是因为 obsidian-api
包不是一个独立的库。相反,它只包含一个 obsidian.d.ts
文件,它是一个 TypeScript 声明文件。与其他语言的头文件类似,这个头文件不提供任何实现,而只提供库的签名和类型——这意味着 Kotlin/JS 的 webpack(或任何 JavaScript 工具,就此而言)将无法解决实际的实现。这是意料之中的,可以通过将模块声明为 external
来解决。为此,请在 Kotlin/JS 中创建一个名为 webpack.config.d
的目录,并添加一个包含以下内容的文件 01.externals.js
:
config.externals = {
obsidian: 'obsidian',};
(您实际上也可以在官方 sample-plugin configuration 中找到等效的代码段,因为这不是 Kotlin/JS 特定问题)
对多个 @JsModule
声明进行分组
因为您要从同一个包中导入多个声明,而不是用 @JsModule
/ @JsNonModule
注释多个签名,所以您必须创建一个单独的文件,并用 {{1 注释它}} / @file:@JsModule("...")
:
@file:JsNonModule
Kotlin 的 ES5 与 Obsidian 的 ES6
此外,您的一些问题源于这样一个事实,即 Obsidian 的示例隐含地假设您的目标是 ES6(而 Kotlin 当前的目标是 ES5)。具体来说,这在插件导出其成员的方式以及类的实例化方式方面会有所不同。
继承
关于继承(由于 @file:JsModule("obsidian")
@file:JsNonModule
open external class Component {
open fun onload()
open fun onunload()
}
open external class Plugin(
app: Any,manifest: Any
) : Component
open external class Notice(message: String,timeout: Number = definedExternally) {
open fun hide()
}
继承自 YourPlugin
),ES6 类会自动使用所有参数初始化父类。这在 ES5 的原型继承中是不支持的。这就是为什么在上面的代码片段中,我们需要显式地将 Plugin
和 Plugin
参数传递给 app
类构造函数,并在您的特定插件的实现中传递它们:
manifest
导出/模块系统
关于导出您的插件,Obsidian 希望 class SomePlugin(
app: Any,manifest: Any
) : Plugin(
app,manifest
)
或 module.exports
直接成为您的 exports.default
类。要实现这种精确的导出行为,需要满足几个条件,不幸的是,这有点麻烦:
- 库目标需要是 CommonJS:Plugin
(not CommonJS2)
- 通常情况下,为了防止创建间接级别,需要将导出的库设置为 output.libraryTarget = "commonjs"
:null
- 要将您的插件导出为 output.library = null
,其类声明需要标记为 default
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。