Speed up source-map generation with WebAssembly: Google Summer of Code 2018
Try out the new WebAssembly powered dependency for webpack: 60% faster for source-map devtool and 20% for cheap-source-map devtool.
WebAssembly, or WASM, is a new technology that enables code to be compiled and run faster in web and server applications. In this project,
webpack-sources, one of the core packages of Webpack, and its dependencies
Although it has not yet been released as a default dependency in Webpack, you can simply try it out with
webpack-cli. See the Github project for more information.
The project repository and npm package:
A significant performance enhancement when using our package
wasm-webpack-sources to build a large project with source-map and cheap-source-map devtool. For other test items, including normal build (without devtool) and build with cheap-source-map, the performance is a tie.
With the help of
WebAssembly is powerful, yet it requires developers to program in low level and manage annoying issues like memory management by themselves. These issues also include how to pass data to functions WebAssembly instance and get the return values.
As aforementioned, our target
webpack-sources has two major dependencies:
source-map. These two are maintained by different team, webpack and mozilla, and published in npm as separate packages. In our project, these three packages are merged into one WebAssembly binary and released as one big npm package now for performance concerns.
wasm-bindgen can create useful wrappers for our binary, it is still too simple to achieve our final goal: API compatibility.
Thanks to the API compatibility, the WebAssembly can directly replace the old module without any changes in Webpack and plugins. However, it is still a trouble to do the replacement. To alleviate this problem, a
register() function is provided in our module, and it will be called automatically when the module is required. When this function is called, it will override the resolve of the old package
webpack-sources with it, and webpack and plugins which load
webpack-sources will all be "redirected" to load our module. Moreover, it is also possible to use with
webpack-cli with nothing more than an additional command line argument.
Even though our package is still experimental, you can always give it a try with little effort and enjoy the performance enhancement from WebAssembly.
Although WebAssembly has been shown to have the ability to bring considerable performance enhancement in various cases, naively rewriting everything into Rust and compiling to WebAssembly will not make the performance better but sometimes even worse. We always need to deal with performance sensitive part carefully.
Fast string split in Rust
When processing the codes in
StringSlice to mitigate this problem.
In our implementation, each
StringSlice is stored with a reference counter. When creating a substring from a
StringSlice, instead of allocating memory space for the new string, we create a new
StringSlice instance with the pointer pointing to the original string's address and its length, then increment the reference counter. This method can avoid redundant memory allocation/copy as well as maintain the lifetime of used memory for Rust to perform the memory management at the right moment.
Garbage Collection / Memory Deallocation
In old package
This issues can be solved by adding codes to deallocate objects in webpack and plugins, or wait until garbage collection is introduced to WebAssembly.
WebAssembly is only supported by Node.js version greater than 8. However, there are many people still using webpack with Node.js 6. Thus, a fallback is necessary for runtime not supporting WebAssembly. To make it possible, we can compile our Rust code into
asm.js version. To overcome this issue, another wrapper needs to be done for
Since this package is still under experiment, this issue is not urgent and can be completed before releasing as default dependency of webpack.
With our new package
wasm-webpack-sources, source-map genration is 60% faster and cheap-source-map generation is 20% faster than before. The package is now released in npm and welcoming performance feedbacks and bug reports. Further improvement can be made to make it even better and ready to be the default dependency in webpack.