将 Kotlin/JS 项目迁移到 IR 编译器
我们已经用 基于 IR 的编译器 替代了旧的 Kotlin/JS 编译器, 原因是为了在所有的平台上统一 Kotlin 的行为, 以及能够实现新的 JS 专有的优化, 还有其他一些原因. 关于两种编译器的内部区别, 请参见 Sebastian Aigner 的 Blog 将我们的 Kotlin/JS 应用程序迁移到新的 IR 编译器.
由于编译器之间的显著区别, 将你的 Kotlin/JS 项目从旧的编译器后端切换到新的, 可能会需要调整你的代码. 本章中, 我们会列举已知的迁移问题, 以及建议的解决方案.
注意, 由于我们修正了问题, 或者发现了新的问题, 本向导将来可能会发生变更. 请帮助我们完善这些信息 – 请报告你切换到 IR 编译器时遇到的问题, 提交到我们的问题追踪系统 YouTrack, 或填写这个 表格.
将 JS 和 React 相关的类和接口转换为外部接口(External Interface)
问题
: 使用 Kotlin 接口和类 (包括数据类), 如果继承自纯 JS 类, 比如 React 的 State
和 Props
, 可能导致 ClassCastException
异常. 出现这样的异常是因为, 编译器试图将这些类的实例象 Kotlin 对象一样使用, 然而它们实际上来自 JS.
解决方案: 将所有继承自纯 JS 类的类和接口转换为 外部接口(External Interface):
在 IntelliJ IDEA 中, 你可以使用这些 结构化查找与替换 模板, 将接口自动标记为 external
:
将外部接口的属性转换为 var
问题: 在 Kotlin/JS 代码中, 外部接口的属性不能为只读(val
)属性, 因为这些属性的赋值, 只能在使用 js()
或 jso()
(来自 kotlin-wrappers
的帮助函数) 创建对象之后:
解决方案: 将外部接口的所有属性转换为 var
:
将外部接口中带接受者的函数转换为普通函数
问题: 外部声明不能包含带接受者的函数, 比如扩展函数, 或这类函数类型的属性.
解决方案: 将这样的函数和属性转换为通常的函数, 将接受者对象添加为一个参数:
为与 JS 交互, 创建单纯 JS 对象
问题: 实现外部接口的 Kotlin 对象的属性不可 列举. 因此不能通过对象属性的遍历得到这些属性, 比如:
for (var name in obj)
console.log(obj)
JSON.stringify(obj)
但属性仍然可以通过名称访问: obj.myProperty
解决方案 1: 使用 js()
或 jso()
(来自 kotlin-wrappers
的帮助函数) 创建单纯 JavaScript 对象:
解决方案 2: 使用 kotlin.js.json()
创建对象:
将函数引用上的 toString() 调用替换为 .name
问题: 在 IR 后端中, 对函数引用调用 toString()
不会输出唯一的值.
解决方案: 使用 name
属性代替 toString()
调用.
在构建脚本中明确指定 binaries.executable()
问题: 编译器不会产生可执行的 .js
文件.
可能会发生这样的问题, 因为默认的编译器会默认产生 JavaScript 可执行文件, 但 IR 编译器则需要明确指定. 详情请参见 Kotlin/JS 项目设置指南.
解决方案: 在项目的 build.gradle(.kts)
文件中添加 binaries.executable()
.
关于使用 Kotlin/JS IR 编译器时其他问题的提示
这些提示也许能够帮助你解决在使用 Kotlin/JS IR 编译器的项目中遇到的问题.
将外部接口中的 boolean 属性标记为 nullable
问题: 当你对外部接口中的 Boolean
属性调用 toString
时, 你会得到 Uncaught TypeError: Cannot read properties of undefined (reading 'toString')
之类的错误. JavaScript 将 boolean 变量的 null
值或 undefined
值当作 false
处理. 如果你需要对可能为 null
或 undefined
的 Boolean
值调用 toString
(比如, 如果你的代码被 JavaScript 代码调用, 而你无法控制这些 JavaScript 代码), 需要注意这个问题:
如果你想要在 Kotlin 中覆盖的函数内(比如, 一个 React button
), 使用这样的属性, 将会发生 ClassCastException
异常:
解决方案: 你可以将你的外部接口的 Boolean
属性标记为 nullable (Boolean?
):