如何在Kotlin1.4多平台项目中设置gradle任务以在build.gradle.kts中创建fatJar

问题描述

我一直在寻找一种方法来创建一个 jar,其中包含我需要拥有一个包含前端和后端的完全工作的应用程序的一切。 fatJar 是解决方案,但是如何在创建这个 fatJar 的 kotlin/多平台项目中创建 gradle 任务? 我找不到开箱即用的解决方案。我不得不修改和扩展找到的任务以获得我想要的结果。

解决方法

所以这是我的任务:

import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack
import org.gradle.jvm.tasks.Jar

val kotlinVersion = "1.4.0"
val serializationVersion = "1.0.0-RC"
val ktorVersion = "1.4.0"

plugins {
    kotlin("multiplatform") version "1.4.0"
    application //to run JVM part
    kotlin("plugin.serialization") version "1.4.0"
    id("com.github.johnrengelman.shadow") version "6.1.0"
}

group = "com.bantolomeus"
version = "0.1"

repositories {
    maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
    mavenCentral()
    jcenter()
    maven("https://kotlin.bintray.com/kotlin-js-wrappers/") // react,styled,...
}

kotlin {
    jvm {
        withJava()
    }
    js {
        browser {
            binaries.executable()
        }
    }
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation(kotlin("stdlib-common"))
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion")
                implementation("io.ktor:ktor-client-core:$ktorVersion")
//                implementation("com.github.jengelman.gradle.plugins:shadow:6.1.0")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }

        val jvmMain by getting {
            dependencies {
                implementation("io.ktor:ktor-serialization:$ktorVersion")
                implementation("io.ktor:ktor-server-core:$ktorVersion")
                implementation("io.ktor:ktor-server-netty:$ktorVersion")
                implementation("ch.qos.logback:logback-classic:1.2.3")
                implementation("io.ktor:ktor-websockets:$ktorVersion")
                implementation("org.litote.kmongo:kmongo-coroutine-serialization:4.1.1")
            }
        }

        val jsMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-js:$ktorVersion") //include http&websockets

                //ktor client js json
                implementation("io.ktor:ktor-client-json-js:$ktorVersion")
                implementation("io.ktor:ktor-client-serialization-js:$ktorVersion")

                implementation("org.jetbrains:kotlin-react:17.0.1-pre.148-kotlin-1.4.21")
                implementation("org.jetbrains:kotlin-react-dom:17.0.1-pre.148-kotlin-1.4.21")
                implementation(npm("react","17.0.1"))
                implementation(npm("react-dom","17.0.1"))
            }
        }
    }
}

application {
    mainClassName = "ServerKt"
}

// include JS artifacts in any JAR we generate
tasks.getByName<Jar>("jvmJar") {
    val taskName = if (project.hasProperty("isProduction")) {
        "jsBrowserProductionWebpack"
    } else {
        "jsBrowserDevelopmentWebpack"
    }
    val webpackTask = tasks.getByName<KotlinWebpack>(taskName)
    dependsOn(webpackTask) // make sure JS gets compiled first
    from(File(webpackTask.destinationDirectory,webpackTask.outputFileName)) // bring output file along into the JAR
}

tasks {
    withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
        kotlinOptions {
            jvmTarget = "1.8"
        }
    }
}

distributions {
    main {
        contents {
            from("$buildDir/libs") {
                rename("${rootProject.name}-jvm",rootProject.name)
                into("lib")
            }
        }
    }
}

// Alias "installDist" as "stage" (for cloud providers)
tasks.create("stage") {
    dependsOn(tasks.getByName("installDist"))
}

tasks.getByName<JavaExec>("run") {
    classpath(tasks.getByName<Jar>("jvmJar")) // so that the JS artifacts generated by `jvmJar` can be found and served
}

// tasks to create an executable jar with all components of the app
tasks.getByName<ShadowJar>("shadowJar") {
    val webpackTask = tasks.getByName<KotlinWebpack>("jsBrowserProductionWebpack")
    dependsOn(webpackTask) // make sure JS gets compiled first
    from(File(webpackTask.destinationDirectory,webpackTask.outputFileName)) // bring output file along into the JAR
    archiveBaseName.set("shadow")
    mergeServiceFiles()
    manifest {
        attributes["Main-Class"] = "ServerKt"
    }
}

// task to create executable jar during build task
//tasks {
//    build {
//        dependsOn(shadowJar)
//    }
//}

我注释掉了最后一部分,不要总是在构建过程中创建 shadowJar (fatJar),因为这只是需要时间,在我的情况下不需要。 相关任务是最后一个没有被注释掉的任务。 我还发布了我的整个 build.gradle.kts 文件,因为您需要一些导入、插件和依赖项(与 jengelman 的 shadowJar 相关的所有内容)。

我希望遇到同样问题的其他人会觉得这有帮助。