feat: add yew-link crate for unified SSR/CSR data fetching#4027
feat: add yew-link crate for unified SSR/CSR data fetching#4027Madoshakalaka wants to merge 7 commits intomasterfrom
Conversation
|
Visit the preview URL for this PR (updated for commit ea2893a): https://yew-rs--pr4027-yew-link-sylkdib6.web.app (expires Sat, 14 Mar 2026 17:32:40 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 |
Benchmark - SSRYew MasterDetails
Pull RequestDetails
|
Size ComparisonDetails
✅ None of the examples has changed their size significantly. |
Benchmark - coreYew MasterPull Request |
f4df507 to
851a43a
Compare
6e0dbf2 to
4e9e867
Compare
|
|
||
| // -- Part 2: Navigate to /posts within the same app, then to /posts/0 -- | ||
|
|
||
| yew::scheduler::flush().await; |
There was a problem hiding this comment.
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.
CacheKey previously stored only a u64 hash of the input, so two different inputs producing the same hash would silently return wrong cached data. Store the actual input as Rc<dyn Any> with a monomorphized function pointer for type-erased PartialEq comparison. Hash-based bucket lookup is unchanged; Eq now verifies with real input equality.
|
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 |
Description
Closes #2649, whose lower-level half including
use_prepared_stateanduse_transitive_stateis already shippedThis PR implements the higher-level half of #2649: a
yew-linkcrate 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-linkcloses this gap.Implemented new crates proposed in the pr:
yew-linkandyew-link-macroOverhauled
ssr_routerexample, rewired to useyew-linkinstead 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
QueryAPI anduse_prepared_queryhook do overlapping but not identical workyew-link has bounded cache: client-side cache uses
lru::LruCache(default 64 entries, configurable viaLinkProvider'scache_capacityprop). Dependency gated towasm32only.yew-link has more granular code isolation as its
#[linked_state]stripsresolve()from WASM andQuery::query()body is always compiled into WASM.yew-link also provides better utility by its built-in
linked_state_handlerfor axum.Checklist
I have overhauled the ssr_router to use yew-link.
I have overhauled the ssr_router's E2E test too:
post/0receives a server-rendered page with no extra fetch requests.postspage first, click on the anchor of posts with the id 0, in-app navigation happens and fetch happens exactly onceI'm not sure how
cargo releasein our.github/workflows/publish.ymlhandles the two added new crates, but that's a matter for the future when when publish yew-link with yew 0.23