1. Introduction to WebAssembly
- Cross-platform, runs on any platform that supports WebAssembly, including web browsers, servers, mobile devices, etc.
- High performance, using a compact binary format that can be loaded and parsed quickly in a browser to improve application performance
- Security, using a sandbox model that isolates the code running in it to protect the system from malicious code attacks
- Portability, WebAssembly code can be generated from different programming languages through a compiler, so existing code can be easily converted to WebAssembly format
- Extensibility, WebAssembly supports backward-compatible version control and allows new instructions and features to be added in the future, making it more extensible
2. Cases
- autocad https://web.autocad.com/
- Online collaborative design tool figma https://www.figma.com/
- Google Earth https://earth.google.com/web/
- web version of photoshop https://photoshop.adobe.com/
- libreoffice for web https://lab.allotropia.de/wasm/
- WebAssembly implementation of virtual machine v86 https://github.com/copy/v86
- Running Go online https://goscript.dev/
- Running Python online https://pyscript.net/
More examples of using WebAssembly are available at https://madewithwebassembly.com/
3. Common WebAssembly non-front-end runtimes
The WebAssembly runtime is the environment in which WebAssembly code runs, it is responsible for loading WebAssembly modules, creating WebAssembly instances, and executing WebAssembly code.
- C/C++ implementation - wasmEdge, wasm3
- Rust - wasmer, wasmtime
- Go - WaZero
Wasm is supported by all major browsers and high versions of Nodejs.
4. Install WasmEdge
Since the new version of Docker supports WasmEdge, I also choose to use WasmEdge as the WebAssembly runtime locally for consistency within the container.
-
Download the Wasmedge binary
Download the binaries for your platform at https://github.com/WasmEdge/WasmEdge/releases.
1
wget https://github.com/WasmEdge/WasmEdge/releases/download/0.12.0/WasmEdge-0.12.0-darwin_x86_64.tar.gz
-
Unpack Wasmedge and install
If you need to copy to another directory, be careful to keep the bin, include and lib directories relative to each other, otherwise the following error will occur.
-
View Wasmedge version
5. Using TinyGo to compile WebAssembly programs
5.1 Advantages and disadvantages of using TinyGo
-
Advantages of using TinyGo
TinyGo is a subset of Go and allows you to write WebAssembly programs using the Go language.
Can be run directly on WasmEdge, no JavaScript environment required.
wasm files are small enough, a few tens of KB.
-
Disadvantages of using TinyGo
Some libraries in TinyGo are not available, such as net/http, etc. See https://tinygo.org/docs/reference/lang-support/stdlib/ for details.
TinyGo does not support all Go language features, such as Cgo, etc. See https://tinygo.org/docs/reference/lang-support/ for details.
5.1 Hello, World
-
Create a new main.go file
-
Compilation
1
tinygo build -o ./build/main.wasm -target=wasm
-
Run with WasmEdge
-
Create a new Dockerfile file
-
Compiling the container image
1
docker build -t shaowenchen/wasm-hello-world:tinygo .
-
Running the container image
6. Using Go to compile WebAssembly programs
6.1 Advantages and disadvantages of using Go
-
Advantages of using Go
You can use the syscall/js package to interact with JavaScript.
You can use the full range of Go language features and packages.
In the future, WebAssembly runtime support for GC may improve program size and performance.
-
Disadvantages of using Go
Requires JavaScript environment support by default.
Large size, several MB or even tens of MB, but many older projects compile to tens or hundreds of MB.
6.2 Hello, World
-
Create a new main.go file
-
Compilation
1
GOOS=js GOARCH=wasm go build -o ./dist/main.wasm
-
Run with node
Note that nodejs requires 12 and above to work.
-
Create a new Dockerfile file
-
Compiling the container image
1
docker build -t shaowenchen/wasm-hello-world:go .
-
Running the container image
6.3 Using syscall/js to interact with JavaScript data
The Go language provides the syscall/js package that can be used to interact with JavaScript.
-
Calling JavaScript functions in Go
The Global() function provided by the
syscall/js
package gets the object of the host JavaScript environment.1
js.Global().Get("console").Get("log").Invoke("Hello, World!")
Equivalent to
1
console.log("Hello, World!")
-
Calling Go functions in JavaScript
js.Global().Set
registers the object into the JavaScript environment, and themyfunc
function can be called directly in the browser front-end. -
Rewrite hello world and execute wasm in the browser page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
package main import ( "syscall/js" ) func main() { // Call the front-end function and print on the console js.Global().Get("console").Get("log").Invoke("Hello, World by Go") // Find the element with the ID hello and insert the text js.Global().Get("document").Call("getElementById", "hello").Set("innerHTML", "Hello, World! by Go") // Register the Go function to the front-end js.Global().Set("myfunc", js.FuncOf(myfunc)) // Do not exit immediately, otherwise an error will be reported <-make(chan bool) } func myfunc(this js.Value, args []js.Value) interface{} { println("myfunc called") // Get function parameters myfunc_arg0 := args[0].String() // Set variables in the front-end window object js.Global().Set("myfunc_arg0", myfunc_arg0) js.Global().Get("console").Get("log").Invoke(myfunc_arg0) return nil }
-
Copy wasm_exec.js wasm_exec.html file
The Go compiler comes with a sample example.
wasm_exec.js is used to load the execution of wasm in the browser, wasm_exec.html is an example.
-
Modifying wasm_exec.html
To demonstrate Go’s ability to interact with JavaScript data, here’s a slightly modified sample.
1
WebAssembly.instantiateStreaming(fetch("main.wasm")...
The fetch here should be the compiled wasm file, which defaults to
test.wasm
and is modified tomain.wasm
as needed.A new button is added here to call the Go function myfunc.
-
Check the effect
Start a local http service.
Visit the
http://localhost:8000/wasm_exec.html
page.Clicking the Run button, Go calls the front-end object, outputs the text, and inserts the text on the page.
Click callGoButton to call the Go function on the front end.
Access
windows.myfunc_arg0
in the console and get the value set by Go in the front-end object.
7. Summary
This article is mainly trying out some ways of writing WebAssembly in Go. Without additional configuration, the two quicker ways are.
- Write it in TingyGo and run it directly on WasmEdge
- written in Go, loaded with JS, and run on Nodejs
There is also an example of writing WebAssembly with Go 1.19 to interact with JavaScript functions and data.
The code in the text is available at https://github.com/shaowenchen/demo/tree/master/wasm-hello-world.
8. Ref
https://www.chenshaowen.com/blog/get-webassembly-programs-using-go.html