为什么需要这样一篇文章
我们知道 Kotlin 对 Jvm 的支持实在是太好了,以至于我们创建一个 Java 工程,配置一下 Kotlin 的编译插件和标准库就可以很轻松愉快的开始玩耍,什么互调用、什么单步调试都没有毛病——毕竟 KotlinJvm 与 Java 无论从使用上还是从生态上都尽可能的保持了一致,构建也主要用了 gradle,所以从 Java 到 Kotlin 的切换可谓是无缝衔接。
而 Kotlin 同样支持的 JavaScript 就似乎有点儿麻烦了,毕竟二者所处的生态差异略大,KotlinJs 仍然主要采用 gradle 构建,而 JavaScript 的话,例如 Node.js,就使用 npm/yarn 安装管理依赖了。想想可能还是有点儿别扭,你当然可以自己创建一个简单的 KotlinJs 工程,并且自己负责管理 nodemodules,但那样的话,nodemodules 的依赖并不会被 KotlinJs 直接依赖到,还需要管理 JavaScript 映射到 Kotlin 的接口依赖,例如 jQuery 在 Kotlinjs 侧就有一个接口库方便 Kotlin 以类型安全的方式调用,不过你还是要自己安装好 jQuery 才行,很麻烦对吧。
这一节我们将给大家展示如何搭建一个基于 Node.js 的相对完美的 KotlinJs 的开发环境,这个环境可以做到:
- 依赖只需要在 Gradle 中统一管理即可,node_modules 会被自动安装
- 右键运行 Kotlin 中的 main 函数,就像我们在 KotlinJvm 当中一样
- 单步调试 Kotlin 代码,全程对 JavaScript 的编译结果无感知
基于这个工程,大家就可以很愉快的测试 KotlinJs 的特性啦,就像我们在 KotlinJvm 上面那样,毫无违和感。
准备工作
首先,你需要一个 IntelliJ Idea Utilmate,俗称的 IU。为什么呢?因为我们需要 IDE 支持 Gradle,所以 WebStorm 就不行啦。
接着,你需要在 IU 中安装 NodeJS 插件,如图:
我的 IU 已经安装了 NodeJS 的插件,因此在左侧可以看到,如果你没有安装,那么点击 Browse repositories 搜索安装即可。安装完成后重启 IU。
最后,为了能够正常运行 Node.js 程序,请大家提前安装好 Node,这个就比较简单了,我就不多说啦。
创建工程
创建工程其实也比较简单,选 Gradle,再选择 Kotlin(JavaScript) 即可,后面的根据你的实际情况配置即可。
工程创建完成后,等待 Gradle sync 完成,会得到下图所示的工程目录结构,非常熟悉对不对:
开始调试
我们直接在 src/main/kotlin 下面创建一个目录,例如 com/bennyhuo/kotlin/js,创建一个 Main.kt 文件,写下著名的一小步:
代码语言:javascript复制fun main() {
println("Hello")
}
然后,这时候你就可以看到 IDE 提示你这个东西可以直接运行:
点击这个按钮,或者右键 main 函数,你都可以看到运行它的选项,点击之~
首先你要选择一个合适的 node 环境,其次这个图提示我们要正确的 JavaScript 路径,由于我们实际上运行的是 Kotlin 编译生成的 JavaScript 文件,因此不要 care 下面的这个 Error,直接点击 run,下一个对话框再点击 “Continue Anyway”。
当然这时候肯定是会报错的,它会报错说没有 kotlin 这个东西,因为默认情况下 KotlinJs 编译得到的 JavaScript 是 plain 类型的,引用的依赖都需要作为全局变量出现。我们要配置它为 commonjs 或者 umd,在 gradle 最后填下以下配置:
代码语言:javascript复制compileKotlin2Js {
kotlinOptions.moduleKind = 'commonjs'
kotlinOptions.sourceMap = true
kotlinOptions.metaInfo = true
}
其他的两项配置主要是为了调试用,比如单步调试映射代码位置等等。
这时候你当然可以选择继续运行了,不过还是会报错,虽然编译的结果已经能够主动去 require('kotlin')
,但这个 kotlin 在哪儿呢?我们并没有主动去安装它,甚至我们从一开始就声称是基于 node.js 的,我们连 npm init 都没有做过,我们所有的依赖都在 gradle 当中配置:
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-js"
testImplementation "org.jetbrains.kotlin:kotlin-test-js"
}
这怎么能运行得起来呢?
因此我们还需要一个插件:
代码语言:javascript复制apply plugin: 'org.jetbrains.kotlin.frontend'
为了依赖这个插件,我们需要添加一个仓库,毕竟这个插件还没有发布到 jcenter 的公共仓库或者 gradle 的插件仓库:
代码语言:javascript复制buildscript {
repositories {
maven {
url "https://dl.bintray.com/kotlin/kotlin-eap"
}
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-frontend-plugin:0.0.45"
}
}
这样我们耐心的 sync 一下 gradle,你就会发现 build 目录下多了一些东西:
而这正包含了我们所需要的运行时依赖。kotlin frontend 这个插件会帮我们把 gradle 中配置的依赖也一并通过 npm 安装,它还可以在 gradle 当中为 npm 配置依赖:
代码语言:javascript复制kotlinFrontend {
npm {
dependency "style-loader" // production dependency
devDependency "karma" // development dependency
}
}
还支持 webpack 。
好啦,这时候再运行咱们的程序,就会得到结果:
体验一把 KotlinJs 的协程
首先添加依赖:
代码语言:javascript复制implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.1.1'
接着,编写我们的 Kotlin 代码:
代码语言:javascript复制fun log(msg: Any) {
println("[${Date().toLocaleTimeString()}] $msg")
}
fun main() {
log(1)
GlobalScope.launch {
log(3)
val result = withContext(coroutineContext) {
delay(1000)
log(4)
"HelloWorld"
}
log("5. $result")
}
log(2)
}
运行结果如下:
单步调试无需任何特殊配置,直接打断点,点 debug 运行的按钮即可:
我们可以看到 result 的值正是协程内部返回的 HelloWorld。
是不是很美?
小结
虽然,在最开始运行的时候会被配置 JavaScript 文件的路径恶心一把,但这个并不会有太多影响,整体体验已经非常不错了。嗯,公司正好有个做了半年的 NodeJs 项目,感觉可以玩一把了,反正组里用啥我说了算 ٩(๑>◡<๑)۶