Skip to content

feat(docs): split the docs site into per-locale wasm bundles - #309

Merged
vshengbro merged 1 commit into
masterfrom
feat/docs-per-locale-bundles
Oct 10, 2026
Merged

vshengbro merged 1 commit into
masterfrom
feat/docs-per-locale-bundles

Conversation

@vshengbro

Copy link
Copy Markdown
Collaborator

Summary

All locales used to compile into a single wasm bundle (2.24 MB): every visitor
downloaded every language, and the shell resolved locale state at runtime. This
PR splits the build into one bundle per locale, mirroring the directory layout
static i18n sites already use — the default locale at the output root, every
other locale in its own directory (en/, ja/, ko/, …).

build.rs gains the pin: EUV_DOCS_LOCALE selects the locale by prefix,
directory, or label (unset → the default / locale). Alias entries resolve to
their canonical directory; pages of other locales are dropped; the pinned prefix
is stripped from every route and internal link, so in-bundle routes are
prefix-free. Non-default bundles rebase relative asset URLs (./img/… →
../img/…) because assets are copied only by the default build and hosted once
at the site root. The generated code emits SITE_LANGUAGES (switcher entries),
SITE_LOCALE_DIR, and SITE_REDIRECTS next to SITE, and writes
.deploy/locales.tsv so the CLI discovers the remaining locales without a
second YAML parser.

Runtime: the shell keeps rendering from SITE unchanged (it now contains
exactly one locale); the language switcher reads SITE_LANGUAGES and switches
via cross-directory navigation (Location::assign), which the old code already
approximated with a full-page reload. A boot-time redirect before mount maps
legacy single-bundle links (<root>/#/en/…) and alias prefixes (#/zh/…) onto
the right bundle, so old links keep working.

CLI: --locale <name> builds a single bundle for fast iteration; the default
invocation builds the default locale, reads the manifest, then builds every
remaining locale into its own sub-directory. The redundant CLI-side public/
copy is gone (build.rs owns assets now).

Verification

Local build of the 632-page, 4-locale docs site (zh/en/ja/ko):

Bundle wasm size Before
zh (root) 984 KB 2.24 MB all-in-one
en 1.02 MB 〃
ja 1.06 MB 〃
ko 1.04 MB 〃

Per-visitor download drops 54–57%. Assets are hosted once at the site root
(total site ~59 MB; naive per-locale asset copies would have been ~214 MB).

Browser-verified on the built output:

  • each bundle renders only its own sidebar tree (en bundle's Chinese entries
    are the known untranslated LICENSE page titles, a content gap tracked
    separately, not a routing bug)
  • the language switcher preserves the current route across directories
    (/#/ltpp/version.html → /en/#/ltpp/version.html)
  • legacy single-bundle links /#/en/ltpp/version.html redirect to the en
    bundle; the #/zh/… legacy alias rewrites in place to #/…
  • images load in every bundle (en bundle rebased to ../markdown-images/…,
    11/11 natural-width OK; zh unchanged, 11/11 OK)
  • TOC scroll spy still tracks the current section in per-locale bundles
  • --locale en produces a single-bundle build with no locale subdirectories

cargo fmt --check clean, clippy --workspace --all-targets 0 warnings, full
workspace test suite passing. Version 0.28.23, workspace pins realigned.

Deploy notes

No workflow change needed in docs-pages/docs: the deploy installs the euv-docs
CLI from master and runs euv-docs docs --out www, which now emits the
per-locale layout (www/en/, …) that cp -r www/* pushes as-is.

All locales used to compile into a single wasm bundle (2.24 MB), so every
visitor downloaded every language and the shell tracked locale state at
runtime. The build now pins one locale per bundle and the CLI builds one
bundle per locale, mirroring the directory layout static i18n sites
already use: the default locale at the output root, every other locale in
its own directory (en/, ja/, ko/, …).

build.rs gains the pin: EUV_DOCS_LOCALE selects the locale by prefix,
directory, or label (unset → the default '/' locale), alias entries are
resolved to their canonical directory, pages of other locales are dropped,
and the pinned prefix is stripped from every route and internal link so
in-bundle routes are prefix-free. Non-default bundles also rebase relative
asset URLs (./img/… → ../img/…) because assets are copied only by the
default build and hosted once at the site root. The generated code emits
SITE_LANGUAGES (switcher entries, one per unique content directory),
SITE_LOCALE_DIR (this bundle's directory), and SITE_REDIRECTS (foreign
prefix → owning directory) next to SITE, and writes .deploy/locales.tsv so
the CLI discovers the remaining locales without a second YAML parser.

Runtime: the shell keeps rendering from SITE unchanged (it now contains
exactly one locale); the language switcher reads SITE_LANGUAGES and
switches via cross-directory navigation (Location::assign), which the old
code already approximated with a full-page reload. A boot-time redirect
before mount maps legacy single-bundle links (<root>/#/en/…) and alias
prefixes (#/zh/…) onto the right bundle, so old links keep working.

CLI: --locale <name> builds a single bundle for fast iteration; the
default invocation builds the default locale, reads the manifest, then
builds every remaining locale into its own sub-directory. The redundant
CLI-side public/ copy is gone (build.rs owns assets now).

Verified locally on the 632-page, 4-locale docs site: zh 984 KB, en 1.02
MB, ja 1.06 MB, ko 1.04 MB (down from 2.24 MB, -54~57% per visitor); each
bundle renders only its own sidebar; the switcher preserves the current
route across directories; legacy #/en/… links redirect to /en/#/…; the
/zh/ alias rewrites in place; images load in every bundle; the TOC scroll
spy still tracks.
@ghfind-review ghfind-review Bot added the review: high ghfind author score; see https://ghfind.com label Oct 10, 2026
@vshengbro
vshengbro merged commit a21eb0e into master Oct 10, 2026
8 checks passed
@vshengbro
vshengbro deleted the feat/docs-per-locale-bundles branch October 10, 2026 05:10
vshengbro added a commit that referenced this pull request Oct 10, 2026
…cale refactor

Resolve two semantic conflicts the auto-merge could not:

- Cargo.toml version: keep 0.28.24. #309 set the workspace to 0.28.23,
  which is already published, so the bump has to land past it.
- DocsLocale.label: #309 dropped the field from the generated locale
  and moved every label into the cross-bundle language switcher.
  locale_label_for now resolves a route's label out of SITE_LANGUAGES
  by prefix instead of reading the removed field.

Also fix three §audits that #309 itself introduced: move
LocaleManifestEntry out of bin/docs/fn.rs into struct.rs (a struct in a
keyword file fails the purity rule), and give the retained
resolve_locale_roots binding a name and type so the explicit-annotation
rule passes. The call stays — it is what fails the build when a declared
locale has no directory or no markdown.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: high ghfind author score; see https://ghfind.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant