代码之家  ›  专栏  ›  技术社区  ›  Sergey Okatov

Angular 6字体脚本与Kotlinks集成

  •  4
  • Sergey Okatov  · 技术社区  · 6 年前

    我刚刚成功地将Kotlin编译的javascript模块导入到一个Angular6字体脚本文件中。这不容易,结果让我困惑。我想知道是否存在更优雅的方式。

    最初我用的是Kotlin文件:

    package com.example.test
    
    data class SomeInterface(
        var id: String? = null,
        var value: String? = null
    ) {
    }
    

    它很好地编译成以下的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 _;
    }));
    

    在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;
    

    这是使用类的最小强制代码 SomeInterfac 在包裹里 com.example.test 生成到模块 TestKotlinCompiled .

    这里的问题如下。

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

    const 对于 new SomeInterface()

    type 对于 let x: SomeInterface;

    所有这些看起来都很粗糙。 我想要更简单的 import {SomeInterface} from '../../generated/TestKotlinCompiled' using namespace com.example.test 没有 康斯特 类型 . 那么,有没有一种方法可以简化我上面的代码?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Sergey Okatov    6 年前

    我成功地在角度上提高了Kotlinjs的一点点可用性。我把实验安排在 https://github.com/svok/kotlin-multiplatform-sample

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

    然后我们添加到package.json…

    {
      "dependencies": {
        "kotlin": "^1.3.21",
        "proj-common": "file:../build/javascript-compiled"
      }
    }
    

    proj common是我们编译的Kotlin模块。Kotlin JS文件的构建路径。

    因此,在typescript中,我们只使用一个以上的NPM模块

    import {sample} from 'proj-common/proj-common';
    
    // For class Sample
    sample = new sample.Sample();
    
    // For object Platform
    platform = sample.Platform;
    

    编译很好,没有必要使用 // @ts-ignore

    更新

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

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

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

    {
      "dependencies": {
        "proj-common": "file:../build/npm"
      }
    }
    

    在typescript文件中:

    import {sample} from 'proj-common';
    
    // For class Sample
    sample = new sample.Sample();
    
    // For object Platform
    platform = sample.Platform;
    

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