Kotlin JS: непокоренная вершина VK
После окончания нативного Android приложения от заказчика последовало предложение написать мини-приложение VK. Так как я имел опыт написания кода только для нативных приложений, то для меня это был интересный челенж. Немного погуглив пришел к тому, что добрые разработчики из Jet Brains разработали Kotlin JS — оболочку над React (а Kotlin мой основной язык). Вдохновившись статьей https://habr.com/ru/companies/vk/articles/521192/ я приступил к написанию кода.
Итак, чем хорош Kotlin для разработки такого рода приложений — использование всех фишек (экстеншены, дата классы, корутины, конструкции и пр.) языка и в то же время возможность реализации компонентов и хуков React. Поэтому, сомнений у меня не было.
Несмотря на то, что в статьях указывается как легко имплементируются в проект библиотеки, действительность оказалось другой. Gradle сыпал ошибками несовместимости библиотек между собой. При этом, при одинаковых номерах версий дружба никак не зарождалась. В итоге, поэкспериментировав с различными версиями пришлось перейти к изучению списка оберток в https://github.com/JetBrains/kotlin-wrappers/. Здесь меня ожидало решение проблемы совместимости — https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-wrappers-bom. Добавление имплементации этой библиотеки позволяет не заморачиваться и передать это заботу этой библиотеке:
val kotlinWrappersBomVersion = "1.0.0-pre.339-compat"
kotlin {
sourceSets {
dependencies {
implementation(kotlin("stdlib-js"))
implementation(platform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:$kotlinWrappersBomVersion"))
implementation("org.jetbrains.kotlin-wrappers:kotlin-react")
implementation("org.jetbrains.kotlin-wrappers:kotlin-react-dom")
implementation("org.jetbrains.kotlin-wrappers:kotlin-css")
implementation("org.jetbrains.kotlin-wrappers:kotlin-mui")
}
}
}
Впрочем не смотря на составленные списки дружественных зависимостей, все равно не все библиотеки устанавливались без ошибок. Но мне повезло и основные необходимые для моего проекта заработали.
Следующей задачей стало установка библиотек vk-bridge и vk-tunnel. К сожалению для них Jet Brains не создал обертки и их пришлось устанавливать через следующий синтаксис зависимостей:
implementation(npm("@vkontakte/vk-bridge", "2.14.1"))
implementation(npm("@vkontakte/vk-tunnel", "0.2.0"))
implementation(npm("@vkontakte/vk-miniapps-deploy", "0.1.7"))
К сожалению, в документации vk нет ничего об использовании кода на Kotlin и меня ожидала череда экспериментов по внедрению этих библиотек в код.
Первой задачей было запустить vk-bridge. Для этого необходимо создать отдельный файл для импорта который я назвал VkBridge.kt и написать в нем следующий код:
@JsModule("@vkontakte/vk-bridge")
@JsNonModule
external object VkBridge{
@JsName("default")
object Default {
fun send(method: String): dynamic
}
}
Данный код создает объект с необходимыми нам методами для последующего использования данной библиотеки. Объект содержит вложенный объект с уникальным именем, которое мы даем в аннотации. В результате в классах использующих vk-bridge открывается возможность обращаться к методам данной библиотеки. В частности, запуск библиотеки:
VkBridge.Default.send("VKWebAppInit")
Следующей библиотекой которую необходимо было запустить являлся vk-tunnel (впрочем для разработки можно обойтись и без него, но если хотим наблюдать за изменениями работы кода непосредственно из вк, то он нужен).
Так как vk-tunnel запускается из терминала, то необходимости создавать класс для импорта нет. Но данная библиотека для работы требует некоторых параметров. В Intellij IDEA при работе с Kotlin JS не создается файл package.json, а именно он нужен для выполнения команды терминала. На самом деле данный файл создается при сборке проекта и находится в …build\js\ и непосредственно мы туда напрямую не можем добавить то что нужно. Для терминала же требуется чтобы он был непосредственно в папке проекта. Как решить эту проблему? Для этого был предусмотрен следующий механизм Gradle.
kotlin {
js(IR) {
binaries.executable()
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
}
compilations["main"].packageJson {
customField("scripts",mapOf(
"tunnel" to "vk-tunnel --insecure=1 --http-protocol=https --ws-protocol=wss --host=localhost --port=8080 --timeout=5000 --app_id=5------1",
"start" to "cross-env PORT=8080 HTTPS=true react-scripts start",
"deploy" to "vk-miniapps-deploy --app_id=5------1"
))
}
}
}
Когда мы откроем файл из папки …build\js\ то мы увидим, что теперь параметры vk-tunnel, vk-miniapps-deploy и др. находятся там где нужно. Вышенаписанный код является образцом добавления записей в json и может быть использован для других ситуаций. Но, добавление необходимых библиотек и записей не позволило запускать vk-tunnel без ошибок. Потребовалось скопировать package.json в папку приложения.
В итоге, после предварительной настройки и создания пары компонентов настала пора попробовать сделать deploy приложения. И вот здесь меня ждала неудача. Код компилировался, пытался залиться на хостинг, но я неизменно получал unknown_error (что в итоге послужило основой для заголовка статьи). Возможно, мне оставалось совсем чуть чуть до достижения положительного результата (вершины), но я не смог найти причину такой ошибки, а время не терпело и мне все же пришлось перейти на Rect.
К сожалению, у меня не получилась полная рекомендация как разрабатывать в vk на Kotlin JS, но надеюсь отдельные решения задач будут полезны, тем кто решится на использование Kotlin JS в своих проектах.