В Go 1.11 добавили поддержку компиляции в Web Assembly (wasm). Сейчас уже 1.13, и я решил закопаться в это всё, пописать браузерные игры на Go через canvas 🙃 Если кратко, то всё работает и вообще очень круто, но с экосистемы пока толком нет. Теперь давайте в деталях. Говорить я буду про компиляцию именно wasm для браузера (GOOS=js GOARCH=wasm
) потому что очень хочется стать фуллстеко-разработчиком, не выходя из уютного мира Go.
Для начала несколько статей:
WebAssembly — официальный гайд, покрывающий все основы, какие-то тонкие моменты и имеющий ссылки на разные статьи и библиотеки.
The world’s easiest introduction to WebAssembly — лучшая статья, которую я нашёл. По крайней мере, единственная с работающими исходниками
От просто скомпилированного в wasm бинарника толку мало. Нельзя делать большинство системных вызовов, включая чтение локальных файлов (браузер не разрешит). Зато можно делать сетевые запросы, а ещё всё, что обычно попадает в stdout/stderr, будет перекинуто в консоль разработчика. Ну и вот чтобы можно было взаимодействовать с браузером, есть syscall/js. Эта волшебная библиотека позволяет взаимодействовать с JS на полную катушку: получать любые объекты и аттрибуты, читать их в стандартные типы Go, вызывать функции и методы, и даже регистрировать свои собственные Go функции, чтобы их можно было вызывать из JS. Ну вот правда, все возможности. Вот только проблема в том, что эта штука ничего не знает о всяких WebAPI. Вот пример кода из документации:
cb = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
fmt.Println("button clicked")
cb.Release() // release the function if the button will not be clicked again
return nil
})
js.Global().Get("document").Call("getElementById", "myButton").Call("addEventListener", "click", cb)```
В общем, добро пожаловать в нетипизированный мир. Причём это хуже, чем писать на чистом JS, потому что в данном случае у нас вообще нет никакого автокомплита, дебаггинга (дебаггер для wasm ещё не сделали, дружно дебажим принтами), документации. Вообще ничего, только наше безрассудство и отвага. Поэтому вокруг этого прям очень нужны обёртки на Go, которые всё сделают явным и типизированным. Вот об этом и поговорим.
+ [app](https://github.com/maxence-charriere/app) — работает, но автор хочет написать новую библиотеку, а эту выкинуть ([пруф](https://github.com/maxence-charriere/app/issues/312#issuecomment-580255190)). К тому же, она навязывает свой сервер, свой логгинг и прочее, что делает работу с ней сложной.
+ [vert](https://github.com/norunners/vert) — обертка для более удобной ковертации Go struct в JS object и обратно. Не развивается, но работает.
+ [go-canvas](https://github.com/markfarnan/go-canvas) — библиотека для рисования на canvas через [draw2d](https://github.com/llgcode/draw2d). Не пробовал, но планирую, выглядит интересно.
+ [webapi](https://github.com/gowebapi/webapi) — попытка автоматически сгенерировать обертку над WebAPI. Проект выглядит заброшенным, причём на ранних этапах. Многих вещей не хватает, и поэтому работать с этой штукой просто не получается. К тому же, даже там, где нужные функции есть, зачастую работать с ними больно. Вот, например, как новый canvas создать (😨):
`canvas.HTMLCanvasElementFromJS(webapi.GetWindow().Document().CreateElement("canvas", &webapi.Union{js.ValueOf("dom.Node")}))`
Всё остальное, что я попробовал (vue, dom) не работает и не развивается.
В общем, если есть непреодолимое желание написать React на Go — вперёд, миру нужен герой. Если хочется написать обёртку над WebAPI — ещё лучше! Можете мне написать, я 2 дня этим занимался, довольно многое сделал, но не уверен, что хватит энергии продолжить. Вот если кто-то ещё хочет этим заняться — другое дело, вместе веселее.