Введение: Зачем Swift в браузере?
Мир веб-разработки переживает ренессанс. Долгое время JavaScript был безальтернативным королём фронтенда. Но что, если я скажу вам, что теперь вы можете запускать нативный, быстрый код Swift прямо в браузере, получая прирост производительности до 10-15 раз на сложных вычислениях? Звучит как фантастика? Добро пожаловать в эру WebAssembly (Wasm) и Swift.
В этой статье мы разберем, что такое WebAssembly, как он дружит со Swift, зачем это нужно обычному разработчику и как написать свой первый модуль на Swift, который будет работать быстрее, чем аналогичный код на JS. Если вы пишете на Swift под iOS/macOS или просто хотите расширить кругозор — этот материал для вас.
Что такое WebAssembly простыми словами?
Представьте, что браузер — это операционная система. JavaScript — это её родной, но не самый быстрый язык. WebAssembly — это бинарный формат инструкций (как машинный код), который браузер выполняет почти со скоростью нативного приложения. Вы компилируете свой код на C, C++, Rust или Swift в компактный .wasm-файл, и браузер запускает его в специальной виртуальной машине.
Ключевые особенности Wasm:
- Скорость: Загрузка и выполнение в разы быстрее JS для тяжелых задач (шифрование, рендеринг 3D, обработка видео).
- Безопасность: Код выполняется в изолированной песочнице, не имеет доступа к системе напрямую.
- Переносимость: Работает во всех современных браузерах (Chrome, Firefox, Safari, Edge).
Swift + WebAssembly: Брак по расчету
Долгое время Swift считался языком исключительно для экосистемы Apple. Но проект SwiftWasm (и его фреймворк Tokamak для UI) перевернул эту парадигму. Теперь вы можете писать бэкенд, фронтенд и мобильные приложения на одном языке.
Почему именно Swift для Wasm?
- Производительность: Swift компилируется в LLVM IR, который легко транслируется в Wasm. Код получается компактным и быстрым.
- Безопасность памяти: ARC (Automatic Reference Counting) и строгая типизация уменьшают количество багов по сравнению с C++.
- Синтаксис: Лаконичный и выразительный — писать на Swift одно удовольствие.
- Современность: SwiftUI-like подход (через Tokamak) позволяет создавать реактивные интерфейсы прямо в браузере.
Главный минус: пока экосистема библиотек для SwiftWasm меньше, чем для Rust или AssemblyScript. Но для большинства задач — хватает.
Практика: Компилируем Swift в Wasm
Давайте напишем простой модуль, который будет вычислять числа Фибоначчи. Сначала на JavaScript, потом на Swift. Вы увидите разницу в скорости.
Шаг 1. Установка инструментов
Вам понадобится:
- Swift 5.9+ (с поддержкой Wasm). Скачайте с swift.org.
- SwiftWasm toolchain — специальная версия компилятора.
- Node.js (для запуска примера в терминале).
Установка toolchain (пример для macOS):
brew install swiftwasm/tap/swiftwasm
swiftwasm --version
После установки создадим новый проект:
mkdir SwiftWasmDemo && cd SwiftWasmDemo
swift package init --type executable
Шаг 2. Пишем код на Swift
Откройте файл Sources/SwiftWasmDemo/main.swift и вставьте следующий код:
import JavaScriptKit
// Функция для вычисления чисел Фибоначчи (рекурсивно с мемоизацией)
func fibonacci(_ n: Int) -> Int {
var cache = [Int: Int]()
func fib(_ n: Int) -> Int {
if let cached = cache[n] { return cached }
if n <= 1 { return n }
let result = fib(n - 1) + fib(n - 2)
cache[n] = result
return result
}
return fib(n)
}
// Экспортируем функцию в JavaScript
let jsFib = JSClosure { (args: [JSValue]) -> JSValue in
guard let n = args.first?.number else { return .number(0) }
let result = fibonacci(Int(n))
return .number(Double(result))
}
// Регистрируем функцию в глобальной области видимости JS
_ = JSObject.global.setProperty("swiftFib", jsFib)
print("Swift модуль загружен! Используйте swiftFib(n) в консоли браузера.")
Важно: Мы используем библиотеку JavaScriptKit для взаимодействия с JS. Добавьте её в Package.swift:
// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "SwiftWasmDemo",
dependencies: [
.package(url: "https://github.com/swiftwasm/JavaScriptKit.git", from: "0.18.0")
],
targets: [
.executableTarget(
name: "SwiftWasmDemo",
dependencies: ["JavaScriptKit"])
]
)
Шаг 3. Компиляция в Wasm
Выполните команду:
swift build --triple wasm32-unknown-wasi
После успешной сборки вы найдёте SwiftWasmDemo.wasm в папке .build/wasm32-unknown-wasi/release/.
Шаг 4. Запускаем в браузере
Создайте HTML-файл index.html:
<!DOCTYPE html>
<html>
<head>
<title>Swift + WebAssembly Demo</title>
</head>
<body>
<h2>Вычисление Фибоначчи</h2>
<input type="number" id="input" value="40">
<button onclick="runSwift()">Swift Wasm</button>
<button onclick="runJS()">JavaScript</button>
<p>Результат: <span id="result"></span></p>
<p>Время: <span id="time"></span> мс</p>
<script>
// Загружаем Wasm модуль
const go = new Go(); // из wasm_exec.js
WebAssembly.instantiateStreaming(
fetch("SwiftWasmDemo.wasm"), go.importObject
).then((result) => {
go.run(result.instance);
});
function runSwift() {
const n = parseInt(document.getElementById('input').value);
if (typeof swiftFib === 'undefined') {
alert("Модуль ещё не загружен!");
return;
}
const start = performance.now();
const result = swiftFib(n);
const end = performance.now();
document.getElementById('result').textContent = result;
document.getElementById('time').textContent = (end - start).toFixed