Skip to content

feat: add yew-link crate for unified SSR/CSR data fetching#4027

Open
Madoshakalaka wants to merge 10 commits intomasterfrom
yew-link
Open

feat: add yew-link crate for unified SSR/CSR data fetching#4027
Madoshakalaka wants to merge 10 commits intomasterfrom
yew-link

Conversation

@Madoshakalaka
Copy link
Copy Markdown
Member

@Madoshakalaka Madoshakalaka commented Mar 1, 2026

Description

Closes #2649, whose lower-level half includinguse_prepared_state and use_transitive_state is already shipped

This PR implements the higher-level half of #2649: a yew-link crate that unifies SSR, hydration, and client-side data fetching behind a single hook.

The mentioned lower-level hooks already carry server-computed state to the client during hydration. But after that initial page load, client-side navigation requires a completely separate fetch path. This means every data-dependent component needs two code paths stitched together manually. yew-link closes this gap.

Implemented new crates proposed in the pr: yew-link and yew-link-macro

Overhauled ssr_router example, rewired to use yew-link instead of generating content inline. Demonstrates #[linked_state], LinkProvider, use_linked_state, Resolver::register_linked, and the axum handler, with full SSR-to-hydration state transfer and client-side nav fetching.

See the new website changes to understand the usage pattern

Comparison with Bounce's Query API

@futursolo's Bounce, whose Query API and use_prepared_query hook do overlapping but not identical work

