Введение: Почему WebAssembly и Kotlin — идеальная пара
Современная веб-разработка требует не только скорости, но и безопасности. WebAssembly (Wasm) — это низкоуровневый бинарный формат, который выполняется в браузере со скоростью, близкой к нативной. Kotlin, в свою очередь, — это современный мультиплатформенный язык, который компилируется в байт-код JVM, JavaScript и, с недавнего времени, в WebAssembly.
Сочетание Kotlin и WebAssembly открывает новые горизонты: вы можете писать сложную логику на знакомом языке с мощной системой типов, а затем запускать её в любом современном браузере без оверхэда JavaScript. В этой статье мы разберём работу с WebAssembly и Kotlin от А до Я: от установки инструментов до развёртывания готового приложения.
1. Настройка окружения для Kotlin/Wasm
Прежде чем писать код, необходимо подготовить среду. На момент написания статьи официальная поддержка Kotlin/Wasm находится в стадии эксперимента (начиная с Kotlin 1.9.20). Для работы потребуется:
- JDK 11 или выше (рекомендуется JDK 17)
- IntelliJ IDEA (Community Edition подойдёт) или любой редактор с поддержкой Gradle
- Последняя версия Kotlin (1.9.22+).
Создание проекта
Создадим новый проект Gradle с мультиплатформенной конфигурацией. В файле build.gradle.kts укажите плагины и цель Wasm:
plugins {
kotlin("multiplatform") version "1.9.22"
kotlin("plugin.serialization") version "1.9.22" // опционально
}
kotlin {
wasmJs {
binaries.executable()
nodejs()
browser {
commonWebpackConfig {
cssSupport {
enabled.set(true)
}
}
}
}
sourceSets {
val commonMain by getting
val wasmJsMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}
}
}
}
После синхронизации Gradle, структура проекта будет готова к компиляции в Wasm.
2. Пишем первую программу на Kotlin/Wasm
Создадим простой модуль, который вычисляет факториал числа — идеальный пример для демонстрации производительности Wasm.
Код на Kotlin
В папке src/wasmJsMain/kotlin создайте файл Main.kt:
import kotlinx.coroutines.*
// Функция, которая будет экспортирована в Wasm
@WasmExport
fun factorial(n: Int): Long {
if (n < 0) return -1L
var result = 1L
for (i in 2..n) {
result *= i
}
return result
}
// Точка входа для браузера
fun main() {
println("Kotlin/Wasm загружен!")
// Используем корутины для асинхронного вызова
GlobalScope.launch {
val result = factorial(10)
println("Факториал 10: $result")
}
}
Аннотация @WasmExport делает функцию доступной из JavaScript. Обратите внимание: не все типы Kotlin можно экспортировать — поддерживаются примитивы, строки и массивы.
Сборка и запуск
Выполните команду Gradle:
./gradlew wasmJsBrowserDevelopmentRun
После сборки откроется браузер с консолью, где вы увидите вывод. Если всё прошло успешно, вы только что запустили Kotlin в WebAssembly!
3. Взаимодействие с JavaScript: мост между двумя мирами
Одна из ключевых возможностей Kotlin/Wasm — двустороннее взаимодействие с JavaScript. Вы можете вызывать JS-функции из Kotlin и наоборот.
Вызов JavaScript из Kotlin
Добавим в Main.kt код, который использует DOM API браузера:
import org.w3c.dom.*
@WasmExport
fun showAlert(message: String) {
// Используем глобальный объект window
window.alert("Kotlin говорит: $message")
}
fun main() {
// Получаем элемент по ID и меняем его содержимое
val element = document.getElementById("output")
element?.innerHTML = "Привет из Kotlin/Wasm!"
}
Для этого в build.gradle.kts нужно добавить зависимость kotlin-stdlib-js (она обычно включена по умолчанию для wasmJs).
Вызов Kotlin из JavaScript
После компиляции сгенерируется файл .wasm и JS-обёртка. В HTML-файле подключите скрипт и вызывайте экспортированные функции:
<!DOCTYPE html>
<html>
<head>
<title>Kotlin Wasm Demo</title>
</head>
<body>
<div id="output"></div>
<button onclick="callKotlin()">Вызвать Kotlin</button>
<script src="build/developmentExecutable/main.js"></script>
<script>
async function callKotlin() {
// Функция была экспортирована через @WasmExport
const result = await window.factorial(5);
console.log("Результат из Wasm:", result);
}
</script>
</body>
</html>
Обратите внимание: вызовы к Wasm-функциям асинхронны, так как модуль загружается динамически.
4. Оптимизация и продакшн-сборка
Для реальных проектов важно настроить финальную сборку. Используйте команду:
./gradlew wasmJsBrowserDistribution
В папке build/dist/wasmJs/productionExecutable появятся оптимизированные файлы:
main.wasm— бинарный модульmain.js— загрузчик и обёрткаindex.html— точка входа
Советы по оптимизации
- Минимизируйте экспорт: экспортируйте только те функции, которые нужны из JS.
- Используйте примитивы: избегайте сложных объектов на границе Kotlin-JS.