Skip to content

Wasm splitting in yew#3932

Open
WorldSEnder wants to merge 10 commits intoyewstack:masterfrom
WorldSEnder:split-wasm
Open

Wasm splitting in yew#3932
WorldSEnder wants to merge 10 commits intoyewstack:masterfrom
WorldSEnder:split-wasm

Conversation

@WorldSEnder
Copy link
Member

Description

Add a way to split the wasm bundle in multiple components. This modifies the build process, and uses relocation information emitted by llvm to identify where to "split". There's a bit of glue code in yew to ensure that messages sent to the lazy component are processed and properties are passed along without additional cloning.

The main part of the solution lives in https://github.com/WorldSEnder/wasm-split-prototype as of now. This was implemented in collaboration with the maintainer of leptos.

Checklist

  • I have reviewed my own code
  • I have added examples

@WorldSEnder WorldSEnder requested review from jstarry and ranile October 14, 2025 21:01
github-actions[bot]
github-actions bot previously approved these changes Oct 14, 2025
@WorldSEnder
Copy link
Member Author

WorldSEnder commented Oct 14, 2025

The review pings are mostly because I think both of you will find this interesting, not necessarily as an invite to dig into the code and give meaningful suggestions for improvements (but feel free to if you have the time).

github-actions[bot]
github-actions bot previously approved these changes Oct 16, 2025
@github-actions
Copy link

github-actions bot commented Oct 16, 2025

Benchmark - core

Yew Master

vnode           fastest       │ slowest       │ median        │ mean          │ samples │ iters
╰─ vnode_clone  2.05 ns       │ 3.318 ns      │ 2.059 ns      │ 2.497 ns      │ 100     │ 1000000000

Pull Request

vnode           fastest       │ slowest       │ median        │ mean          │ samples │ iters
╰─ vnode_clone  2.621 ns      │ 3.869 ns      │ 2.625 ns      │ 2.649 ns      │ 100     │ 1000000000

@github-actions
Copy link

github-actions bot commented Oct 16, 2025

Benchmark - SSR

Yew Master

Details
Benchmark Round Min (ms) Max (ms) Mean (ms) Standard Deviation
Baseline 10 291.175 292.917 291.601 0.544
Hello World 10 483.044 510.945 491.166 9.699
Function Router 10 31170.032 31963.366 31610.745 264.713
Concurrent Task 10 1006.238 1007.431 1006.903 0.424
Many Providers 10 1056.219 1084.603 1070.719 9.374

Pull Request

Details
Benchmark Round Min (ms) Max (ms) Mean (ms) Standard Deviation
Baseline 10 291.013 291.738 291.357 0.190
Hello World 10 465.238 476.853 469.039 3.277
Function Router 10 32312.297 34402.628 33020.111 631.322
Concurrent Task 10 1006.336 1007.649 1007.061 0.489
Many Providers 10 1070.362 1114.549 1092.624 12.653

github-actions[bot]
github-actions bot previously approved these changes Oct 22, 2025
@github-actions
Copy link

github-actions bot commented Oct 22, 2025

Visit the preview URL for this PR (updated for commit 26921f8):

https://yew-rs-api--pr3932-split-wasm-ahe0tdp5.web.app

