Smaller Files, Load WASM Faster with TinyGo

  • YC YC
  • |
  • 06 November 2023
post-thumb

It’s been some time since I last made any changes to the mortgage calculator tool which I initially developed in Golang and compiled as WebAssembly code, after finalizing my property purchase and mortgage settlement in 2022. Now, as I approach the need to refinance my loan and given the recent CPF ceiling adjustment, I believe it’s high time to refresh and enhance the mortgage calculator.

Compiling with Go 1.17

To compile the code, the following mage target was used.

// WASM compile the program into WebAssembly.
func WASM() error {
	env := map[string]string{
		"GOOS":   "js",
		"GOARCH": "wasm",
	}

	return sh.RunWithV(env, "go", "build", "-ldflags", "-s -w", "-o", "mortgage.wasm")
}

The program is then compiled using the Go toolchain and Go version 1.17, which was the version used at the time. This results in a program build size of 2.88MiB. Consequently, when a user initially uses the mortgage calculator tool, they have to download a 2.88MiB file, which might not appear significant on a wired connection but can cause slower page loading and increased data costs on mobile devices.

Attempting with latest Go 1.21

To minimize the build size, the program was recompiled using Go 1.21. Surprisingly, the resulting build expanded to 3.1MiB, which represents an increase of approximately 7.6% in size. This increase in size might be attributed to the introduction of reproducible builds.

TinyGo to the rescue

Next, I investigate the possibility of utilizing TinyGo for program compilation. TinyGo describes itself as Go on embedded systems and WebAssembly where it can also produce WebAssembly code that is very compact in size.

TinyGo can also produce WebAssembly (WASM) code which is very compact in size. You can compile programs for web browsers, as well as for server and edge computing environments that support the WebAssembly System Interface (WASI) family of interfaces.

The setup process is remarkably simple, and I managed to install it on my Ubuntu Windows Subsystem for Linux (WSL) in under 10 minutes by following the provided guide.

Then I wrote the following mage target to compile the program with TinyGo.

// TinyWASM compile the program into WebAssembly using TinyGo.
func TinyWASM() error {
	env := map[string]string{
		"GOOS":   "js",
		"GOARCH": "wasm",
	}

	return sh.RunWithV(env, "tinygo", "build", "-target", "wasm", "--no-debug", "-o", "mortgage.wasm", "./main.go")
}

The output file size has significantly decreased to just 492KiB, down from the original 2.88MiB. This represents an impressive 83% reduction in file size!

Conclusion

While the official Golang toolchain is the most common and straightforward method for compiling and creating a WASM program from Go code, relying solely on builds generated by the official Go toolchain might not always be the most efficient or practical choice. Therefore, it could be beneficial to investigate alternative compilers like TinyGo and become acquainted with the advantages and specific use cases they offer.

comments powered by Disqus

You May Also Like