Your bundler ships component code your app never runs. svelte-shaker deletes it.
It reads how your whole app calls every component, folds props that never vary, and deletes the dead branches, CSS, and modules behind them — at the source, before the Svelte compiler. When a change can't be proven safe, the code is left untouched.

Try it
The engine runs in your browser. The app only ever renders <Button variant="primary"> — so loading folds away, the <Spinner> it guarded drops from the
bundle, and .btn-danger can never match. Edit either side
of the story and watch the output update.
How it works
- Crawl every call site. From your entry, it records the value
passed to every prop at every
<Child/>— a literal, a default, or "unknown". - Decide what's reachable. Props that never vary fold to their constant; only branches and CSS their values can reach survive. Folds cascade to a whole-program fixpoint.
- Slim the source, then compile. Dead code is deleted from the
.sveltefiles, and Svelte compiles only what's left.
Sound by construction: anything unprovable (spreads, bind:,
dynamic components…) bails and ships unchanged. Build-time only, as a
Vite / Rollup plugin — entries is where the crawl starts, and
it must cover every call site in the app.
# vite.config.ts import { shaker } from 'svelte-shaker/vite'; plugins: [shaker({ entries: ['src'] }), svelte()]