Minimizing Go WebAssembly Binary Size
Minimizing Go WebAssembly Binary Size
https://dev.bitolog.com/minimizing-go-webassembly-binary-size/

In both of the previous posts I’ve described different aspects of WebAssembly. The first of the two explained what WebAssembly is and how to run a simple Go WebAssembly application in the browser. The second post was a Go WebAssembly performance benchmark. If you are unfamiliar with Go WebAssembly, I’d recommend reading the first post before diving into this one. In this post I’m going to discuss the Go WebAssembly binary size.
While working with Go WebAssembly I’ve noticed that the .wasm
binary files are quite big. Not huge for my simple tests, but several MBs for a just a few functions.
That made me ask myself – is that the best we can get assuming we want
these files to be served over the web? In this blog post I’ll show you
how to minimize your Go WebAssembly binary size so it will be much more
web friendly.
Current State
Going back to my encoding example from the introductory post, you can see that the encode.wasm
Go WebAssembly binary file size is roughly 2MB:

Currently the encoding function code imports only two packages:
import (
"encoding/base64"
"syscall/js"
)
If I was to import another package, let’s say the fmt package, how do you think that will affect the .wasm
binary file size? let’s try it out:

That’s a lot. Importing a simple and basic package such as fmt
costs us roughly 0.4MB. A takeaway from this is that you need to keep in mind that packages imports leads to a larger binary file.
For the rest of this post, I’ll remove the fmt
package and work with the original code.
First Try – Serving Gzipped Content
For my first attempt to reduce the .wasm
file size, I ran my server with a gzip handler. This means that every file being served to the browser is first compressed using gzip on the server side, and extracted by the browser. You can read more about the method of serving compressed files here.
For the purpose of this test I used the gziphandler package in order to create a handler that compresses server responses:
package main
import (
"github.com/NYTimes/gziphandler"
"log"
"net/http"
)
func main() {
err := http.ListenAndServe(":8080",
gziphandler.GzipHandler(http.FileServer(http.Dir("/path/to/served/files"))))
if err != http.ErrServerClosed {
log.Fatal(err)
}
}
Now let’s see how much do we benefit by doing so:

Well this is not bad at all. Gzipping the content reduced the file size by about 75% from 2MB to 0.5MB. You can see that the time it takes to serve the file increased dramatically, that is because the gzip extraction process is more complex than simply serving static files.
Can we do it better?
Second Try – TinyGo
From the official homepage:
TinyGo is a project to bring the Go programming language to microcontrollers and modern web browsers by creating a new compiler based on LLVM.
[…] It can also be used to produce WebAssembly (WASM) code which is very compact in size.
TinyGo hompage – https://tinygo.org/
In other words – TinyGo is a Go compiler, focused on creating small binaries. Since TinyGo does not aim to compile any possible Go program, it lacks some language and packages support. In other words, this means that you might need to modify your code in order for it to be compiled by TinyGo.
Luckily for me, both of the packages my code imports are fully supported by TinyGo:



Now that we understand it’s purpose, let’s give it a try.
I chose to install TinyGo on my machine, you can also use a Docker image if you don’t want to install it locally. The official documentation on using TinyGo for WebAssembly is available here.
Compiling Using TinyGo
Now I needed to compile my main.go
file to encode.wasm
using the TinyGo compiler. This will replace the older 2MB file:
$ tinygo build -o encode.wasm -target wasm main.go
After creating the binary file, I then tried refreshing my browser session, only to get the following weird error:
Uncaught (in promise) TypeError: WebAssembly.instantiate(): Import #0 module="wasi_unstable" error: module is not an object or function
Well, turns out that the JavaScript glue code (which we talked about) used by the TinyGo compiler is a different one. So I had to replace it:
$ cp $(tinygo env TINYGOROOT)/targets/wasm_exec.js .
Now refreshing worked, and so did my basic application!
Let’s take a look a the file size: **drums**

Amazing! We got our .wasm
binary file down from 2MB to 86KB.
Key Takeaways
- Go WebAssembly is still in early stages but as you can see it’s quite ready to handle various use cases.
- Decreasing the binary file size can be a bit tricky for larger applications but is feasible.
- I would definitely recommend experimenting with this interesting technology which, in my opinion, we’ll see more and more of in the future as it matures.
As always, feel free to comment, like and share. See you on the next one!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
2019-12-15 Linux stress 命令