Skip to content

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

Merged
Madoshakalaka merged 14 commits intomasterfrom
yew-link
Apr 14, 2026
Merged

feat: add yew-link crate for unified SSR/CSR data fetching#4027
Madoshakalaka merged 14 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 67c54e2):

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

(expires Tue, 21 Apr 2026 13:21:49 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.322 295.722 292.199 1.610
Hello World 10 490.974 498.228 494.394 2.468
Function Router 10 31582.986 32051.284 31795.879 178.854
Concurrent Task 10 1005.358 1008.298 1007.207 0.762
Many Providers 10 1099.999 1137.107 1113.567 12.600

Pull Request

Details
Benchmark Round Min (ms) Max (ms) Mean (ms) Standard Deviation
Baseline 10 294.474 307.257 298.394 4.076
Hello World 10 494.938 511.830 502.660 6.648
Function Router 10 31846.938 32278.908 32054.113 116.898
Concurrent Task 10 1007.809 1009.084 1008.295 0.367
Many Providers 10 1137.252 1176.647 1157.080 12.911

@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.166 N/A N/A
async_clock 100.054 100.054 0 0.000%
axum_ssr_router N/A 611.165 N/A N/A
boids 163.882 163.882 0 0.000%
communication_child_to_parent 93.483 93.483 0 0.000%
communication_grandchild_with_grandparent 105.467 105.467 0 0.000%
communication_grandparent_to_grandchild 101.821 101.821 0 0.000%
communication_parent_to_child 90.894 90.894 0 0.000%
contexts 105.709 105.709 0 0.000%
counter 85.742 85.742 0 0.000%
counter_functional 87.755 87.755 0 0.000%
dyn_create_destroy_apps 89.633 89.633 0 0.000%
file_upload 99.250 99.250 0 0.000%
function_delayed_input 94.374 94.374 0 0.000%
function_memory_game 169.549 169.549 0 0.000%
function_router 399.260 399.260 0 0.000%
function_todomvc 164.196 164.196 0 0.000%
futures 234.741 234.741 0 0.000%
game_of_life 100.489 100.489 0 0.000%
immutable 258.379 258.379 0 0.000%
inner_html 80.586 80.586 0 0.000%
js_callback 109.293 109.293 0 0.000%
keyed_list 175.911 175.911 0 0.000%
mount_point 83.953 83.953 0 0.000%
nested_list 112.851 112.851 0 0.000%
node_refs 91.469 91.469 0 0.000%
password_strength 1717.778 1717.778 0 0.000%
portals 93.107 93.107 0 0.000%
router 365.998 365.998 0 0.000%
suspense 113.165 113.165 0 0.000%
timer 88.326 88.326 0 0.000%
timer_functional 98.785 98.785 0 0.000%
todomvc 141.351 141.351 0 0.000%
two_apps 85.927 85.927 0 0.000%
web_worker_fib 136.226 136.226 0 0.000%
web_worker_prime 184.621 184.621 0 0.000%
webgl 82.729 82.729 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.459 ns      │ 2.484 ns      │ 2.464 ns      │ 2.465 ns      │ 100     │ 1000000000

Pull Request

vnode           fastest       │ slowest       │ median        │ mean          │ samples │ iters
╰─ vnode_clone  2.459 ns      │ 2.654 ns      │ 2.467 ns      │ 2.47 ns       │ 100     │ 1000000000

Comment thread examples/ssr_router/tests/e2e.rs Outdated

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

Comment thread packages/yew-link/src/lib.rs Outdated
Comment thread packages/yew-link/src/lib.rs Outdated
@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 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 7, 2026
github-actions[bot]
github-actions bot previously approved these changes Apr 9, 2026
github-actions[bot]
github-actions bot previously approved these changes Apr 9, 2026
github-actions[bot]
github-actions bot previously approved these changes Apr 14, 2026
Copy link
Copy Markdown
Member Author

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

I have reviewed this to the best of my effort.

@Madoshakalaka Madoshakalaka merged commit 9d3e9ba into master Apr 14, 2026
41 checks passed
@Madoshakalaka Madoshakalaka deleted the yew-link branch April 14, 2026 13:38
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