Skip to content

Rewrite yew.rs with Yew#4069

Draft
Madoshakalaka wants to merge 6 commits intomasterfrom
yew-docs
Draft

Rewrite yew.rs with Yew#4069
Madoshakalaka wants to merge 6 commits intomasterfrom
yew-docs

Conversation

@Madoshakalaka
Copy link
Member

@Madoshakalaka Madoshakalaka commented Mar 11, 2026

fixes #2779
Replace the Docusaurus-based website with a pure Rust/Yew implementation.

The SSG pipeline compiles each page to WASM, runs wasm-bindgen and wasm-opt, then captures SSR output for SEO-friendly HTML. All docs (5 versions x 4 languages), blog posts, community pages, search, and 404 are generated as static files.

This is a quite faithful rewrite of our old docusaurus based website.

Key features:

  • Content model with dual HTML/Markdown rendering which enables a copy-as-markdown button on each page (new feature)
  • Syntax highlighting via syntect (rust solution) with light/dark themes (old site used prism.js)
  • Collapsible sidebar, table of contents, breadcrumbs, and pagination (matching old site)
  • 3-state theme toggle (light/dark/system) (matching old site)
  • Blog with date-prefixed URLs, index, sidebar, RSS and Atom feeds (matching old site)
  • Full-page Algolia search with version faceting (matching old site)
  • OpenSearch descriptor, sitemap, robots.txt, 404 page (matching old site)
  • SEO: hreflang, OG tags, JSON-LD breadcrumbs, canonical URLs (matching old site)
  • wasm bundle and javascript hashing for cache control
  • CI workflow builds with Rust toolchain instead of Node.js

