Recently, I came across a blog post about converting parts of a JavaScript library into WebAssembly. The part that interested me the most was a section about efficiently embedding the WebAssembly binary into the JavaScript code such that the library could be distributed as a single file, instead of the usual method of providing the WebAssembly binary as a separate file. This is accomplished by Base64-encoding the WebAssembly binary as a string and including the resulting string in the JavaScript file. Unfortunately, this significantly inflates the total file size, since the Base64-encoded string does not compress nearly as well as the original binary. To mitigate this issue, the blog post author had the clever idea of gzip-compressing the binary prior to Base64-encoding it and using the zlib.js JavaScript library to decompress the binary client-side, after undoing the Base64-encoding. While this significantly reduced the size of the Base64-encoded WebAssembly binary, it required ~6.5 kB for the decompression code, after gzip compression.1
While I liked the idea of compressing the WebAssembly binary prior to Base64-encoding it, I thought there must be a way of decompressing it with a smaller decompression code. The simplest change would be to use a raw Deflate-compressed payload instead of one encapsulated with gzip, as the zlib.js library also provides a decompression function for this, which is only ~2.5 kB after gzip-compression, saving ~4 kB. However, this is still excessive, since it shouldn’t be necessary to provide a Deflate decompression function as web browsers include such functionality. Although such decompression functionality isn’t exposed directly to JavaScript, PNG images can be decoded from JavaScript, and PNG images use Deflate compression. Thus, I decided to encode the WebAssembly binary as a grayscale PNG image, Base64-encode the PNG as a data URI, and include the resulting string in the JavaScript file. Continue reading
The author mentioned 12 kB of decompression code, but that was without gzip-compression of the JavaScript code. ↩