(expires Tue, 24 Mar 2026 15:29:37 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

don't start fetching once per component, cache the vtable.
makes it possible to implement a helper macro without the user
pulling in an extra dependency and has tighter version requirements.
github-actions[bot]
github-actions bot previously approved these changes Mar 11, 2026
@github-actions
Copy link

github-actions bot commented Mar 11, 2026

Size Comparison

Details
examples master (KB) pull request (KB) diff (KB) diff (%)
async_clock 101.055 101.109 +0.055 +0.054%
boids 168.883 169.329 +0.446 +0.264%
communication_child_to_parent 94.509 94.812 +0.303 +0.320%
communication_grandchild_with_grandparent 106.350 107.028 +0.679 +0.638%
communication_grandparent_to_grandchild 102.690 103.391 +0.700 +0.682%
communication_parent_to_child 91.920 92.217 +0.297 +0.323%
contexts 106.413 107.521 +1.107 +1.041%
counter 87.230 87.293 +0.062 +0.072%
counter_functional 89.266 89.322 +0.057 +0.063%
dyn_create_destroy_apps 91.147 91.202 +0.055 +0.060%
file_upload 100.326 100.381 +0.055 +0.055%
function_delayed_input 95.237 95.299 +0.062 +0.065%
function_memory_game 174.094 175.243 +1.149 +0.660%
function_router 396.079 399.447 +3.368 +0.850%
function_todomvc 165.388 166.260 +0.872 +0.527%
futures 235.983 236.038 +0.055 +0.023%
game_of_life 105.531 105.594 +0.062 +0.059%
immutable 260.450 264.964 +4.514 +1.733%
inner_html 81.773 81.828 +0.055 +0.067%
js_callback 110.393 111.216 +0.823 +0.746%
keyed_list 180.711 181.015 +0.304 +0.168%
mount_point 85.147 85.204 +0.057 +0.067%
nested_list 114.090 114.570 +0.480 +0.421%
node_refs 92.517 92.815 +0.299 +0.323%
password_strength 1719.354 1719.660 +0.307 +0.018%
portals 93.994 94.290 +0.296 +0.315%
router 366.729 369.259 +2.530 +0.690%
split-wasm N/A 762.377 N/A N/A
suspense 114.397 115.605 +1.208 +1.056%
timer 89.368 89.431 +0.062 +0.070%
timer_functional 99.806 100.127 +0.321 +0.322%
todomvc 143.095 143.149 +0.055 +0.038%
two_apps 87.144 87.206 +0.062 +0.072%
web_worker_fib 137.044 137.690 +0.646 +0.472%
web_worker_prime 188.231 188.871 +0.640 +0.340%
webgl 83.921 83.984 +0.063 +0.076%

⚠️ The following examples have changed their size significantly:

examples master (KB) pull request (KB) diff (KB) diff (%)
contexts 106.413 107.521 +1.107 +1.041%
immutable 260.450 264.964 +4.514 +1.733%
suspense 114.397 115.605 +1.208 +1.056%

we accept the penalty of running a lot of lifecycle hooks twice:
once for the Lazy<_> component, once for the inner one, and just forward
messages and other things, instead of hacking around in Scope.
github-actions[bot]
github-actions bot previously approved these changes Mar 11, 2026
github-actions[bot]
github-actions bot previously approved these changes Mar 11, 2026
@WorldSEnder
Copy link
Member Author

I want to say that having wasm split support would probably cut down the size of all these different bundles in the current "Yew.rs in Yew" push.

github-actions[bot]
github-actions bot previously approved these changes Mar 11, 2026
Copy link
Member

@Madoshakalaka Madoshakalaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good now. I can't spot anything wrong.

can you suppress the warnings though?

split-wasm git:(split-wasm) ✗ ./build.sh
/home/maa/.cache/trunk/wasm-bindgen-0.2.114/wasm-bindgen
warning: function `start_now` is never used
   --> packages/yew/src/scheduler.rs:214:15
    |
214 | pub(crate) fn start_now() {
    |               ^^^^^^^^^
    |
    = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default

warning: `yew` (lib) generated 1 warning
    Finished `release` profile [optimized] target(s) in 0.11s
running wasm-bindgen
running wasm-opt
warning: unknown name subsection with id 3 at 25937
moving to dist dir

@Madoshakalaka
Copy link
Member

I want to say that having wasm split support would probably cut down the size of all these different bundles in the current "Yew.rs in Yew" push.

yeeaah

It'd be nice if you could add some wasm-split docs in the mdx files too. It will take a while for the rewrite to land anyway. I'll sync the docs there.

@Madoshakalaka Madoshakalaka mentioned this pull request Mar 16, 2026
11 tasks
Comment on lines +214 to +220
#[cfg(any(
test,
feature = "test",
not(target_arch = "wasm32"),
target_os = "wasi",
feature = "not_browser_env"
))]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this very unreadable. Unifying the entry points into the scheduler might make it more clear which target uses which loop.

The yield strategy in #4033 does not take the LOCK to prevent recursive re-entry, but duplicates code from here. This method is now basically only used in tests as a substitute for a sync flush (which should be fine). Nevertheless, I would try to clean this up in a follow up PR.

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

Successfully merging this pull request may close these issues.

2 participants