Spec-Zone.ru › Kotlin 1.8

Миграция проектов Kotlin/JS на компилятор IR

Мы заменили текущий компилятор Kotlin/JS на компилятор на основе IR, чтобы унифицировать поведение Kotlin на всех платформах и реализовать новые JS-специфичные оптимизации, среди прочего. Вы можете узнать больше о внутренних различиях между двумя компиляторами в блоге Миграция приложения Kotlin/JS на новый компилятор IR от Себастьяна Айгнера.

Из-за значительных различий между компиляторами, переход вашего проекта Kotlin/JS со старого бэкенда на новый может потребовать корректировки кода. На этой странице мы собрали список известных проблем миграции вместе с предлагаемыми решениями.

Установите плагин Kotlin/JS Inspection pack, чтобы получить ценные советы по исправлению некоторых проблем, возникающих во время миграции.

Обратите внимание, что это руководство может со временем меняться по мере исправления проблем и обнаружения новых. Пожалуйста, помогите нам поддерживать его актуальность – сообщите о любых проблемах, с которыми вы столкнетесь при переходе на компилятор 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:

  • Шаблон для State

  • Шаблон для Props

Преобразование свойств внешних интерфейсов в 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?
}
Последнее изменение: 10 января 2023
Компилятор Kotlin/JS IR API браузера и DOM

© 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API