Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Splitting and lazy loading wasm modules #52

Open
sendilkumarn opened this issue Feb 12, 2018 · 14 comments
Open

Splitting and lazy loading wasm modules #52

sendilkumarn opened this issue Feb 12, 2018 · 14 comments

Comments

@sendilkumarn
Copy link
Member

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.

@Pauan
Copy link

Pauan commented Feb 12, 2018

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.

@est31
Copy link

est31 commented Feb 13, 2018

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.

@linclark
Copy link

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).

@sendilkumarn
Copy link
Member Author

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

@fitzgen
Copy link
Member

fitzgen commented Feb 13, 2018

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.

@najamelan
Copy link

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.

@giacomocariello
Copy link

Any news on this?

@tlively
Copy link

tlively commented Aug 12, 2020

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.

@wdanilo
Copy link

wdanilo commented May 17, 2022

Hi! Is there any progress in this regards? :)

@tlively
Copy link

tlively commented May 17, 2022

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.

@wdanilo
Copy link

wdanilo commented May 17, 2022

Oh, that's super interesting! Thanks for letting me know. I'm so sad that wasm-pack does not support it though :/

@lukechu10
Copy link

I'm not familiar with how the wasm-split tool works. Any chance something similar could be built for the wasm32-unknown-unknown target?

@tlively
Copy link

tlively commented May 17, 2022

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.

@jbms
Copy link

jbms commented Apr 29, 2024

I've built a prototype that addresses this issue in what I think is quite an elegant way. See rustwasm/wasm-bindgen#3939

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests