javascript

Kotlin JS: непокоренная вершина VK

  • понедельник, 13 мая 2024 г. в 00:00:08
https://habr.com/ru/articles/813725/

После окончания нативного 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 в своих проектах.