Awesome
<p align="center"> <img src="https://i.ibb.co/J5dgL4v/Webp-net-resizeimage.png"> </p> <h1 align="center">go-vdom-wasm</h1>This package allows to build frontend applications in Go targeting Webassembly. It provides a conveniant syntax close to the hyperscript one in the JavaScript lands and aims to provide efficient way to deal with the DOM. If you're not familiar the Virtual DOM notion, I suggest you take a look at this document.
:warning: This package is not production ready. Use at your own risks. A Todos section is available if you want to take part of the projet and try to make it better. You can also check the Go + WASM wiki to get a better overview of the Webassembly support for the Go language.
This module has been inspired by the awesome work of @mbasso on https://github.com/mbasso/asm-dom.
Want to see go-vdom-wasm in action?
Ready to start?
Before starting
You have to make some little configuration that are well explained in the Go + WASM wiki - Getting started guide.
If you prefer a quickest solution, you can also rely on the go-wasm-cli utility. It allows to create a WASM application in one command line and to have hot reload while coding.
Install the module
In your favorite terminal
$ GOOS=js GOARCH=wasm go get github.com/mfrachet/go-vdom-wasm
Usage
Let's define the root of our go-vdom-wasm
application. Everything that the library will work on is inside that div
:
<!-- index.html-->
<div id="app"></div>
Let's now Patch
that node with a virtual one to make something happen:
// main.go
rootNode := vn.H("div", "Hello world")
vn.Patch("#app", rootNode)
Passing attributes
In this example, we set a class="navbar"
to the underlying ul
element
vn.H("ul", &vn.Props{"class": "navbar"}, vn.Children{
vn.H("li", "First item"),
vn.H("li", "Second item"),
}),
The DOM representation of the previous snippet is:
<ul class="navbar">
<li>First item</li>
<li>Second item</li>
</ul>
Handling events
The Ev
structure allows to pass functions to handle specific events.
In this example, we set a click event on of the the li
:
func handleClick(args []js.Value){
fmt.Println("I've been clicked!")
}
func main() {
rootNode := vn.H("ul", &vn.Props{"class": "navbar"}, vn.Children{
vn.H("li", &vn.Ev{"click": handleClick}, "First item"),
vn.H("li", "Second item"),
})
vn.patch("#app", rootNode)
}
This module binds the event using the addEventListener
API
:warning: While using event handler, it's necessary to add en empty select{}
at the end of the main
function
Using keys
in list of item
For efficient diffing while you're relying a list of items, you can rely on a key
parameter:
vn.H("div", vn.Children{
vn.H("span", attrsChecked, "Some text"),
}, &vn.Key{"UNIQUE KEY"})
The key aims to identifiy a Node. It has to be unique and will ensure a quick comparison before handling the computation. The idea is the same (less advanced actually, but here's the idea) as the React key system.
Todos
- Add more tests :woman_facepalming: :man_facepalming:
- Find a better solution to compare two virtual nodes
- Ensure consistency and avoid unecessary rerendering that sometimes occur for the same DOMNodes :question:
- Make a better abstraction concerning the reconciler (it's a really first step)
- Rely on Go good practices (reference passing, better algorithms and so forth...)
- Generating the API doc and adding decent comment in code
- Find a way to abstract the
[]js.Value
passed in every event handler