yew-link has bounded cache: client-side cache uses lru::LruCache (default 64 entries, configurable via LinkProvider's cache_capacity prop). Dependency gated to wasm32 only.

yew-link has more granular code isolation as its #[linked_state] strips resolve() from WASM and Query::query() body is always compiled into WASM.

yew-link also provides better utility by its built-in linked_state_handler for axum and actix-web (gated by respective features)

Checklist

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

I have overhauled the ssr_router to use yew-link.

I have overhauled the ssr_router's E2E test too:

  1. Directly visiting a post by its url post/0 receives a server-rendered page with no extra fetch requests.
  2. vist the posts page first, click on the anchor of posts with the id 0, in-app navigation happens and fetch happens exactly once
  3. the post contents in 1 and 2 match

I'm not sure how cargo release in our .github/workflows/publish.yml handles the two added new crates, but that's a matter for the future when when publish yew-link with yew 0.24

github-actions[bot]
github-actions bot previously approved these changes Mar 1, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 1, 2026

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

https://yew-rs--pr4027-yew-link-ts30s1c0.web.app

(expires Tue, 14 Apr 2026 15:52:15 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

github-actions[bot]
github-actions bot previously approved these changes Mar 1, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 1, 2026

Benchmark - SSR

Yew Master

Details
Benchmark Round Min (ms) Max (ms) Mean (ms) Standard Deviation
Baseline 10 291.282 293.893 291.962 0.885
Hello World 10 505.239 512.654 507.483 2.427
Function Router 10 31637.535 31960.582 31830.565 93.154
Concurrent Task 10 1006.150 1007.736 1007.118 0.623
Many Providers 10 1303.776 1432.563 1336.258 38.909

Pull Request

Details
Benchmark Round Min (ms) Max (ms) Mean (ms) Standard Deviation
Baseline 10 291.266 295.971 291.864 1.448
Hello World 10 485.925 501.467 491.952 5.573
Function Router 10 31153.259 31970.499 31710.755 241.250
Concurrent Task 10 1006.156 1007.831 1007.104 0.603
Many Providers 10 1088.739 1194.718 1115.010 32.826

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 1, 2026

Size Comparison

Details
examples master (KB) pull request (KB) diff (KB) diff (%)
actix_ssr_router N/A 611.871 N/A N/A
async_clock 99.933 99.933 0 0.000%
axum_ssr_router N/A 611.872 N/A N/A
boids 164.027 164.027 0 0.000%
communication_child_to_parent 93.359 93.359 0 0.000%
communication_grandchild_with_grandparent 105.338 105.338 0 0.000%
communication_grandparent_to_grandchild 101.696 101.696 0 0.000%
communication_parent_to_child 90.771 90.771 0 0.000%
contexts 105.584 105.584 0 0.000%
counter 85.941 85.941 0 0.000%
counter_functional 87.976 87.976 0 0.000%
dyn_create_destroy_apps 89.864 89.864 0 0.000%
file_upload 98.950 98.950 0 0.000%
function_delayed_input 93.931 93.931 0 0.000%
function_memory_game 169.575 169.575 0 0.000%
function_router 398.704 398.704 0 0.000%
function_todomvc 164.481 164.481 0 0.000%
futures 234.661 234.661 0 0.000%
game_of_life 100.274 100.274 0 0.000%
immutable 258.191 258.191 0 0.000%
inner_html 80.464 80.464 0 0.000%
js_callback 109.425 109.425 0 0.000%
keyed_list 175.892 175.892 0 0.000%
mount_point 83.833 83.833 0 0.000%
nested_list 113.023 113.023 0 0.000%
node_refs 91.347 91.347 0 0.000%
password_strength 1718.561 1718.561 0 0.000%
portals 92.836 92.836 0 0.000%
router 365.078 365.078 0 0.000%
suspense 113.531 113.531 0 0.000%
timer 88.079 88.079 0 0.000%
timer_functional 98.696 98.696 0 0.000%
todomvc 141.760 141.760 0 0.000%
two_apps 85.805 85.805 0 0.000%
web_worker_fib 135.942 135.942 0 0.000%
web_worker_prime 184.321 184.321 0 0.000%
webgl 82.606 82.606 0 0.000%

✅ None of the examples has changed their size significantly.

github-actions[bot]
github-actions bot previously approved these changes Mar 1, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 4, 2026

Benchmark - core

Yew Master

vnode           fastest       │ slowest       │ median        │ mean          │ samples │ iters
╰─ vnode_clone  2.625 ns      │ 3.879 ns      │ 2.642 ns      │ 2.686 ns      │ 100     │ 1000000000

Pull Request

vnode           fastest       │ slowest       │ median        │ mean          │ samples │ iters
╰─ vnode_clone  2.466 ns      │ 3.301 ns      │ 2.482 ns      │ 2.496 ns      │ 100     │ 1000000000


// -- Part 2: Navigate to /posts within the same app, then to /posts/0 --

yew::scheduler::flush().await;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

these flush turned out to be very neccessary. Without them the ssr tests fails.

When .click() fires on the element, yew's event delegation hasn't processed it yet (scheduler is deferred to the microtask queue). So the browser's default anchor behavior kicks in - it performs a real navigation to /posts, which crashes the test runner.

@Madoshakalaka
Copy link
Copy Markdown
Member Author

I've done some external testing too

My work has an SSR Axum-Yew app totaling 40k+ lines of rust. I've patched the project's dependency to use yew-link and migrated a handful of bounce's use_prepared_query to yew-link and saw good code simplification and no test failure.

@Madoshakalaka Madoshakalaka marked this pull request as ready for review March 7, 2026 14:33
github-actions[bot]
github-actions bot previously approved these changes Mar 7, 2026
github-actions[bot]
github-actions bot previously approved these changes Mar 14, 2026
github-actions[bot]
github-actions bot previously approved these changes Apr 4, 2026
wasm-bindgen 0.2.115+ introduced incremental DOM scraping that assumes
#output content is append-only. The SSR E2E tests replace #output via
set_inner_html, breaking the offset tracker and causing the runner to
miss test results. WASM_BINDGEN_TEST_NO_STREAM falls back to reading
full text each poll.
github-actions[bot]
github-actions bot previously approved these changes Apr 4, 2026
github-actions[bot]
github-actions bot previously approved these changes Apr 5, 2026
github-actions[bot]
github-actions bot previously approved these changes Apr 5, 2026
github-actions[bot]
github-actions bot previously approved these changes Apr 5, 2026
github-actions[bot]
github-actions bot previously approved these changes Apr 5, 2026
github-actions[bot]
github-actions bot previously approved these changes Apr 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-yew-link Area: The yew-link crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Send states created during SSR alongside SSR artifact to be used with client-side rendering hydration

2 participants