Миграция проектов Kotlin/JS на компилятор IR
Мы заменили текущий компилятор Kotlin/JS на компилятор на основе IR, чтобы унифицировать поведение Kotlin на всех платформах и реализовать новые JS-специфичные оптимизации, среди прочего. Вы можете узнать больше о внутренних различиях между двумя компиляторами в блоге Миграция приложения Kotlin/JS на новый компилятор IR от Себастьяна Айгнера.
Из-за значительных различий между компиляторами, переход вашего проекта Kotlin/JS со старого бэкенда на новый может потребовать корректировки кода. На этой странице мы собрали список известных проблем миграции вместе с предлагаемыми решениями.
Обратите внимание, что это руководство может со временем меняться по мере исправления проблем и обнаружения новых. Пожалуйста, помогите нам поддерживать его актуальность – сообщите о любых проблемах, с которыми вы столкнетесь при переходе на компилятор IR, отправив их в нашу систему отслеживания проблем YouTrack или заполнив эту форму.
Преобразование классов и интерфейсов, связанных с JS и React, во внешние интерфейсы
Проблема: Использование Kotlin-интерфейсов и классов (включая данные классы), которые наследуются от чистых JS-классов, таких как React's State и Props, может привести к ошибке ClassCastException. Такие исключения появляются, потому что компилятор пытается работать с экземплярами этих классов как с Kotlin-объектами, в то время как они фактически происходят из JS.
Решение: Преобразуйте все классы и интерфейсы, которые наследуются от чистых JS-классов, во внешние интерфейсы:
// Replace this
interface AppState : State { }
interface AppProps : Props { }
data class CustomComponentState(var name: String) : State
// With this
external interface AppState : State { }
external interface AppProps : Props { }
external interface CustomComponentState : State {
var name: String
}
В IntelliJ IDEA вы можете использовать эти шаблоны структурного поиска и замены, чтобы автоматически пометить интерфейсы как external:
Преобразование свойств внешних интерфейсов в var
Проблема: свойства внешних интерфейсов в коде Kotlin/JS не могут быть неизменяемыми (val) свойствами, потому что их значения можно назначить только после создания объекта с js() или jso() (функция-помощник из kotlin-wrappers):
import kotlinx.js.jso val myState = jso<CustomComponentState>() myState.name = "name"
Решение: Преобразуйте все свойства внешних интерфейсов в var:
// Replace this
external interface CustomComponentState : State {
val name: String
}
// With this
external interface CustomComponentState : State {
var name: String
}
Преобразование функций с получателями во внешних интерфейсах в обычные функции
Проблема: внешние объявления не могут содержать функции с получателями, такие как расширяющие функции или свойства с соответствующими функциональными типами.
Решение: Преобразуйте такие функции и свойства в обычные функции, добавив объект получателя в качестве аргумента:
// Replace this
external interface ButtonProps : Props {
var inside: StyledDOMBuilder<BUTTON>.() -> Unit
}
external interface ButtonProps : Props {
var inside: (StyledDOMBuilder<BUTTON>) -> Unit
}
Создание простых JS-объектов для взаимодействия
Проблема: свойства Kotlin-объекта, реализующего внешний интерфейс, не являются перечисляемыми. Это означает, что они не видны для операций, которые итерируют по свойствам объекта, например:
for (var name in obj)console.log(obj)JSON.stringify(obj)
Хотя они все еще доступны по имени: obj.myProperty
external interface AppProps { var name: String }
data class AppPropsImpl(override var name: String) : AppProps
fun main() {
val jsApp = js("{name: 'App1'}") as AppProps // plain JS object
println("Kotlin sees: ${jsApp.name}") // "App1"
println("JSON.stringify sees:" + JSON.stringify(jsApp)) // {"name":"App1"} - OK
val ktApp = AppPropsImpl("App2") // Kotlin object
println("Kotlin sees: ${ktApp.name}") // "App2"
// JSON sees only the backing field, not the property
println("JSON.stringify sees:" + JSON.stringify(ktApp)) // {"_name_3":"App2"}
}
Решение 1: Создайте простые JavaScript-объекты с js() или jso() (функция-помощник из kotlin-wrappers):
external interface AppProps { var name: String }
data class AppPropsImpl(override var name: String) : AppProps
// Replace this
val ktApp = AppPropsImpl("App1") // Kotlin object
// With this
val jsApp = js("{name: 'App1'}") as AppProps // or jso {}
Решение 2: Создайте объекты с kotlin.js.json():
// or with this
val jsonApp = kotlin.js.json(Pair("name", "App1")) as AppProps
Замена вызовов toString() для ссылок на функции свойством .name
Проблема: в бэкенде IR вызов toString() для ссылок на функции не генерирует уникальные значения.
Решение: используйте свойство name вместо toString().
Явно укажите binaries.executable() в скрипте сборки
Проблема: компилятор не создает исполняемые .js файлы.
Это может произойти потому, что по умолчанию компилятор создаёт JavaScript-исполнимые файлы, а компилятор IR требует явного указания этого. Дополнительная информация в инструкциях по настройке проекта Kotlin/JS.
Решение: добавьте строку binaries.executable() в build.gradle(.kts) проекта.
kotlin {
js(IR) {
browser {
}
binaries.executable()
}
}
Дополнительные советы по устранению неполадок при работе с компилятором Kotlin/JS IR
Сделайте булевы свойства необязательными во внешних интерфейсах
Проблема: когда вы вызываете toString на Boolean из внешнего интерфейса, вы получаете ошибку, подобную Uncaught TypeError: Cannot read properties of undefined (reading 'toString'). JavaScript обрабатывает значения null или undefined булевого переменной как false. Если вы полагаетесь на вызов toString на Boolean , которое может быть null или undefined (например, когда ваш код вызывается из JavaScript-кода, над которым у вас нет контроля), учитывайте это:
external interface SomeExternal {
var visible: Boolean
}
fun main() {
val empty: SomeExternal = js("{}")
println(empty.visible.toString()) // Uncaught TypeError: Cannot read properties of undefined (reading 'toString')
}
Решение: вы можете сделать ваши Boolean свойства внешних интерфейсов необязательными (Boolean?):
// Replace this
external interface SomeExternal {
var visible: Boolean
}
// With this
external interface SomeExternal {
var visible: Boolean?
}
© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/js-ir-migration.html