WebAssembly и Kotlin: Полное руководство по интеграции

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в WebAssembly и Kotlin

Современная веб-разработка требует всё большей производительности, особенно для сложных вычислений, обработки изображений, игр и научных приложений. WebAssembly (Wasm) — это низкоуровневый бинарный формат, который выполняется в браузере со скоростью, близкой к нативной. А Kotlin, благодаря своей гибкости и поддержке множества платформ, становится отличным кандидатом для компиляции в Wasm.

В этой статье мы подробно разберём, как настроить проект на Kotlin для компиляции в WebAssembly, напишем практические примеры и рассмотрим лучшие практики оптимизации.

1. Настройка окружения для Kotlin/Native и WebAssembly

Для работы с WebAssembly в Kotlin используется Kotlin/Native — технология, позволяющая компилировать Kotlin-код в нативные бинарные файлы, включая Wasm. Рассмотрим пошаговую настройку.

Установка необходимых инструментов

  • IntelliJ IDEA (Community или Ultimate версия) — основная среда разработки.
  • Gradle (встроен в IDEA) — система сборки.
  • Emscripten SDK — инструмент для работы с Wasm (требуется для некоторых продвинутых сценариев).

Создание проекта

Создайте новый Gradle-проект и добавьте в build.gradle.kts следующую конфигурацию:

plugins {
    kotlin("multiplatform") version "1.9.22"
    kotlin("plugin.serialization") version "1.9.22"
}

kotlin {
    wasm {
        binaries.executable()
        browser {
            commonWebpackConfig {
                cssSupport.enabled = true
            }
        }
    }
}

dependencies {
    commonMainImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
}

Обратите внимание: для Kotlin 1.9+ используется таргет wasm (ранее был wasm32). Убедитесь, что версия Kotlin актуальна.

Структура проекта

После настройки создайте файл src/wasmMain/kotlin/Main.kt — это будет точка входа вашего Wasm-приложения.

2. Написание первого приложения на Kotlin для WebAssembly

Напишем простое приложение, которое вычисляет факториал числа и взаимодействует с JavaScript.

Код на Kotlin

// src/wasmMain/kotlin/Main.kt
import kotlinx.browser.document
import kotlinx.browser.window

fun factorial(n: Int): Long {
    var result = 1L
    for (i in 1..n) {
        result *= i
    }
    return result
}

fun main() {
    window.onload = {
        val output = document.getElementById("output") ?: return@onload
        val input = document.getElementById("number") ?: return@onload
        
        // Пример вызова
        val num = 10
        output.textContent = "Факториал $num = ${factorial(num)}"
        
        // Добавляем обработчик для динамического ввода
        input.addEventListener("input", {
            val value = (input as? org.w3c.dom.HTMLInputElement)?.value?.toIntOrNull() ?: 0
            output.textContent = "Факториал $value = ${factorial(value)}"
        })
    }
}

HTML-шаблон для запуска

Создайте файл src/wasmMain/resources/index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Kotlin Wasm Demo</title>
</head>
<body>
    <h1>Калькулятор факториала на Kotlin/Wasm</h1>
    <input type="number" id="number" value="10">
    <p id="output">Загрузка...</p>
    
    <script src="https://unpkg.com/kotlin-wasm-bridge@latest/dist/kotlin-wasm-bridge.js"></script>
    <script src="main.js"></script>
</body>
</html>

3. Взаимодействие Kotlin и JavaScript через WebAssembly

Одна из ключевых возможностей — передача данных между Wasm-модулем и JavaScript. Рассмотрим продвинутые сценарии.

Экспорт функций из Kotlin

Чтобы функция была доступна из JavaScript, её нужно пометить аннотацией @JsExport:

import kotlin.js.JsExport

@JsExport
fun calculatePrimes(limit: Int): String {
    val primes = mutableListOf<Int>()
    for (i in 2..limit) {
        if (primes.none { i % it == 0 }) {
            primes.add(i)
        }
    }
    return primes.joinToString(", ")
}

Теперь из JavaScript можно вызвать:

// JavaScript
const result = Kotlin.modules["main"].calculatePrimes(100);
console.log(result); // "2, 3, 5, 7, 11, ..."

Передача сложных объектов

Для передачи JSON-объектов используйте библиотеку kotlinx.serialization:

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json

@Serializable
data class User(val name: String, val age: Int)

@JsExport
fun processUserData(json: String): String {
    val user = Json.decodeFromString<User>(json)
    val processed = User(user.name.uppercase(), user.age + 1)
    return Json.encodeToString(processed)
}

4. Оптимизация производительности и лучшие практики

WebAssembly даёт прирост производительности, но важно правильно использовать его возможности.

Избегайте лишних аллокаций

Внутри Wasm-модуля старайтесь использовать примитивные типы и массивы фиксированной длины. Пример:

// Плохо: создание новых объектов в цикле
fun processData(data: List<Int>): List<Int> {
    return data.map { it * 2 }
}

// Хорошо: работа с IntArray
fun processDataFast(data: IntArray): IntArray {
    val result = IntArray(data.size)
    for (i in data.indices) {
        result[i] = data[i] * 2
    }
    return result
}

Минимизируйте взаимодействие с JavaScript

Каждый вызов между Wasm и JS имеет накладные расходы. Старайтесь передавать данные пачками:

// Вместо 1000 отдельных вызовов                

Блоги

Рекомендаций по книгам