惯用的 Kotlin2JS Gradle 设置

Posted

技术标签:

【中文标题】惯用的 Kotlin2JS Gradle 设置【英文标题】:Idiomatic Kotlin2JS Gradle setup 【发布时间】:2019-08-09 11:11:06 【问题描述】:

我想在 Kotlin 中编写一个 javascript 库,使用 Gradle 作为构建工具,并使用 Kotlin 作为配置语言。最后,我想获得一个可以用作独立库的单个 JS 文件,即将 Kotlin 库的(所有必需部分)捆绑到其中。

使这项工作看起来像的最小设置是什么?具体来说,如何获取捆绑的 Kotlin 库?


这是我目前所拥有的。

https://kotlinlang.org/docs/tutorials/javascript/getting-started-gradle/getting-started-with-gradle.html 只使用 Groovy 来配置 Gradle。它还将buildscriptapply plugin 语句结合使用,我的总体印象是这被认为是一种遗留方法,而plugins 部分将是首选方法。

https://kotlinlang.org/docs/reference/using-gradle.html#targeting-javascript 有 Kotlin 脚本。 settings.gradle 的代码 sn-p 在 Groovy 和 Kotlin 之间没有切换,但在我的 settings.gradle.kts 中似乎无需修改即可工作。这将创建一个文件js/build/classes/kotlin/main/$project.name.js,看起来像这样(带有moduleKind = "commonjs"):

(function (_, Kotlin)  … (module.exports, require('kotlin')));

所以我可以看到它包含我的源代码的转译版本,但它不会自行运行;它将需要标准库的副本。我可以将其添加为依赖项

dependencies 
    compile("org.jetbrains.kotlin:kotlin-stdlib-js")
    testImplementation("org.jetbrains.kotlin:kotlin-test-js")

但仅凭这一点还不足以使标准库最终出现在输出中。我想我也许可以使用kotlin npm package,但我更愿意自动将这些来源合并为一个。

我还尝试使用禁用noStdlib 设置

tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile> 
    kotlinOptions 
        noStdlib = false
    

其中包含相当多的猜测,因为执行此类操作的示例倾向于使用 Groovy 表示法和 compileKotlin2Js 块,如果我的构建脚本在 Kotlin 中,则会导致语法错误。所以上面我得到一个编译器错误:

w: Unable to find kotlin-stdlib-js.jar in the Kotlin home directory.
Pass either '-no-stdlib' to prevent adding it to the classpath, or
the correct '-kotlin-home'

那么我如何让那个使用作为依赖项提供的标准库呢?这甚至是正确的方法吗?

https://blog.kotlin-academy.com/kotlin-js-configuration-made-simple-ef0e361fcd4 和它引用的@​​987654325@ 描述了另一种帮助 Web 开发的插件,但同样所有的例子都是 Groovy 的,我什至无法解决这个插件。我试过像

plugins 
    id("org.jetbrains.kotlin.frontend").version("0.0.45")


repositories 
    jcenter()
    maven 
        url = java.net.URI("https://dl.bintray.com/kotlin/kotlin-eap")
    

Another blog post 建议一些Gist 的命令,据称这些命令会从依赖项中提取 JavaScript 文件并将它们放入我的输出目录。我可以想象这会奏效,但我还不愿意接受这是解决问题的最佳方式,没有更精简的方式来实现这一结果。

【问题讨论】:

【参考方案1】:

可以使用 Webpack 来创建包含所有依赖项的单个 JS。

https://github.com/eggeral/kotlin-single-js-file-lib 展示了一个完整的例子

    确保 KotlinJS 编译器使用 webpack 可以理解的模块系统。

    tasks.withType<Kotlin2JsCompile> 
        kotlinOptions 
            moduleKind = "umd"
        
    
    

    将所有依赖复制到构建目录中的某个位置

    task<Copy>("assembleJsLib") 
        configurations.compile.get().resolve().forEach  file: File ->
            from(zipTree(file.absolutePath), 
                includeEmptyDirs = false
                include  fileTreeElement ->
                    val path = fileTreeElement.path
                    (path.endsWith(".js") || path.endsWith(".js.map")) && (path.startsWith("META-INF/resources/") ||
                            !path.startsWith("META-INF/"))
                
            )
        
        from(tasks.withType<ProcessResources>().map  it.destinationDir )
        into("$buildDir/js")
    
        dependsOn("classes")
    
    

    使用 com.moowork.node 插件运行 Webpack。

    import com.moowork.gradle.node.task.NodeTask
    
    plugins 
        id("kotlin2js") version "1.3.21"
        id("com.moowork.node") version "1.2.0"
    
    
    node 
        download = true
    
    
    task<NodeTask>("webpack") 
        dependsOn("npm_install")
        setScript(File("$projectDir/node_modules/webpack/bin/webpack"))
    
    

    确保一切都在gradle build上执行

    tasks 
        named("webpack")  dependsOn("assembleJsLib") 
        assemble  dependsOn("webpack") 
    
    

    为 Npm 创建一个最小的package.json

    
        "devDependencies": 
            "webpack": "^4.29.0",
            "webpack-cli": "^3.2.1"
        
    
    

    创建一个最小的webpack.config.js

    const path = require('path');
    
    module.exports = 
        mode: 'development',
        devtool: 'source-map',
        entry: path.resolve(__dirname, 'build/classes/kotlin/main/kotlin-lib.js'),
        resolve: 
            "modules": [
                path.resolve(__dirname, 'build/js'),
                "node_modules"
            ]
        ,
        output: 
            filename: "kotlin-lib.js",
            libraryTarget: "umd",
            path: path.resolve(__dirname, 'build/webpack'),
        
    
    ;
    

【讨论】:

以上是关于惯用的 Kotlin2JS Gradle 设置的主要内容,如果未能解决你的问题,请参考以下文章

Gradle Docker 下载依赖项

Android开发:《Gradle Recipes for Android》阅读笔记(翻译)6.1——推荐配置

无效的 splitapkbundle。捆绑目标未知语言:[gr]

Mac 安装 gradle

Linux安装Gradle

cordova Gradle: not installed