如何在Kotlin多平台/Ktor应用程序的Fat Jar或Docker容器中包含交叉编译的客户端JS代码



不久前,我继承了一个小型Kotlin Multiplatform/Ktor应用程序,并开始部署。我对这个框架非常陌生,作为一个整体,我遇到了一些问题,包括Fat Jar或Docker Container中的交叉编译客户端JS。我不完全确定这是否应该在Fat Jar中,或者我是否将JS包含在Docker容器中,我只知道它没有按预期工作,我找不到任何好的文档或这些问题的答案。

我得到的具体错误是:这里的HTML页面错误:

<script>
Application.main();
</script>

未捕获引用错误:应用程序未定义

页面工作正常,在Intellij IDEA中运行项目时调用该函数,但当我从Fat Jar中创建Docker Image或在IDEA之外运行它时,它就不再工作了。以下是Kotlin的源文件,仅供后人使用:

(在应用程序.kt(

fun main() {

这是我的Dockerfile:

FROM gradle:7-jdk11 AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle buildFatJar --no-daemon
FROM openjdk:11
EXPOSE 8080:8080
RUN mkdir /app
COPY --from=build /home/gradle/src/build/libs/MyApp.jar /app/MyApp.jar
ENTRYPOINT ["java","-jar","/app/MyApp.jar"]

这是我的build.gradle.kts:

import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack
val kotlinVersion = "1.7.20-Beta"
val ktorVersion = "2.0.3"
val kotlinxHtmlVersion = "0.8.0"
val kotlinxCoroutinesVersion = "1.3.8" //curr: 1.6.4
val kotlinWrappersVersion = "1.0.0-pre.354"
val logbackVersion = "1.2.3" //11
plugins {
id("io.ktor.plugin") version "2.1.3"
kotlin("multiplatform") version "1.7.20-Beta"
application
}
application {
mainClass.set("com.example.application.ServerKt")
}
ktor {
fatJar {
archiveFileName.set("MyApp.jar")
}
}
group = "com.example"
version = "1.0-SNAPSHOT"
repositories {
jcenter()
mavenCentral()
}
dependencies {
implementation("org.apache.commons:commons-email:1.5")
}
kotlin {
jvm {
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
withJava()
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
js {
browser {
binaries.executable()
dceTask {
keep("Application.columnIndex", "Application.prepareTable")
}
}
}
sourceSets {...} // excluded for brevity
}
// include JS artifacts in any JAR we generate
tasks.getByName<Jar>("jvmJar") {
val taskName = if (project.hasProperty("isProduction") || project.gradle.startParameter.taskNames.contains("installDist")) {
"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") {
// so that the JS artifacts generated by `jvmJar` can be found and served
classpath(tasks.getByName<Jar>("jvmJar")) 
}

在运行了运行buildFatJar的docker文件后,它将创建的Jar复制到docker映像中,然后我手动添加静态文件&一些.json文件和所有这些文件都可以正常工作;然而,我一辈子都无法让交叉编译的JS工作或在应用程序中被引用。

TLDR:如何将交叉编译的JS包含在Fat Jar本身或Docker容器中?

我已经试过了:https://stackoverflow.com/questions/61245847/create-fat-jar-from-ktor-kotlin-multiplatform-project-with-kotlin-gradle-dsl以及这个的许多变体加上其他几个堆栈溢出答案,似乎对我来说什么都不起作用

我尝试了几种不同的方法来将Cross编译的JS放入fat jar中,当失败时,我尝试将build/js/目录的内容复制到docker容器中,看看这是否允许它运行,但这两种方法都不适用。

我一整天都在寻找答案,但一无所获,所以任何建议都会很有帮助,谢谢!

事实证明答案其实很简单。需要将名为Application.js的文件从/build/didistributions移到项目中,并放置在服务器可以看到&提供它,即/static/script。

把这件事留在这里,因为这件事在任何地方都没有记录,我花了大约4个小时寻找解决方案,所以我希望这能在未来帮助人们。

最新更新