Kotlin/JS — 是一个将Kotlin代码编译为JavaScript的编译器,允许用Kotlin语言创建前端应用程序和网页界面。与TypeScript不同,Kotlin/JS提供严格的静态类型、协程支持以及与Kotlin Multiplatform的无缝集成。从Kotlin 1.8开始,编译器使用基于IR的后端来生成优化的JavaScript代码。根据JetBrains, 2025的数据,Kotlin/JS支持通过自动生成.d.ts文件与NPM生态系统和TypeScript集成。
要点概述
Kotlin/JS — 是Kotlin编译器的三个后端之一(与JVM和Native并列),用于将Kotlin代码翻译为JavaScript。由JetBrains开发的Kotlin/JS允许用具有严格静态类型的语言编写网页应用程序,同时通过外部声明机制保持对庞大JavaScript库生态系统的访问。自Kotlin 1.3中的首个稳定版本以来,编译器已从实验性后端发展成为用于工业项目的生产就绪工具。
Kotlin/JS的主要用途是使用Kotlin替代JavaScript或TypeScript进行前端开发。开发人员获得Kotlin语言的所有功能:空安全、扩展函数、数据类、协程和密封类。生成的JavaScript代码可以在任何现代浏览器或Node.js环境中运行。Kotlin/JS在Kotlin Multiplatform项目中尤其受欢迎,其中公共模块(commonMain)既可用于移动应用程序,也可用于网页应用程序。
Kotlin/JS生态系统包括用于创建用户界面的框架。用于Web的Compose Multiplatform将Kotlin/JS作为目标后端,允许创建在浏览器中工作的声明式UI组件。替代解决方案包括用于React的封装器——Kotlin Wrappers,它们为React、React Router和Redux提供类型安全的API。
编译 Kotlin/JS经过多个转换阶段。源代码Kotlin首先被编译为中间表示(IR),然后进行优化并生成JavaScript代码。从Kotlin 1.8开始,旧的后端(基于AST的JsBackend)已完全被IR后端取代,后者提供更好的优化、更小的输出代码大小和TypeScript兼容性。
以前,Kotlin/JS使用JsBackend,它直接与AST树(抽象语法树)一起工作。这种方法有局限性:平台优化支持的复杂性、所有后端缺乏统一的IR以及无法生成TypeScript声明。迁移到IR后端解决了这些问题,统一了所有三个Kotlin后端的编译,并为跨后端优化开辟了道路。
Kotlin/JS支持两种编译模式,决定输出代码的格式和优化。生产模式使用Webpack进行编译、压缩和摇树优化。开发模式支持热模块替换以实现快速开发迭代。模式选择在build.gradle.kts中通过js.target配置进行设置。
kotlin {
js {
browser {
webpackTask {
outputFileName = "app.js"
}
}
binaries.executable()
}
}
集成 Kotlin/JS与NPM生态系统的连接通过build.gradle.kts中的特殊DSL实现。开发人员在kotlin配置中声明npm依赖项,指定包名和版本。Kotlin/JS通过npm或yarn包管理器自动下载包。为了提供对JavaScript库的类型安全访问,使用外部声明来描述库的类型和函数给Kotlin编译器。
外部声明 — 是用关键字external标记的Kotlin声明。它们告知编译器函数或类的实现位于JavaScript代码中,而不是Kotlin中。JetBrains在Kotlin Wrappers中提供了流行库的现成套件,包括React、React Router、Redux、Emotion和MUI。对于没有现成封装器的库,开发人员可以手动编写外部声明或使用Dukat TypeScript绑定生成器。
kotlin {
js {
browser { }
npm {
dependency("react", "18.3.1")
dependency("react-dom", "18.3.1")
devDependency("webpack", "5.92.0")
}
}
}
// JavaScript库的外部声明
@JsModule("date-fns")
external fun formatDistance(
date: Date, baseDate: Date
): String
TypeScript — 是现代Web不可或缺的一部分,Kotlin/JS通过生成.d.ts文件确保与其兼容。当设置js.generateTsDeclarations = true时,编译器为所有公共Kotlin函数和类创建TypeScript声明。这允许TypeScript项目像普通npm包一样导入具有完整类型支持的Kotlin模块。TypeScript声明的生成仅适用于IR后端,并且是从旧后端迁移的关键原因之一。
IR后端(中间表示)——是所有三个Kotlin平台(JVM、JS和Native)的统一后端。它使用一个公共中间表示,在生成目标代码之前经过多个优化阶段。对于Kotlin/JS,IR后端从Kotlin 1.8.0起成为必需,取代了已标记为弃用的旧AST后端。
IR后端对Kotlin/JS的优势包括IR级别上改进的代码优化、通过死代码消除和内联优化减少包大小,以及支持TypeScript声明。IR后端还确保在翻译为JavaScript时正确内联函数、具体化泛型和挂起函数的处理,这在旧后端中是有问题的。
| 特性 | 旧后端(AST) | IR后端 |
|---|---|---|
| TypeScript声明 | 不支持 | 自动生成 |
| 死代码消除 | 有限 | 完整,在IR级别 |
| 内联函数 | 正确性问题 | 正确处理 |
| 具体化泛型 | 不支持 | 支持 |
| 包大小 | 基础 | 减少20–30% |
一个完整的Kotlin/JS项目从配置build.gradle.kts开始。kotlin multiplatform插件允许将Kotlin/JS设置为目标平台之一。让我们看一个使用React的网页应用程序的配置示例。
plugins {
kotlin("multiplatform") version "2.0.21"
id("org.jetbrains.kotlin-wrappers") version "1.0.0-pre.775"
}
kotlin {
js {
browser { }
binaries.executable()
generateTsDeclarations = true
}
}
dependencies {
implementation(enwraps(react, reactDom))
}
配置后,可以用Kotlin编写React组件。Kotlin Wrappers为React提供类型安全的API,包括函数组件、hooks和通过DSL构建器实现的类似JSX语法。Counter组件示例演示了useState和事件处理程序的使用。
@OptIn(ExperimentalWrapperApi::class)
val Counter = FC<Props> {
var count = useState(0)
div {
+"Counter value: ${count.component1()}"
button {
onClick = { count.component2()(count.component1() + 1) }
+"Increment"
}
}
}
fun main() {
createRoot(document.getElementById("root")!!).render(
createElement(Counter)
)
}
Kotlin/JS项目的构建通过Gradle任务完成。jsDevelopmentRun启动带有HMR的Webpack开发服务器以进行开发。jsProductionExecutableCompileSync生成带有压缩和摇树优化的生产包。连接编译后JavaScript的最终HTML文件由webpack插件生成,位于build/dist中。
// 使用HMR启动开发服务器
./gradlew jsDevelopmentRun
// 带压缩的生产构建
./gradlew jsProductionExecutableCompileSync
// 输出在build/dist/productionExecutable/
TypeScript — 是Kotlin/JS在类型化JavaScript领域的主要竞争对手。两种语言都编译为JavaScript,并在动态JS之上添加静态类型。然而,Kotlin/JS提供了一系列优势:默认空安全、密封类、协程和与Kotlin Multiplatform的无缝集成。而TypeScript拥有更广泛的社区、更多带有类型的现成库以及更成熟的生态系统。
对于已经在项目其他部分使用Kotlin的团队来说,使用Kotlin/JS的开发效率可能更高,因为不需要在语言之间切换。TypeScript仍然是纯网络项目(不使用Kotlin Multiplatform)的更受欢迎选择。然而,随着Compose Multiplatform在Web领域的日益普及,Kotlin/JS正在作为React和Angular的替代品获得地位。
| 特性 | Kotlin/JS | TypeScript |
|---|---|---|
| 空安全 | 默认 | strictNullChecks可选 |
| 密封类 | 支持 | 通过联合类型 |
| 协程 | 原生 | 通过async/await |
| KMM集成 | 完整 | 无 |
| 社区规模 | 小 | 巨大 |
| 库的现成类型 | 有限(通过Dukat使用DefinitelyTyped) | DefinitelyTyped(数千个库) |
在Kotlin/JS和TypeScript之间的选择取决于项目背景。如果团队已经在使用Kotlin Multiplatform或计划开始使用,Kotlin/JS是前端部分的逻辑选择。对于独立的Web项目,由于JavaScript库现成类型的可用性和市场上更多的开发人员,TypeScript仍然是更务实的选择。
常见问题
可以,JetBrains提供Kotlin Wrappers,即用于React、React Router和Redux的类型安全Kotlin封装器。它们允许在完全支持hooks和类似JSX的DSL的情况下用Kotlin编写React组件。
启用generateTsDeclarations = true后,Kotlin/JS为所有公共API生成.d.ts文件。TypeScript项目可以像普通npm包一样导入具有完整类型定义的Kotlin模块。
包大小取决于所使用的库。最小的Hello World应用程序包括Kotlin标准库大约占用300 KB。使用React和Kotlin Wrappers,大小增加到400–600 KB。
可以,Kotlin/JS可用于在Node.js下开发无服务器函数和控制台工具。为此,需要在配置中指定js.nodejs而不是js.browser。
Kotlin/Wasm — 是用于WebAssembly的实验性后端,而Kotlin/JS生成JavaScript代码。Wasm提供更高的性能,但对浏览器DOM的访问有限。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。