Spec-Zone.ru › Kotlin 1.6

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

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

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

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

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

Обратите внимание, что это руководство может со временем изменяться по мере исправления проблем и обнаружения новых. Пожалуйста, помогите нам поддерживать его полноту – сообщайте о любых проблемах, с которыми вы сталкиваетесь при переходе на компилятор IR, отправив их в систему отслеживания ошибок YouTrack или заполнив эту форму.

Преобразование JS- и React-связанных классов и интерфейсов во внешние интерфейсы

Проблема: Использование Kotlin-интерфейсов и классов (включая data-классы), которые наследуются от чистых 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() или jsObject() (вспомогательная функция из kotlin-wrappers):

val myState = js("{}") as CustomComponentState
myState.name = "name"

Решение: преобразуйте все свойства внешних интерфейсов в var:

// Replace this
external interface CustomComponentState : State {
   val name: String
}
// With this
external interface CustomComponentState : State {
   var name: String
}

Сделать булевы свойства неявными во внешних интерфейсах

Проблема: JavaScript обрабатывает значение null или undefined булевой переменной как false. Поэтому булевы свойства могут использоваться в выражениях без определения. Это допустимо в JavaScript, но не в Kotlin.

external interface ComponentProps: Props {
   var isInitialized: Boolean
   var visible: Boolean
}
val props = js("{}") as ComponentProps
props.isInitialized = true
// visible is not initialized - OK in JS – means it's false

Если вы попытаетесь использовать такое свойство в функции, переопределённой в Kotlin (например, React button), вы получите ClassCastException:

button {
   attrs {
       autoFocus = props.visible // ClassCastException here
   }
}

Решение: сделайте все Boolean свойства внешних интерфейсов неявными (Boolean?):

// Replace this
external interface ComponentProps: Props {
   var visible: Boolean
}
// With this
external interface ComponentProps: Props {
   var visible: Boolean?
}

Преобразование функций с получателями во внешних интерфейсах в обычные функции

Проблема: внешние объявления не могут содержать функции с получателями, такие как функции-расширения или свойства с соответствующими функциональными типами.

Решение: преобразуйте такие функции и свойства в обычные функции, добавив объект получателя в качестве аргумента:

// 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() или jsObject() (вспомогательная функция из 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 jsObject {}

Решение 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()
    }
}
Последнее изменение: 07 апреля 2022
Компилятор Kotlin/JS IR API браузера и DOM

© 2010–2022 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