Svelte kompiliert Komponenten zu nativem JavaScript ohne Runtime-Overhead. In Kombination mit Rails 7 entsteht eine Architektur, die das bewährte Rails-Backend mit einem minimal schlanken Frontend verbindet. Aber ist das immer die richtige Wahl? In diesem Artikel zeigen wir das konkrete Setup, vergleichen Svelte mit dem Rails-eigenen Hotwire/Turbo-Stack und teilen unsere Erfahrungen aus realen Projekten.
Svelte auf Rails mit Tailwind | Ruby on Rails 7
Wann lohnt sich Svelte statt Hotwire/Turbo?
Rails 7 liefert mit Hotwire (Turbo + Stimulus) bereits ein leistungsfähiges Frontend-Toolkit. Bevor Sie Svelte einbinden, sollten Sie ehrlich prüfen, ob Ihr Projekt es wirklich braucht.
Hotwire/Turbo ist die bessere Wahl, wenn:
- Ihre App vorwiegend serverseitig gerenderte Seiten mit wenig Client-Interaktivität hat
- Sie schnelle Turnaround-Zeiten brauchen und das Team bereits Rails kennt
- CRUD-Operationen mit Live-Updates (Turbo Streams) den Grossteil der UI ausmachen
Svelte lohnt sich, wenn:
- Komplexe, zustandsbehaftete UI-Komponenten nötig sind (Dashboards, Drag-and-Drop, Echtzeit-Editoren)
- Sie eigenständige Widgets bauen, die unabhängig vom Rails-Rendering arbeiten
- Bundle-Grösse kritisch ist: Eine typische Svelte-Komponente kompiliert zu 2-5 KB gzip, während React-Äquivalente 40-50 KB Runtime mitbringen
USEO’s Take: Zwei Ökosysteme bedeuten doppelte Wartungskosten
Aus unserer Projekterfahrung bei USEO: Svelte in eine Rails-App einzubinden funktioniert technisch einwandfrei. Die eigentliche Herausforderung liegt im langfristigen Betrieb. Sie pflegen zwei Dependency-Bäume (Gemfile + package.json), zwei Build-Pipelines und brauchen Entwickler, die beide Welten verstehen.
In einem Kundenprojekt haben wir ein Dashboard mit ca. 15 Svelte-Komponenten in einer Rails 7.1 App betrieben. Die initialen Bundle-Grössen waren hervorragend (gesamtes Svelte-Bundle: 38 KB gzip vs. geschätzte 120+ KB mit React). Aber jedes Rails-Upgrade erforderte auch die Prüfung der Node-Toolchain-Kompatibilität. Unser Rat: Setzen Sie Svelte gezielt für die Teile ein, wo Hotwire nicht ausreicht, statt die gesamte App damit zu bauen.
Voraussetzungen: Versionen und Werkzeuge
| Werkzeug | Version | Hinweis |
|---|---|---|
| Ruby | >= 3.2.0 | Empfohlen: 3.3.x für YJIT-Performance |
| Rails | >= 7.1.0 | 7.0 funktioniert, aber 7.1 hat bessere ESBuild-Integration |
| Node.js | >= 18.0 (LTS) | Node 16 ist EOL seit September 2023 |
| npm | >= 9.0 | Wird mit Node 18 ausgeliefert |
| Bundler | >= 2.4 | gem install bundler |
| ESBuild | >= 0.19 | Wird über jsbundling-rails installiert |
| svelte-on-rails | >= 1.0.0 | Das zentrale Integrations-Gem |
Prüfen Sie Ihre Versionen:
ruby --version # >= 3.2.0
rails --version # >= 7.1.0
node --version # >= 18.0.0
npm --version # >= 9.0.0
Rails-Projekt mit ESBuild erstellen
rails new svelte_rails_app --javascript=esbuild --css=tailwind
cd svelte_rails_app
bundle install
Warum --javascript=esbuild? ESBuild kompiliert JavaScript 10-100x schneller als Webpack. Ein typischer Svelte-Build mit 20 Komponenten dauert unter 200ms.
Warum Tailwind statt Bootstrap? Tailwind generiert nur genutztes CSS per PurgeCSS. In Kombination mit Svelte ergibt das ein Gesamt-CSS-Bundle von ca. 8-12 KB gzip.
Ihre Gemfile sollte diese Gems enthalten:
gem 'jsbundling-rails' # ~> 1.3
gem 'turbo-rails' # ~> 2.0
gem 'stimulus-rails' # ~> 1.3
Svelte installieren und konfigurieren
Gem und npm-Pakete hinzufügen
bundle add svelte-on-rails
rails generate svelte_on_rails:install
npm install svelte@4 esbuild-svelte@0.8
Die Installation erstellt die nötige ESBuild-Konfiguration und das Komponentenverzeichnis.
Build-Konfiguration prüfen
Nach der Installation sollte esbuild.config.mjs einen Svelte-Plugin-Eintrag enthalten:
import sveltePlugin from 'esbuild-svelte';
import sveltePreprocess from 'svelte-preprocess';
export default {
plugins: [
sveltePlugin({
preprocess: sveltePreprocess(),
}),
],
};
Starten Sie den Dev-Server und prüfen Sie, ob der Build fehlerfrei durchläuft:
bin/dev
Der Procfile.dev startet sowohl Rails als auch den ESBuild-Watcher.
Erste Testkomponente
Erstellen Sie app/frontend/javascript/components/HelloWorld.svelte:
<script>
export let name = 'Welt';
</script>
<div class="hello">
<h2>Hallo {name}</h2>
<p>Svelte läuft in Rails.</p>
</div>
<style>
.hello {
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
margin: 1rem 0;
}
</style>
In einer Rails-View einbinden:
<%= svelte_component('HelloWorld', { name: 'Rails-Entwickler' }) %>
Daten zwischen Rails und Svelte austauschen
Der häufigste Anwendungsfall: Rails liefert Daten per Props an Svelte-Komponenten.
Controller vorbereiten
class DashboardController < ApplicationController
def show
@metrics = {
revenue: current_company.monthly_revenue,
users: current_company.active_users_count,
uptime: current_company.uptime_percentage,
last_updated: Time.current.iso8601
}
end
end
Svelte-Komponente mit Props
<script>
export let revenue;
export let users;
export let uptime;
export let lastUpdated;
const formatCurrency = (amount) =>
new Intl.NumberFormat('de-CH', {
style: 'currency',
currency: 'CHF'
}).format(amount);
const formatDate = (iso) =>
new Intl.DateTimeFormat('de-CH', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
}).format(new Date(iso));
</script>
<div class="dashboard-card">
<h3>Monatsübersicht</h3>
<ul>
<li>Umsatz: {formatCurrency(revenue)}</li>
<li>Aktive Nutzer: {users.toLocaleString('de-CH')}</li>
<li>Uptime: {uptime}%</li>
</ul>
<small>Stand: {formatDate(lastUpdated)}</small>
</div>
View
<%= svelte_component('DashboardCard', @metrics) %>
Beachten Sie: svelte-on-rails konvertiert Ruby snake_case automatisch zu JavaScript camelCase. Aus last_updated wird lastUpdated.
Bundle-Grössen im Vergleich
Wir haben die Bundle-Grössen für ein identisches Dashboard (5 Komponenten, Chart-Rendering, Echtzeit-Updates) gemessen:
| Stack | JS Bundle (gzip) | CSS Bundle (gzip) | Build-Zeit |
|---|---|---|---|
| Svelte 4 + ESBuild | 22 KB | 4 KB | 180ms |
| React 18 + ESBuild | 68 KB | 4 KB | 320ms |
| Vue 3 + Vite | 54 KB | 5 KB | 450ms |
| Hotwire/Turbo + Stimulus | 18 KB | 4 KB | 90ms |
Hotwire ist kleiner, bietet aber keine Client-seitige Reaktivität für komplexe UI-Logik. Svelte liegt nah an Hotwire bei der Grösse, bietet aber ein vollständiges Komponentenmodell.
Ordnerstruktur und Konventionen
app/
├── frontend/
│ └── javascript/
│ ├── components/ # Svelte-Komponenten (PascalCase)
│ │ ├── DashboardCard.svelte
│ │ ├── UserProfile.svelte
│ │ └── shared/ # Wiederverwendbare Basis-Komponenten
│ │ └── Modal.svelte
│ └── utils/ # Hilfsfunktionen
│ └── formatters.js
├── views/ # Rails ERB Templates
└── assets/ # Rails Asset Pipeline
Halten Sie Svelte-Komponenten in PascalCase und gruppieren Sie wiederverwendbare Teile in einem shared/ Unterverzeichnis. Für Utility-Funktionen (Formatierung, API-Calls) nutzen Sie utils/.
Typische Probleme und deren Lösung
ESBuild findet Svelte-Dateien nicht
Prüfen Sie den entryPoints-Pfad in esbuild.config.mjs. Er muss auf das Verzeichnis zeigen, das Ihre Svelte-Imports enthält.
HMR funktioniert nicht korrekt
ESBuild unterstützt kein vollständiges HMR für Svelte. Der Watcher erkennt Änderungen und baut neu, aber der Browser lädt die ganze Seite. Für echtes HMR brauchen Sie Vite statt ESBuild:
rails new my_app --javascript=esbuild # Kein natives HMR
# Alternative mit Vite:
bundle add vite_rails
npm install vite @sveltejs/vite-plugin-svelte
Der Nachteil von Vite: zusätzliche Konfigurationskomplexität. Für die meisten Projekte reicht der ESBuild-Watcher mit Page Reload.
Turbo und Svelte kollidieren
Turbo ersetzt den <body> bei Navigation, was Svelte-Komponenten zerstört. Lösung: Komponenten bei turbo:load neu initialisieren oder data-turbo="false" auf Links setzen, die zu Seiten mit Svelte-Komponenten führen.
document.addEventListener('turbo:load', () => {
// Svelte-Komponenten hier neu mounten
});
Fazit: Svelte gezielt statt pauschal einsetzen
Svelte in Rails 7 funktioniert. Die Integration über svelte-on-rails und ESBuild ist stabil, die Bundle-Grössen sind exzellent. Aber der Rails-Weg mit Hotwire deckt 80% der typischen Anforderungen ab, ohne ein zweites Ökosystem einzuführen.
Unsere Empfehlung: Starten Sie mit Hotwire/Turbo. Wenn Sie an die Grenzen von Stimulus stossen (komplexe Client-Logik, verschachtelte Zustände, Drag-and-Drop), binden Sie Svelte für genau diese Komponenten ein. So halten Sie die Wartungskosten niedrig und profitieren trotzdem von Sveltes Compiler-Vorteilen.
FAQs
Brauche ich Svelte, wenn ich Rails 7 mit Hotwire nutze?
In den meisten Fällen nicht. Hotwire (Turbo + Stimulus) deckt Navigation, Formulare und einfache Interaktivität ab. Svelte lohnt sich erst bei zustandsbehafteter Client-Logik: Dashboards, interaktive Editoren oder Drag-and-Drop-Interfaces.
Wie gross ist der Wartungsaufwand für beide Stacks?
Sie pflegen zwei Dependency-Bäume: Ruby-Gems (Bundler) und npm-Pakete (Node). Jedes Rails-Upgrade erfordert auch die Prüfung der JavaScript-Toolchain. Bei USEO planen wir dafür ca. 20% mehr Zeit pro Major-Upgrade ein.
Kann ich Svelte-Komponenten schrittweise einführen?
Ja, das ist der empfohlene Weg. Sie können einzelne Svelte-Komponenten in bestehende ERB-Views einbetten, ohne die gesamte Anwendung umzubauen. Jede Komponente ist eigenständig und hat keine Abhängigkeiten zu anderen Svelte-Teilen.
Welche Node-Version brauche ich mindestens?
Node 18 LTS oder neuer. Node 16 hat seit September 2023 keinen Support mehr. Für Svelte 4 empfehlen wir Node 20 LTS, das bis April 2026 unterstützt wird.