Angular 6打字稿与KotlinJs的集成

Ser*_*tov 10 javascript requirejs kotlin typescript angular

我刚刚设法在角度6打字稿文件中导入Kotlin编译的javascript模块。这并不容易,结果使我感到困惑。我想知道是否存在更优雅的方式。

最初,我使用Kotlin文件:

package com.example.test

data class SomeInterface(
    var id: String? = null,
    var value: String? = null
) {
}
Run Code Online (Sandbox Code Playgroud)

可以很好地编译为以下JavaScript

(function (root, factory) {
  if (typeof define === 'function' && define.amd)
    define(['exports', 'kotlin'], factory);
  else if (typeof exports === 'object')
    factory(module.exports, require('kotlin'));
  else {
    if (typeof kotlin === 'undefined') {
      throw new Error("Error loading module 'TestKotlinCompiled'. Its dependency 'kotlin' was not found. Please, check whether 'kotlin' is loaded prior to 'TestKotlinCompiled'.");
    }
    root.TestKotlinCompiled = factory(typeof TestKotlinCompiled === 'undefined' ? {} : TestKotlinCompiled, kotlin);
  }
}(this, function (_, Kotlin) {
  'use strict';
  var Kind_CLASS = Kotlin.Kind.CLASS;
  function SomeInterface(id, value) {
    if (id === void 0)
      id = null;
    if (value === void 0)
      value = null;
    this.id = id;
    this.value = value;
  }
  SomeInterface.$metadata$ = {
    kind: Kind_CLASS,
    simpleName: 'SomeInterface',
    interfaces: []
  };
  SomeInterface.prototype.component1 = function () {
    return this.id;
  };
  SomeInterface.prototype.component2 = function () {
    return this.value;
  };
  SomeInterface.prototype.copy_rkkr90$ = function (id, value) {
    return new SomeInterface(id === void 0 ? this.id : id, value === void 0 ? this.value : value);
  };
  SomeInterface.prototype.toString = function () {
    return 'SomeInterface(id=' + Kotlin.toString(this.id) + (', value=' + Kotlin.toString(this.value)) + ')';
  };
  SomeInterface.prototype.hashCode = function () {
    var result = 0;
    result = result * 31 + Kotlin.hashCode(this.id) | 0;
    result = result * 31 + Kotlin.hashCode(this.value) | 0;
    return result;
  };
  SomeInterface.prototype.equals = function (other) {
    return this === other || (other !== null && (typeof other === 'object' && (Object.getPrototypeOf(this) === Object.getPrototypeOf(other) && (Kotlin.equals(this.id, other.id) && Kotlin.equals(this.value, other.value)))));
  };
  var package$com = _.com || (_.com = {});
  var package$example = package$com.example || (package$com.example =     {});
  var package$test = package$example.test || (package$example.test = {});
  package$test.SomeInterface = SomeInterface;
  Kotlin.defineModule('TestKotlinCompiled', _);
  return _;
}));
Run Code Online (Sandbox Code Playgroud)

在package.json中,我添加"kotlin": "^1.2.70",到“依赖项”部分。在角度组件中,我必须使用此类代码进行导入。

import * as TestKotlinCompiled from "../../generated/TestKotlinCompiled";

// @ts-ignore
const SomeInterface = TestKotlinCompiled.com.example.test.SomeInterface;
// @ts-ignore
type SomeInterface = TestKotlinCompiled.com.example.test.SomeInterface;
Run Code Online (Sandbox Code Playgroud)

这是在模块生成SomeInterfac的包中使用类的最少必需代码。com.example.testTestKotlinCompiled

这里的问题如下。

// @ts-ignore 这是必需的,因为在编译时ts-comiler看不到正在导入的模块的内容。

const 是必需的 new SomeInterface()

type 是必需的 let x: SomeInterface;

所有这些看起来都很骇人。我希望像import {SomeInterface} from '../../generated/TestKotlinCompiled' using namespace com.example.test没有const和那样容易一些 type。那么,有没有一种方法可以简化我的上述代码?

Ser*_*tov 2

我成功地提高了 Angular 中 KotlinJs 的一点可用性。我在https://github.com/svok/kotlin-multiplatform-sample中进行了实验

