Skip to content

v0.2.1

Choose a tag to compare

@goddtriffin goddtriffin released this 30 Aug 18:51
· 24 commits to main since this release
9cd8aaa

Two commits since v0.1.23: the crate was split into feature-gated kits, and the base layout is now embedded with every frontend asset derived from a single source.

Feature gates

  • Split into independently gated kits — webserver, pages, templates, assets, analytics, sitemap, observability, telegram, preset — with default = []. A consumer compiles only what it enables: 19 transitive crates by default, down from 156 unconditional.
  • A sidecar still boots with no frontend: no templates, no icons, no analytics, no static/.

The embedded base layout

  • base now ships inside the crate. No project owns a copy, and a project file that would shadow it is a boot error naming the offender. The <head> is pure function — spec conformance, Open Graph, JSON-LD, icons, resource hints — so it is solved once and inherited rather than copy-pasted and left to drift.
  • A page supplies one body block and extends it. The layout contributes no chrome: <body> is bare.

frontend — the line between a site and a service

  • WebServer::frontend(FrontendParams) turns on everything a website needs. Each required input is a field, so forgetting one is a compile error, not a page that silently ships without a share card.
  • Boot-time asset validation. Every declared stylesheet, script, social image and generated icon is proved to resolve before the server binds, and every miss is reported at once. There is deliberately no fallback to the un-hashed path — that turns a misconfiguration into a link that 404s for the visitor and reports nothing back.
  • robots.txt, site.webmanifest and the sitemaps are generated and humans.txt is embedded; all are served from memory, so a production image stays runnable read-only.
  • Adds SiteEntity, ThemeColor, JSON-LD support, and a pre-paint theme script.
  • Every frontend gets the 404 page data for free; 404s are served at the requested URL with a real 404 status instead of redirecting to /404 (a soft 404 returning 200).

Icons

  • Exactly one source — favicon.svg, or a 512×512 favicon-512.png for art that cannot be vectorised — and favicon.ico, apple-touch-icon.png, icon-192.png, icon-512.png derive from it. Every derived size is a downscale from 512, so a smaller source is refused rather than upscaled.
  • The icon directory is a closed set; any other file is a boot error. A stale icon from a previous design is otherwise invisible until the wrong picture turns up in a browser tab.

Static assets

  • Hashing is a build step, never a startup step. Startup hashing was not idempotent, and an in-place restart 404'd every asset on the site.
  • gen-static-assets and gen-static-scripts are subcommands of your own server binary — no shim binary, no per-project glue.
  • cache-buster.json and static/script/generated/ are build outputs. Consuming projects must gitignore both.

Analytics and error monitoring

  • First-party byte relays for Plausible and Sentry, on routes derived from the project name. Both vendors' origins sit on blocklists — Plausible puts the cost at 5–25% of visitors — and a per-project path means no single filter rule can take out every site at once.
  • Bytes are relayed, never re-reported: a server that interpreted a browser error and re-raised it through its own SDK would file it as a server problem with the wrong stack. The tunnel's destination comes from the configured DSN, not the envelope, so it cannot be used as an open relay.
  • The true client IP is forwarded as X-Forwarded-For; without it Plausible's bot filter rejects proxied events outright.
  • Replaces the old frontend error logger and the scitylana script.

Observability

  • bootstrap! initialises Sentry on the main thread before building the runtime, so the hub reaches worker threads; the guard drops after the drain. It stays a macro so the release names your application.
  • Sentry's environment is now set — local and production errors previously shared one bucket.

Fixes

  • Graceful shutdown no longer sleeps out the drain window. The window was passed into with_graceful_shutdown, which postponed the drain by ten seconds instead of bounding it: the server kept accepting connections the whole time, then drained instantly. It is now a timeout around serving whose clock starts when the drain does. An idle server stops in ~0.02s instead of ~10s.
  • The generated CACHE_BUSTER export carries real JSDoc, so deno doc --lint passes.

Breaking changes

  • BaseSettings is replaced by per-kit configs, all WSB_-prefixed. Environment is now Local | Production and required.
  • TemplateData is replaced by BaseTemplateData + PageTemplateData, merged into a borrowed per-render TemplateData. The copyright year is computed per render rather than cached at boot.
  • html/layouts/base.hbs must be deleted from consuming projects — it is now a boot error.
  • Consuming projects must supply one icon source and gitignore the two build outputs.

Dependencies

axum 0.8, axum-extra 0.12, sentry 0.49, reqwest 0.13, tower-http 0.7, sitemap-rs 0.4, md5 0.8. Docker stages on rust 1.98.0, deno 2.9.5, node 26.7.0, alpine 3.24.1, sass 1.103.1. Drops the dead futures / serde_yaml / pulldown-cmark / rand dependencies.


Rust webserver-base 0.2.1 · JSR @todd/webserver-base 0.1.1

Full Changelog: v0.1.23...v0.2.1