The world’s easiest introduction to WebAssembly🕹
- Do you think that WebAssembly (WASM) is only used for image manipulation, hard math, or other niche use cases on the web?
- Are you still confusing WASM with
- Do you want to do frontend web development in non-JS languages?
Our goal is to create a simple game for cats 🐈: moving a red laser on mobile with some 🔈 audio effects and vibrations. We will implement everything in Golang (Go), including DOM manipulation, logic, and state.
Aaaaaand since, cats cannot use a mouse, we’ll need touch interaction for those cat paws 🐾.
Think of WASM as the Universal Virtual Machine (sandbox), where you write ANY code once, and it runs everywhere.
WASM is a compile target, not a language. As if you were to compile for Windows, Mac OS, and Linux at once!
I don’t think that WASM is about dethroning JS, it’s about having alternatives without any sacrifices.
Imagine all the people that are developing in Go, Swift, Rust, Ruby, C++, OCaml or others. Now, they can use their preferred language to create an interactive, networked, fast, offline-capable websites and web apps.
Have you ever been part of a discussion about whether your project will be a mono-repo or a multi-repo?
You’re now also going to have a discussion about whether your project is a mono-language or a multi-language.
When people can work with the same tech stack, everything becomes easier. Especially communication between teams.
You can still use React, Vue but now you’re not forced to use JS anymore.
How is WASM different from the Service and Web Workers?
Service & Web Workers allow you to run background, offline & caching processes. They mimic threading, don’t have access to DOM and can’t share the data (only through messaging) and are running in a separate context. Heck, you could even run WASM instead of JS in them. To me, they only provide some abstraction layer with special privileges, nobody said that these layers have to execute JS.
Service & Web Workersare a browser feature, they are not some exclusive JS feature.
Setup the dev env 💻
We’re going to use WASM, Go, JS and (optionally) Docker 🐳.
Use your local
go, I’m using
golang:1.12-rc Docker image. Just set two WASM flags for the
go compiler here. Create a simple hello world within
main.go to test it.
$ GOOS=js GOARCH=wasm go build -o game.wasm main.go
Now, grab the
wasm_exec.js glue provided by the Go team. This
Go global abstracts WASM initiation. We don’t have to craft any DOM abstraction from scratch 😼. Finally,
.wasm file and run our game.
All in all, it should look like this:
Show me the Go code already!
To render our simple game,
<canvas> should be sufficient. We can create the DOM structure and elements right from the Go code! That
syscall/js (included as a standard Go package) handles the
DOM interaction for us.
I bet you haven’t seen
main() in a long time 😅.
Looks pretty similar to JS, doesn’t it?
Yes, that’s all you need to interact with the
DOM! Just a few
Call functions for now.
At this point, I was asking myself. I’m still kind of writing JS in some way… how is this an upgrade? Because we don’t have direct access to the DOM yet, we have to resort to calling the DOM (via JS) in order to do anything. Imagine how you could abstract this away with let’s say, JSX/React. Actually, you already can, but let’s leave that for my next article 😉.
“Rendering” and the event handling
Directly using the
syscall/js lib reveals some ES5-like callbacks. We are able to listen for the DOM events. Looks very clean with those static types!
Logging, Audio and “async”
In Go, there is a convention to write all the
func in a sync way. It’s up to the caller to decide whether
func is async. Making a
func run asynchronously is really easy. Just prefix it with
go and there you go! It creates a thread with its own context. You can still bind the parent context to it, don’t worry.
Running our game forever! ♾
That code creates an unbuffered channel, and attempts to receive from it. And since no-one ever sends anything on it, it’s essentially a blocking forever operation, allowing us to run our program forever.
Updating the game state and moving the red laser
No state management to see here, just a simple typed
struct, that doesn’t allow you to pass any incorrect values inside.
The fact that WASM is still considered an MVP (MAP) and that you can create a game like this, without writing a single line of JS, is amazing! CanIUse is already fully green, there is nothing stopping you from building WASM powered websites and apps.
Look, you can combine all the languages you want, event JS -> WASM. In the end, they’ll all compile down to the WASM bytecode. If you need to share anything between them, you can, because they can share a raw memory.
What I’m afraid of is, in recent news, we learned that Microsoft is building a Chromium browser and Firefox market share is below 9%. This gives Google a kill switch power over WASM. If they don’t go with it, masses may never know.
Who is using WASM already?
Agreed, my example just draws a full-page
canvas . Here are more advanced examples that focus on the semantic web awesome-wasm#web-frameworks-libraries.
WASM in the Web3 era
Nowadays, if you want to use some Ethereum wallet on the mobile web, you have to download a mobile wallet like Status.im from some centralized App Store and trust all the parties.
How about a Progressive Web App that would run
geth (Go Ethereum client) with light sync over WebRTC? It could use
Service Worker to update its WASM code and run in it the background, could be hosted on IPFS/Dat.
Useful WASM articles, resources & goodies 🔧
- WebAssembly is more than the web
- WebAssembly and Go: A look at the future and the HN comments
- posts by Mozilla Hacks & Hacker News
- WebAssembly architecture for Go
Thanks to https://github.com/twifkak for optimizing Go on the Chrome for Android!
Next article? ✍️
We will take a look at interoperability with JS modules & React. Stay tuned!
If you liked it and would like to see more content, don’t forget to follow and keep pressing that clap button 😌.
About me ⚡️
Also check out https://www.seasy.at/ ⛵️