Bun + Vite + Sveltebuild

Why Bun & Vite & Svelte for TypeScript

Get closer to the machine — no virtual DOM, no runtime framework, no abstraction tax

v2.0·12 min read·Kenneth Pernyér
bunvitesveltetypescripttoolingcompiler

The Problem

The web development world made the same mistake as the backend world: it kept adding layers between the programmer and the machine.

  • A runtime abstraction (Node.js on V8)
  • A virtual DOM (React, Vue)
  • A reconciliation algorithm running on every state change
  • A package manager, a bundler, a dev server, a test runner — all separate tools
  • Hooks, effects, memoization — complexity tax to work around the framework's own overhead

This is the Python problem applied to the frontend. Python made programming "easy for humans" — and paid for it with a GIL, a slow runtime, and a mountain of abstraction. React did the same: it made UI "declarative" — and paid for it with a virtual DOM diffing engine that runs in your users' browsers.

The insight: AI-assisted programming is the accessibility layer now.

We don't need frameworks that make code "easier to write for humans." The AI writes the code. What we need is code that runs fast, ships small, and stays close to the platform. The same logic that led us to Rust over Python on the backend leads us to Svelte over React on the frontend.

Svelte is a compiler, not a runtime. Your components compile to direct DOM manipulation — no virtual DOM, no diffing, no framework code shipped to the browser. Bun replaces Node.js, npm, Jest, and ts-node. Vite provides the dev server and production builds.

Together: no runtime framework, no virtual machine, no abstraction tax.

Current Options

OptionProsCons
Node.js + Webpack + ReactMaximum abstraction. The old way.
  • Battle-tested in production
  • Massive ecosystem of plugins
  • Extensive documentation
  • Large hiring pool
  • Virtual DOM overhead in every user's browser
  • Hooks and memoization complexity
  • Slow dev server startup (30+ seconds)
  • Runtime framework shipped to production
Bun + Vite + ReactFast tooling, but still a runtime framework.
  • Bun: fast runtime, packages, tests
  • Vite: instant dev server, fast builds
  • React ecosystem and patterns
  • Better than Node.js + Webpack
  • Still ships virtual DOM to the browser
  • useEffect, useMemo, useCallback — complexity to manage the framework itself
  • Bundle size includes React runtime (~40KB)
  • Reconciliation runs on every state change
Bun + Vite + SvelteCompiler-first. No runtime framework. Close to the machine.
  • Svelte compiles away — no framework shipped to production
  • Direct DOM updates, no virtual DOM diffing
  • Reactive by default — no hooks, no memoization boilerplate
  • Bun + Vite: fast runtime, instant dev server, fast builds
  • Smaller ecosystem than React
  • Bun is younger than Node.js
  • Fewer third-party component libraries

Future Outlook

The trend is clear: eliminate the layers between your code and the machine.

On the backend: Rust replaced Python and Go for performance-critical work. No garbage collector, no virtual machine, no runtime overhead. The compiler does the work so the runtime doesn't have to.

On the frontend: Svelte applies the same philosophy. The compiler analyzes your components at build time and generates minimal, direct DOM manipulation code. There's no virtual DOM to diff, no reconciliation algorithm to run, no framework runtime to ship.

The AI factor changes everything. React's value proposition was "easier to reason about for humans" — declarative UI, component model, one-way data flow. But when AI writes and modifies the code, human ergonomics matter less. What matters is: does the output run fast? Is the bundle small? Does it stay close to the platform?

Svelte answers yes on all three. Components compile to imperative DOM operations that browsers execute directly. Bundle sizes are dramatically smaller. There's less code between your intent and the user's screen.

Bun completes the picture — the fastest JavaScript runtime, with built-in package management, testing, and TypeScript. No Node.js, no npm, no Jest, no separate TypeScript compiler.

Vite provides the dev experience — instant HMR, optimized production builds, and first-class Svelte support via @sveltejs/vite-plugin-svelte.

This is the same bet we made with Rust: trust the compiler, not the runtime.

Our Decision

