WebAssembly is a project by Google, Microsoft, Mozilla, Apple, and others that aims to create a common binary and text format for the Web. Now let’s demystify WebAssembly step by step and get your hands on WebAssembly in real business.
1. The introduction
Through WebAssembly Advanced Series I: What Is WebAssembly and WebAssembly Advanced Series II: Which part of WebAssembly is in the compilation stage? After these two articles have an in-depth understanding of the origin, advantages and applicable scenarios of WebAssembly, the next is the time for practice to test the truth. Let’s apply WebAssembly in the micro channel applet scene together. Let wechat applet environment support decoding webP format (for those of you who do not know or have not heard of webP, please go to “Explore some things about webP”).
2. WebAssembly workflow
Before getting started, let’s take a look at how to load and run WebAssembly code: C/C++ / Rust/Java and other high-level language developed code or library -> Emscripten compilation -> WASM file -> combined with WebAssembly JS API -> run in the browser environment, as shown below:
In short, compile the front end LLVM/Emscripten process to get wASM files and glue JS. Wasm is then loaded with glue JS and converted to arrayBuffer format. Following compilation and instantiation, JavaScript can be used to communicate with WebAssembly.
The detailed procedure and the API for each procedure call are shown below:
3. The browser supports webP
Not sure where to start once you know the WebAssembly workflow? You can check out the libwebp open-source project at Github. Google already fully supports compiling libwebp as wASM and ASm.js. For systems that do not support WebAssembly or browsers that are incompatible with WebAssembly, you can drop down to using ASM.js at a slight performance loss. The specific compilation steps are shown in the figure below:
After compiling, we can get the WASM file and glue JS. We can then start a local service with “python -m SimpleHTTPServer 8080” and type http://localhost:8080 in the browser address bar to see the webP decoded image.
Finally, let’s summarize the process.
(1) Compile libwebp decoder library with LLVM/Emscripten/CMake tool to obtain WASM file and glue JS.
(2) Glue JS to apply memory, wASM file to compile, load and instantiate, export Module object.
(3) Use the WebpToSDL method on the Module object to decode webP and turn it into Canvas to render and display the final picture in the browser.
4. Wechat applet environment supports webP
Wechat applet is used to execute scripts and render components in different environments on Android/iOS.
On Android, the JavaScript code of wechat small program logic layer runs in V8, and the view layer is rendered by the self-developed XWeb engine based on Mobile Chrome 67 kernel, which naturally supports webP format. On iOS, the JavaScript code of wechat applet logic layer runs in JavaScriptCore, the view layer is rendered by WKWebView, and the host Safari browser kernel does not support webP format.
Through the content of section 3, we know that the browser environment has been able to support webP, so directly put the compiled WASM file and glue JS into the running environment of wechat applet, and then run. Too young too simple!
The idea of supporting webP in browser environment is that libwebp decodes webP -> JPG/PNG/GIF canvas image rendering display, which has changed the structure of the original image component.
While the component provided to developers by wechat Mini program is not allowed to change its original structure, So the alternative is libwebp decoding webP -> JPG/PNG/GIF RGB data -> JPG/PNG/GIF base64 -> back to JS and assigned to image SRC for rendering display.
Here are some of the bugs and optimizations I have encountered since libwebp compiled wASM files and glue JS, and until wechat applets run:
(1) The option of “-O3” should be added when compiling cmakelists. TXT to greatly improve the compilation speed.
(2) Compile cmakelists.txt with “-s USE_PTHREADS=0” option because iOS Safari is not compatible with ShareArrayBuffer.
(3) The option “-S ALLOW_MEMORY_GROWTH=1” should be added when compiling cmakelists. TXT, in order to solve OOM problem when decoding webP pictures with super-high resolution.
(4) Due to the compatibility of wechat small program environment, removing the sDL-related codes added during libwebp compilation in glue JS code can save about 100KB of space.
(5) Remove the code related to ENVIRONMENT_IS_NODE/ENVIRONMENT_IS_SHELL from the glue JS, because the wechat applet environment is not used.
(6) Due to the compatibility problems of iOS Safari browser, the streaming compilation and instantiation method in glue JS is removed and replaced with non-streaming compilation and instantiation method.
(7) Since WebAssembly is not yet integrated with <script type=’module’> or ES6 import statements, convert wASM files to base64 strings first. When glue JS runs the loading logic, turn Base64 into ArrayBuffer, compile and instantiate the Module object, and save the time of downloading wASM files from the server.
(8) When compiling cmakelists. TXT, “-s USE_LIBPNG=1” should be added to compile libpng. A library, and then convert RGB data obtained by webP decoding into PNG memory data through PNG decoding library, and then convert base64 back to JS. Finally, the value is assigned to the image SRC for rendering. The difficulty is that there is a problem in converting RGB to PNG memory data, but WASM cannot debug the code, so it can only debug the breakpoint through constructing the VS project of libpng, and finally locate the cause that data_size passed in when RGB is converted to PNG data is 0.
(9) glue the new WebAssembly in JS. The Memory code in WeChat small application runtime environment, will quote “refused to create a WebAssembly object without ‘unsafe – eval” error, Unsafe-eval must be added to the CSP setting in page-frame. HTML.
After stepping on so many pits, we can finally support webP in wechat applet environment. The performance of WebAssembly is better than JavaScript when decoding webP in different formats and resolutions.
5. Write at the end
While WebAssembly’s decoding performance is considerably faster than JavaScript’s, it lags far behind client-side decoding performance when it comes to webP with very large resolutions (such as 1920 x 1080). After comprehensive comparison of the performance and compatibility of various solutions, we still adopt the solution based on iOS client custom protocol WebPHttps, and the general steps are as follows:
(1) First of all, when the basic library of wechat small program judges that the developer uses webP format in the image component, it adds a webP header such as webpexample.png in the image SRC.
(2) Then, the client ensnares the webPHTTPS request through NSURLProtocol and downloads the corresponding webP data for decoding.
(3) Finally, the decoded image data is returned to the browser for rendering and display.
Finally, we have completed the implementation of wechat applet environment to support webP, please look forward to it.
The resources
- Webassembly introduction
- Load and run the WebAssembly code
- An exercise in WebAssembly for enterprise mailboxes
- Download and install — Emscripten 1.38.38 documentation
- Explore WebP
- Libwebp open source project
Personal public number: front-end development appreciation record