Skip to content

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

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

feat: add yew-link crate for unified SSR/CSR data fetching#4027
Madoshakalaka wants to merge 9 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.

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

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 f940776):

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

(expires Sun, 12 Apr 2026 23:02:50 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.164 292.767 291.474 0.473
Hello World 10 482.353 484.209 483.122 0.662
Function Router 10 31515.489 31816.914 31667.039 98.340
Concurrent Task 10 1006.265 1007.636 1007.159 0.426
Many Providers 10 1086.974 1133.517 1110.302 18.670

Pull Request

Details
Benchmark Round Min (ms) Max (ms) Mean (ms) Standard Deviation
Baseline 10 291.168 291.584 291.383 0.131
Hello World 10 482.457 509.495 487.205 8.271
Function Router 10 31506.714 31975.390 31787.090 169.029
Concurrent Task 10 1006.404 1008.278 1007.183 0.555
Many Providers 10 1086.358 1206.664 1115.604 34.002

@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 (%)
async_clock 99.932 99.932 0 0.000%
boids 163.820 163.820 0 0.000%
communication_child_to_parent 93.235 93.235 0 0.000%
communication_grandchild_with_grandparent 105.056 105.056 0 0.000%
communication_grandparent_to_grandchild 101.410 101.410 0 0.000%
communication_parent_to_child 90.646 90.646 0 0.000%
contexts 105.108 105.108 0 0.000%
counter 85.940 85.940 0 0.000%
counter_functional 87.975 87.975 0 0.000%
dyn_create_destroy_apps 89.865 89.865 0 0.000%
file_upload 98.949 98.949 0 0.000%
function_delayed_input 93.932 93.932 0 0.000%
function_memory_game 169.044 169.044 0 0.000%
function_router 398.069 398.069 0 0.000%
function_todomvc 164.068 164.068 0 0.000%
futures 234.660 234.660 0 0.000%
game_of_life 100.273 100.273 0 0.000%
immutable 257.886 257.886 0 0.000%
inner_html 80.463 80.463 0 0.000%
js_callback 109.086 109.086 0 0.000%
keyed_list 175.777 175.777 0 0.000%
mount_point 83.833 83.833 0 0.000%
nested_list 112.748 112.748 0 0.000%
node_refs 91.222 91.222 0 0.000%
password_strength 1718.438 1718.438 0 0.000%
portals 92.712 92.712 0 0.000%
router 364.772 364.772 0 0.000%
suspense 113.066 113.066 0 0.000%
timer 88.078 88.078 0 0.000%
timer_functional 98.567 98.567 0 0.000%
todomvc 141.759 141.759 0 0.000%
two_apps 85.804 85.804 0 0.000%
web_worker_fib 135.658 135.658 0 0.000%
web_worker_prime 184.060 184.060 0 0.000%
webgl 82.605 82.605 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.748 ns      │ 3.051 ns      │ 2.751 ns      │ 2.757 ns      │ 100     │ 1000000000

Pull Request

vnode           fastest       │ slowest       │ median        │ mean          │ samples │ iters
╰─ vnode_clone  2.749 ns      │ 4.064 ns      │ 2.755 ns      │ 2.98 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 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
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

1 participant