Why we chose this

  • No runtime frameworkSvelte compiles to vanilla JavaScript. No virtual DOM, no diffing algorithm, no framework code in your production bundle. The browser runs your code, not a framework.
  • Smaller bundles, faster loadsA Svelte app ships a fraction of the JavaScript a React app does. No 40KB React runtime. Each component compiles to only the code it needs.
  • Reactive without the boilerplateNo useState, useEffect, useMemo, useCallback. Svelte's reactivity is built into the language with $state and $derived. The compiler tracks dependencies automatically.
  • Sub-second feedback loopsBun starts in milliseconds. Vite serves changes instantly. Svelte HMR preserves state. Change code, see results immediately.
  • Native TypeScript everywhereBun runs TypeScript directly. Vite transforms it instantly. Svelte has first-class TypeScript support in components. No separate compilation step.

×Trade-offs we accept

  • Smaller ecosystemReact has more third-party component libraries. But Svelte uses standard HTML/CSS/JS — you don't need a "Svelte version" of most things.
  • Bun maturityBun is younger than Node.js. Some edge cases may surprise you. We accept this trade-off for the velocity gains.
  • Different mental modelIf your team thinks in React hooks, there's a learning curve. But the AI handles the syntax — the concepts (components, reactivity, composition) transfer directly.

Motivation

We chose this stack for the same reason we chose Rust over Python: get closer to the machine.

The pattern: Python → Rust. React → Svelte. The common thread is eliminating runtime abstractions in favor of compile-time work.

Python is easy for humans but slow for machines. Rust is harder for humans but the compiler produces optimal machine code. AI-assisted programming removes the "harder for humans" part — you get the machine performance without the human cost.

React is easy for humans but ships a runtime framework to every user's browser. Svelte compiles away — the browser runs direct DOM operations, not a reconciliation engine. AI-assisted programming removes the "harder for humans" part — you get the performance without the ergonomic trade-off.

Bun gives us fast package installation (CI went from 2 minutes to 15 seconds), fast test execution, and native TypeScript.

Vite gives us instant dev server startup and optimized production builds. When AI generates a component, we see the result before our finger leaves the key.

Svelte gives us compiled output that's close to the metal of the browser. No virtual DOM. No runtime overhead. No framework tax on our users.

The AI writes the code. The compiler optimizes it. The browser runs it directly. No unnecessary layers.

Recommendation

Start a new Svelte + TypeScript project:

# Install Bun
curl -fsSL https://bun.sh/install | bash

# Create Vite + Svelte project
bun create vite my-app --template svelte-ts
cd my-app

# Install dependencies (fast!)
bun install

# Start dev server
bun run dev

Project structure:

  • bun install for dependencies (replaces npm)
  • bun run dev to start Vite dev server
  • bun test for tests (replaces Jest)
  • bun run build for Vite production build
  • bun run preview to preview production build

Key insight: Svelte compiles your components at build time. What ships to the browser is vanilla JavaScript — no framework runtime, no virtual DOM, no abstraction tax. The same philosophy as Rust: the compiler does the work so the runtime doesn't have to.

Examples

vite.config.tstypescript
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import path from 'path';

export default defineConfig({
  plugins: [svelte()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
});

Complete Vite config for Svelte + TypeScript. Simpler than React — no vendor chunking needed because there's no framework runtime to split out.

src/App.sveltesvelte
<script lang="ts">
  let count = $state(0);
  let doubled = $derived(count * 2);

  async function loadUser() {
    const res = await fetch('/api/user');
    return res.json();
  }

  let user = $state<{ name: string } | null>(null);

  $effect(() => {
    loadUser().then((data) => (user = data));
  });
</script>

<main>
  <h1>Welcome{user ? `, ${user.name}` : ''}</h1>
  <button onclick={() => count++}>
    Count: {count} (doubled: {doubled})
  </button>
</main>

<style>
  main {
    padding: 2rem;
  }
</style>

Svelte component with TypeScript. No useState, no useEffect, no useMemo. Reactivity is built into the language — $state declares reactive values, $derived computes from them, $effect runs side effects. The compiler tracks everything.

package.jsonjson
{
  "name": "my-app",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "test": "bun test",
    "check": "svelte-check --tsconfig ./tsconfig.json"
  },
  "dependencies": {},
  "devDependencies": {
    "@sveltejs/vite-plugin-svelte": "^5.0.0",
    "svelte": "^5.0.0",
    "svelte-check": "^4.0.0",
    "typescript": "^5.0.0",
    "vite": "^6.0.0"
  }
}

Minimal package.json. Notice: Svelte is a devDependency — it's a compiler, not a runtime. Zero production dependencies. No React, no React DOM, no framework shipped to users.

Related Articles

Stockholm, Sweden

Version 2.0

Kenneth Pernyér signature