[Ktjs] 发布自己的 Ktjs 库

使用 Kotlin 来写 js 代码固然很爽,但是 Ktjs 体系和 js 体系本质上的差别还是使得两者在融合上产生了一定的麻烦,当我打算写一个 Ktjs 的库时,发布和使用就不像在 jvm 体系下那么方便了。本篇就来讲一下具体的操作,以方便对 Ktjs 后续使用,也方便对各种组件库进行沉淀。


为了方便起见,我们先建个私库用来练习,避免直接发到公有库造成污染。

自己搭一个 Nexus 还是很方便的,这里需要注意的是,自己搭的时候务必额外加一个 npm-proxy,以免用私库时拉不到公库的数据。一般来说将公有库地址设为 https://registry.npmjs.org,也可以用国内镜象。这里我在自己本地搭建,搭完后 npm 远程路径为 http://0.0.0.0:8081/repository/npm-releases/


下面来建立一个 Ktjs 项目,在 IntelliJ IDEA 内选择新建项目,并且在 Gradle 分类内选择建立 Kotlin/JS 项目,完成后目录结构如下所示:

| -- project
|    | -- build.gradle
|    | -- gradle.properties
|    | -- package.json
|    | -- settings.gradle
|    | -- src
|    |    | -- main
|    |    |    | -- kotlin
|    |    |    | -- resources
|    |    | -- test
|    |    |    | -- kotlin
|    |    |    | -- resources

为了方便发布项目,修改一下 build.gradle,这里直接给出完整的的文件内容:

plugins { id 'kotlin2js' version '1.3.31' }
apply plugin: 'maven-publish'
group 'com.rarnu'
version '0.0.1'

repositories {
    mavenCentral()
    maven { url 'https://kotlin.bintray.com/ktor' }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-js"
}

compileKotlin2Js {
    kotlinOptions.moduleKind = 'commonjs'
}

build.doLast() {
    copy {
        from new File("package.json")
        into "${projectDir}/publish"
    }
    copy {
        includeEmptyDirs = false
        from new File("${project.buildDir}/classes/kotlin/main")
        into "${projectDir}/publish"
    }
    copy {
        includeEmptyDirs = false
        from new File("src/main/resources")
        into "${projectDir}/publish"
    }
}
task sourcesJar(type: Jar) {
    classifier = 'sources'
    from sourceSets.main.allSource
}
publishing {
    publications {
        maven(MavenPublication) {
            artifact "${project.buildDir}/libs/${project.name}-${project.version}.jar"
            artifact sourcesJar
        }
    }
    repositories {
        maven {
            url nexusUploadUrl
            credentials {
                username nexusAccount
                password nexusPassword
            }
        }
    }
}

其中需要注意的是,Ktjs 发布到 npm 时,不应当自身带有依赖,而是应当使用 package.json 来管理依赖,因此编译模式需要设置为 commonjs,如果设置为 umd 就会带上依赖,在引用时就会出现找不到依赖库的问题。

其次是 build.doLast() 方法,它指出了在构建完成后,需要拷贝一些文件用作 npm 发布的文件,把这些文件拷到 publish 目录下。最后就是发布到 Nexus 的方法了,artifact sourcesJar 指出了发布时需要同时发布源码,如果不想开源可以去掉源码包,不会影响用户的使用。

需要特别说明的是,Ktjs 由于使用 Kotlin 语言,并且开发场景通常也是在 Kotlin 环境下,它无法直接与 js 兼容,而 JetBrains 为了能让 IDE 针对 Ktjs 库可以无缝的衔接,实现代码提示,重构等诸多方便开发的特性,他们提供了 kjsm 的映射方式,即可以把 js 方法映射成 Kotlin 方法,从而在 IDE 内被识别,当你引用一个 JS 库时,由于 kjsm 的存在,IDE 即可以从中读取函数并且在开发时给出提示。

话说事后想想这个 kjsm 的含义,还真是耐人寻味啊,Kotlin, JS, SM.... 难道是在劝退么:(


现在可以开始编写 Ktjs 代码了,Kotlin 库是默认自带的,在 npm 内引用为 "kotlin": "^1.3.20",它包含了大量 Kotlin 特有的高阶函数,所以整体写起来还是很爽的。之前我写过一篇文章,来讲述如何使用现有的 js 库(点击查看),这篇文章在面对复杂的库的时候有点无能为力,我们需要新的包装方法。

compressing 库为例,用来完成压缩/解压,可以这样包装:

external fun require(module: String): dynamic
private val zip = require("compressing").zip

fun zip(zipFile: String, src: String, callback: (Boolean) -> Unit) =
    zip.compressDir(src, zipFile).then { callback(true) }.catch { callback(false) }

fun unzip(zipFile: String, dest: String, callback: (Boolean) -> Unit) =
    zip.uncompress(zipFile, dest).then { callback(true) }.catch { callback(false) }

包装完成后,就可以在后面直接使用包装后的方法了:

fun main() {
    zip("sample.zip", "sample") {
        println("result => $it")
    }
}

同理,可以对更复杂的库进行包装,以达到方便使用的目的。总之就一句话,Ktjs 是可以直接使用 js 模块的,千万不要想不开去造更多的轮子。


好了,现在可以尝试编译一下代码,执行 gradle build,完成后会生成 publish 目录,里面的文件如下:

| -- publish
|    | -- package.json
|    | -- sample.js
|    | -- sample.meta.js
|    | -- sample
|    |    | -- sample.kjsm

有了这个目录后,其实已经可以发布到 npm 私库了,不过在此之前先发布到 Nexus 吧。

$ gradle clean build publish

现在我们可以在 Nexus 私库上看到发布的东西,当然这个库现在还无法直接使用,因为它只有 Kotlin 部分,还缺少 JS 部分,我们得发布 JS 部分到 npm。

我们可以在 package.json 内加入发布源,如下所示:

{
  "name": "sample",
  "version": "0.0.1",
  "description": "",
  "author": "rarnu",
  "license": "MIT",
  "main": "sample.js",
  "dependencies": {
    "kotlin": "^1.3.20",
  },
  "publishConfig": {
    "registry": "http://0.0.0.0:8081/repository/npm-releases/"
  }
}

registry 指出的是刚才建立好的 npm 私库路径,即表示发布到这里。发布时需要身份验证,我们需要先登录一私库:

$ npm login –registry http://0.0.0.0:8081/repository/npm-releases/

这时会弹出输入身份信息,如果是默认安装的 Nexus,用户名为 admin,密码为 admin123,再输入一个邮箱就可以完成登录了。看到登录成功的提示后,可以执行 npm publish 命令予以发布。这样我们就可以在 Nexus 里看到这个 npm 库了。


最后就是如何用这个库,我们发布自己的库,最终目的还是为了用它,其实用法比发布方法简单多了。

同样新建一个 Ktjs 的项目,在 build.gradle 里加入以下代码:

implementation "com.rarnu:sample:0.0.1"

这里是常见的三段式引用方法,取决于发布库时的配置,同时在 package.json 里加入以下代码:

"dependencies": {
    "sample": "^0.0.1"
  }

然后在 package.json 所在目录执行安装命令即可,由于是私库,需要先设置请求的 URL:

$ npm config set registry http://0.0.0.0:8081/repository/npm-all/
$ npm install

这样就拉到了我们发布的库,在 Ktjs 内也完成了引用,可以按常规的 Kotlin 开发方式来进行 JS 的开发了。

你可能感兴趣的:([Ktjs] 发布自己的 Ktjs 库)