\n\n

首先,我们必须在 Gradle 中创建一个多平台子模块。我们生成 js 文件(以及其他可能的平台)。

\n\n

然后我们添加到 package.json...

\n\n
{\n  "dependencies": {\n    "kotlin": "^1.3.21",\n    "proj-common": "file:../build/javascript-compiled"\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

proj-common 是我们编译的 Kotlin 模块。那里的路径是构建 kotlin-js 文件的位置。

\n\n

因此,在 typescript 中我们只需要再使用一个 npm 模块

\n\n
{\n  "dependencies": {\n    "kotlin": "^1.3.21",\n    "proj-common": "file:../build/javascript-compiled"\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

编译顺利,无需使用\xd1\x81essity// @ts-ignore

\n\n

更新

\n\n

在上面的解释中存在从属依赖的问题。它们未导出,但并非所有子依赖项在 npm 存储库中都有其等效项。下面的代码解决了这个问题。

\n\n
tasks {\n    task<Sync>("assembleWeb") {\n        val dependencies = configurations.get("jsMainImplementation").map {\n            val file = it\n            val (tDir, tVer) = "^(.*)-([\\\\d.]+-\\\\w+|[\\\\d.]+)\\\\.jar$"\n                .toRegex()\n                .find(file.name)\n                ?.groupValues\n                ?.drop(1)\n                ?: listOf("", "")\n            var jsFile: File? = null\n            copy {\n                from(zipTree(file.absolutePath), {\n                    includeEmptyDirs = false\n                    include { fileTreeElement ->\n                        val path = fileTreeElement.path\n                        val res = (path.endsWith(".js") || path.endsWith(".map"))\n                                && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))\n                        if (res && path.endsWith(".js") && ! path.endsWith(".meta.js")) jsFile = fileTreeElement.file\n                        res\n                    }\n                })\n                into("$npmTarget/$tDir")\n            }\n            jsFile?.also { packageJson(tDir, it, tVer) }\n            tDir to jsFile\n        }\n            .filter { it.second != null }\n            .map { it.first to it.second!! }\n            .toMap()\n\n        packageJson(npmDir, File(jsOutputFile), project.version.toString(), dependencies)\n        dependsOn("jsMainClasses")\n    }\n\n    assemble.get().dependsOn("assembleWeb")\n}\n\nfun packageJson(dir: String, jsFile: File, version: String, dependencies: Map<String, File> = emptyMap()) {\n    val deps = dependencies.map {\n        """"${js2Name(it.value)}": "file:../${it.key}""""\n    }.joinToString(",\\n            ")\n    val text = """\n        {\n          "name": "${js2Name(jsFile)}",\n          "version": "${version}",\n          "main": "./${jsFile.name}",\n          "dependencies": {\n            ${deps}\n          }\n        }\n    """.trimIndent()\n    File("$npmTarget/$dir/package.json").apply {\n        if (parentFile.exists()) {\n            parentFile.delete()\n        }\n        parentFile.mkdirs()\n        writeText(text)\n    }\n}\n\nfun js2Name(jsFile: File) = jsFile.name.replace("""\\.js$""".toRegex(), "")\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后,从前面的子模块导入:

\n\n
{\n  "dependencies": {\n    "proj-common": "file:../build/npm"\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在打字稿文件中:

\n\n
import {sample} from \'proj-common/proj-common\';\n\n// For class Sample\nsample = new sample.Sample();\n\n// For object Platform\nplatform = sample.Platform;\n
Run Code Online (Sandbox Code Playgroud)\n\n

示例项目请参见https://github.com/svok/kotlin-multiplatform-sample

\n\n

更新2

\n\n

现在,您可以使用 kotlin 公共子项目创建全栈项目,就像在 gradle 中附加插件一样简单

\n\n
plugins {\n    id("com.crowdproj.plugins.jar2npm")\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这个插件会在编译过程中自动将你所有的kotlin-js jar包注入到你的node_modules中。

\n\n

https://github.com/svok/kotlin-multiplatform-sample项目现已使用此插件重写。请参阅proj-angularfront子模块。

\n