【问题标题】:How to convert Javascript exported class to Kotlin/JS?如何将 Javascript 导出的类转换为 Kotlin/JS?
【发布时间】:2021-09-18 09:54:46
【问题描述】:

我是 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', 'obsidian'], factory);
  else if (typeof exports === 'object')
    factory(module.exports, require('obsidian'), 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 (_, Component, Plugin, 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 _;
}));

【问题讨论】:

  • ja snipper 确实在 _.SomePlugin = SomePlugin 中导出...这就是 umd/amd/plain 的东西。生成的代码执行后,您可以导入 SomePlugin。我不知道 kotlin/Js 或 obsidian,因此我现在无法从移动设备上真正确定答案,但尝试将这些 JsModule("obsidian") 更改为 JsModule("obsidian. plugin") 等。由于生成的 js 似乎没有从库中访问类,而是像访问所有这些类一样访问库...
  • @S.Janssen 嗨,感谢您抽出宝贵时间来帮助我。很高兴知道这是除了 commonjs 之外的所有内容,所以我切换到了 umd。我将使用更改后的代码更新我的问题。然而,使用“obsidian.plugin”会产生“找不到模块'obsidian.plugin'”的消息,而“obsidan”不会发生这种情况,所以我没有改变它。

标签: javascript kotlin kotlin-js kotlin-js-interop


【解决方案1】:

您可以在 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 中找到等效的 sn-p,因为这不是 Kotlin/JS 特定的问题)

对多个 @JsModule 声明进行分组

因为您要从同一个包中导入多个声明,而不是使用 @JsModule / @JsNonModule 注释多个签名,您必须创建一个单独的文件,并使用 @file:@JsModule("...") / @file:JsNonModule 对其进行注释:

@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()
}

Kotlin 的 ES5 与 Obsidian 的 ES6

此外,您的一些问题源于 Obsidian 的示例隐含地假设您的目标是 ES6(而 Kotlin 当前的目标是 ES5)。具体来说,这会影响您的插件如何导出其成员,以及如何实例化类。

继承

关于继承(因为YourPlugin 继承自Plugin),ES6 类自动使用所有参数初始化父类。这是 ES5 的原型继承不支持的东西。这就是为什么在上面的 sn-p 中,我们需要将appmanifest 参数显式传递给Plugin 类构造函数,并在您的特定插件的实现中传递它们:

class SomePlugin(
    app: Any,
    manifest: Any
) : Plugin(
    app,
    manifest
)

出口/模块系统

关于导出插件,Obsidian 期望 module.exportsexports.default 直接成为您的 Plugin 类。要实现这种精确的导出行为,需要满足几个条件,不幸的是有点麻烦: - 库目标需要是 CommonJS:output.libraryTarget = "commonjs" (not CommonJS2) - 为了防止创建间接级别,通常情况下,需要将导出的库设置为nulloutput.library = null - 要将您的插件导出为default,其类声明需要标记为@JsName("default")

【讨论】:

    猜你喜欢
    • 2019-02-19
    • 1970-01-01
    • 1970-01-01
    • 2020-04-30
    • 2023-03-03
    • 2019-03-12
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    相关资源
    最近更新 更多