Some design choices and notes:

  • fantoccini is used for e2e testing the website. Site navigation needs to be tested because version + i18n selectors + side menu interaction can get very tricky. Alternatives to Fantoccini like thirtyfour, chromiumoxide were considered and Fantoccini has the most downloads, most stars, most recent release cadence.
  • Code snippet testing and tutorial testing preserved.
  • Data-as-code allows us to deduplicate greatly. Next, 0.23, and 0.22 docs are not diverged, which allows 0.23 docs and 0.22 docs to reuse the same data. This reduces 100, 000 lines of mdx to 50 ,000 lines of Rust.
  • stylist-rs is used for more concise styling. Its SSR support renders the same styling during SSG and runtime, causing no content flickering at all.
  • the new build tool, at ./yew-rs/ssg/, accepts page filtering, --jobs N flags, and --skip-wasm-opt flags that can shrink build time greatly. Since we don't have beefy runners and we do have to run wasm-opt in the CI, a fresh build might take a lot longer (10 minutes)
  • the new website uses stable yew (pinned to 0.23 at the moment) for cache friendliness and ecosystem support (stylist-rs won't work with Yew Next)
  • We have version and locale aware home pages now. The Get Started button and the Learn More buttons on each feature card now consume the version and locale too. (new feature)
  • Categories and subcategories all had {category}/introduction.mdx files. Most pages (7 out of 9) had a slug in the old mdx files so that the slug {category} by itself shows the introduction page, (and {category}/introduction gives a 404). The only two exceptions were: https://yew.rs/docs/next/getting-started/introduction and https://yew.rs/docs/advanced-topics/struct-components/introduction. The new code unifies the aliasing behaviour. It means old urls to docs/next/getting-started/introduction and docs/advanced-topics/struct-components/introduction will hit 404.

Todos

  • Verify localized and versioned home page SSG (important SEO)
  • remove mdx refences from the workflow and the website directory.
  • site-ssg only works on workspace root for now
  • the url of the tutorial page currently is prefixed with the /docs/ slug. It doesn't make sense as the nav bar suggests "tutorial" and "docs" are on the same level, handled just like the Community pages and Blog pages with no "docs" prefix. We should remove the docs prefix from the tutorial's url. This will also cause some 404s to old references.
image image
  • we might want to embed the playground directly into yew.rs now. (Should we make code blocks actually runnable ?)
  • SPA: we still generate all static pages. But we make it have dynamic navigation between them. Thanks @kirillsemyonkin for the idea. (!!) Docusaurus actually does this. See a comment from me below.
  • terrible readibility of some highlighting in codeblock in dark mode
  • Some meta description mismatch
  • Table rendering on the /docs/concepts/function-components/state page
  • Language and version menu on small height phone overflows and can't be scrolled
  • use const fn magic or macros to groups localized strings together, further reduction of code size.

@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.049 101.096 +0.047 +0.046%
boids 168.875 168.902 +0.027 +0.016%
communication_child_to_parent 94.502 94.511 +0.009 +0.009%
communication_grandchild_with_grandparent 106.343 106.350 +0.007 +0.006%
communication_grandparent_to_grandchild 102.686 102.692 +0.007 +0.007%
communication_parent_to_child 91.912 91.921 +0.009 +0.010%
contexts 106.401 106.410 +0.009 +0.008%
counter 87.225 87.232 +0.008 +0.009%
counter_functional 89.262 89.270 +0.008 +0.009%
dyn_create_destroy_apps 91.139 91.147 +0.009 +0.010%
file_upload 100.313 100.324 +0.011 +0.011%
function_delayed_input 95.230 95.240 +0.010 +0.010%
function_memory_game 174.086 174.110 +0.024 +0.014%
function_router 395.745 396.048 +0.303 +0.076%
function_todomvc 165.375 165.393 +0.018 +0.011%
futures 235.978 235.982 +0.005 +0.002%
game_of_life 105.525 105.533 +0.008 +0.007%
immutable 260.431 260.398 -0.032 -0.012%
inner_html 81.768 81.775 +0.008 +0.010%
js_callback 110.384 110.396 +0.012 +0.011%
keyed_list 180.700 180.708 +0.008 +0.004%
mount_point 85.140 85.147 +0.008 +0.009%
nested_list 114.088 114.094 +0.006 +0.005%
node_refs 92.515 92.521 +0.006 +0.006%
password_strength 1719.671 1719.392 -0.279 -0.016%
portals 93.984 93.994 +0.010 +0.010%
router 366.386 366.705 +0.319 +0.087%
suspense 114.382 114.392 +0.010 +0.009%
timer 89.362 89.370 +0.008 +0.009%
timer_functional 99.798 99.804 +0.006 +0.006%
todomvc 143.089 143.097 +0.008 +0.005%
two_apps 87.138 87.146 +0.008 +0.009%
web_worker_fib 137.032 137.045 +0.013 +0.009%
web_worker_prime 188.222 188.230 +0.009 +0.005%
webgl 83.911 83.921 +0.010 +0.012%

✅ None of the examples has changed their size significantly.

@Madoshakalaka Madoshakalaka added documentation A-ci Area: The continuous integration labels Mar 11, 2026
@Madoshakalaka Madoshakalaka force-pushed the yew-docs branch 2 times, most recently from 832800f to 0ec8ecd Compare March 11, 2026 12:24
@github-actions
Copy link

github-actions bot commented Mar 11, 2026

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

https://yew-rs--pr4069-yew-docs-185gwe7t.web.app

(expires Mon, 23 Mar 2026 12:53:11 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Madoshakalaka added a commit that referenced this pull request Mar 13, 2026
Replace the Docusaurus-based website with a pure Rust/Yew implementation.

The SSG pipeline compiles each page to WASM, runs wasm-bindgen and
wasm-opt, then captures SSR output for SEO-friendly HTML. All docs
(5 versions x 4 languages), blog posts, community pages, search, and
404 are generated as static files.

Key features:
- Content model with dual HTML/Markdown rendering for copy-as-markdown
- Syntax highlighting via syntect with light/dark themes
- Collapsible sidebar, table of contents, breadcrumbs, pagination
- 3-state theme toggle (light/dark/system)
- Blog with date-prefixed URLs, index, sidebar, RSS and Atom feeds
- Full-page Algolia search with version faceting
- SEO: hreflang, OG tags, JSON-LD breadcrumbs, canonical URLs
- E2E tests with fantoccini/geckodriver
- Deduplicated versioned docs across 0.20/0.21/0.22/0.23/next
Madoshakalaka added a commit that referenced this pull request Mar 13, 2026
Replace the Docusaurus-based website with a pure Rust/Yew implementation.

The SSG pipeline compiles each page to WASM, runs wasm-bindgen and
wasm-opt, then captures SSR output for SEO-friendly HTML. All docs
(5 versions x 4 languages), blog posts, community pages, search, and
404 are generated as static files.

Key features:
- Content model with dual HTML/Markdown rendering for copy-as-markdown
- Syntax highlighting via syntect with light/dark themes
- Collapsible sidebar, table of contents, breadcrumbs, pagination
- 3-state theme toggle (light/dark/system)
- Blog with date-prefixed URLs, index, sidebar, RSS and Atom feeds
- Full-page Algolia search with version faceting
- SEO: hreflang, OG tags, JSON-LD breadcrumbs, canonical URLs
- E2E tests with fantoccini/geckodriver
- Deduplicated versioned docs across 0.20/0.21/0.22/0.23/next
@Madoshakalaka Madoshakalaka force-pushed the yew-docs branch 6 times, most recently from ce3a6d7 to 15b5594 Compare March 14, 2026 11:51
@Madoshakalaka
Copy link
Member Author

@WorldSEnder still a draft PR but any opinions are welcome. you can already try the wasm website in the preview URL

@Madoshakalaka
Copy link
Member Author

Size Note:
every doc page is ~1.7 MB of WASM (700 kB after compression). Home pages (which skip syntect) are only ~378 KB (120 kB after compression).

@Madoshakalaka
Copy link
Member Author

Madoshakalaka commented Mar 16, 2026

SPA: we still generate all static pages. But we make it have dynamic navigation between them.

This is now implemented. Each locale (en, ja, zh-Hans, zh-Hant) has one SPA binary powered by yew-router that covers all 5 doc versions + migration guides. Version switching is client-side (no WASM re-download), locale switching triggers a full reload. This is identical to docusaurus behavior. The rationale I think is version switching is much frequent than locale switching.

Architecture:

  • 4 new SPA crates (spa-en/, spa-ja/, spa-zh-hans/, spa-zh-hant/) with Route enums using wildcard paths
  • SSG compiles 4 SPA binaries instead of ~1,100 per-page binaries, then hardlinks WASM/JS to each page directory
  • SSR unchanged: each page still gets unique meta tags, hreflang, JSON-LD, descriptions
  • Blog, community, and home pages are unchanged (still per-page binaries)

Per-page WASM download went from ~1.7 MB (per navigation) to ~2.8 MB (once per session, then all version/page switches are instant. 930 kB after compression, seems acceptible). Full build time in CI reduces tenfold (90 minutes -> 11 minutes).

@Madoshakalaka
Copy link
Member Author

Madoshakalaka commented Mar 16, 2026

more todos:

  • <title/> isn't changing for same-locale navigation.
  • dropdown doesn't retract for after same-locale version change
  • no standalone home page (?)
  • maybe try isolating syntect to ssr/ssg only to reduce bundle size

@Madoshakalaka
Copy link
Member Author

Madoshakalaka commented Mar 16, 2026

As previously commented, a huge bloat is syntect. We don't have codeblocks on a lot of pages like the home page and the getting-started/examples page.

But the SPA approach now inevitably bundles it.

after #3932 lands though, we can delay loading the CodeBlock component.

This will even beat docusaurus. Note docusaurs based getting-started/examples and getting-started/editor-setup currently load JavaScript of identical size.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ci Area: The continuous integration documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build Yew website with Yew

1 participant