Open sendilkumarn opened 6 years ago
JavaScript has an official way to lazy-load modules: the import()
expression. This allows it to delay loading the module until it is needed. Naturally this allows for lazy-loading .wasm
files as well, because .wasm
files are ES6 modules.
I'm not sure if there are plans to support import()
directly in WebAssembly, but it should be possible to accomplish something similar by having WebAssembly call into JavaScript, and then JavaScript can do the actual import()
call.
However, it is important to note that the import()
expression always loads modules relative to the file which contains the import()
. So if you have a WebAssembly file foo.wasm
, and a JavaScript file bar/qux.js
, and the JavaScript file uses import()
, then it will always import the modules relative to the bar
directory. So when doing the lazy-loading, it will have to take that into account and compensate for it.
Wasm modules don't support splitting up well yet, as shared components like allocators must be included in every component. For this to work well, we'd need dynamic linking support.... right now apparently they want you to go through js but I doubt that this is fast enough for usage in e.g. an allocator. IDK though, maybe js engines can inline such a layer.
I'm not sure if there are plans to support import() directly in WebAssembly, but it should be possible to accomplish something similar by having WebAssembly call into JavaScript, and then JavaScript can do the actual import() call.
The plan is to eventually have WASM modules just be ES modules. Once that's in place, import()
should just work for WASM modules (unless there's some complication I'm missing).
unless there's some complication I'm missing
Well I am not sure, as @est31 points out there is an ambiguity in sharing allocators and dynamic linking of the wasm modules.
using them as ES Modules
is clear. But how can we split one giant wasm file into separate modules
I think we could split at the crate boundary, assuming one of
All of an upstream crate's API was extern "C"
(Annoying)
We define a Rust ABI that maps onto wasm. (Hard)
Exported generics, if allowed, would have to be monomorphised into the downstream crate, I guess.
Basically, it is the same issues we run into when splitting an existing binary across multiple dylibs... Which Rust doesn't have a great story for.
I wonder if we can make any progress on this. wasm-bindgen now supports wasm-pack --target web
which exports wasm as a ES module.
There is documentation on the webassembly website about dynamic loading using module imports/exports.
It would be nice to be able to compile libraries as dylibs that can be linked against for other components.
Any news on this?
FYI I have plans to implement profile-guided module splitting functionality in Binaryen to facilitate lazy loading of code that is not needed for startup. Once that work is farther along, perhaps we can coordinate on a way to expose that functionality ergonomically in wasm-pack.
Hi! Is there any progress in this regards? :)
FWIW Binaryen now has a wasm-split
tool that does what I described back in 2020. It's integrated into Emscripten and documented here: https://emscripten.org/docs/optimizing/Module-Splitting.html#module-splitting.
This should work out of the box with Rust when compiling to the wasm32-unknown-emscripten target, but that's unfortunately not compatible with wasm-pack.
Oh, that's super interesting! Thanks for letting me know. I'm so sad that wasm-pack does not support it though :/
I'm not familiar with how the wasm-split
tool works. Any chance something similar could be built for the wasm32-unknown-unknown
target?
wasm-split
itself isn't specific to Emscripten in any way, so it could be used with wasm32-unknown-unknown
. The only tricky part is that it requires some special new JS to be provided to the split module as an import, so whatever tool generates the JS would need to be told how to generate that extra code. Alternatively, you could maintain your own JS and add the extra code yourself.
I've built a prototype that addresses this issue in what I think is quite an elegant way. See https://github.com/rustwasm/wasm-bindgen/issues/3939
This issue arises based on this discussion.
When converting an entire library into a wasm module, it is quite often we end up in huge size wasm output (~equal to the binary size). This will surely affect the wide usage of wasm.
One important usage of wasm is to use native libraries in the web application straightaway for the speed and other benefits. Splitting of wasm into chunks / modules will have its own benefits. This will probably followed by lazy-loading of the binaries as and when needed.
While, streaming compiler looks promising for libraries that are medium sized. It is better to provide an option to chunk the wasm and load them easily.