Modul 1: Einstieg

Projekt-Struktur

Jeder Ordner und jede Datei in einem Vue-Projekt erklärt — mit direktem Vergleich zur Rails-Konvention.

Überblick

Nach npm create vue@latest mit allen Optionen entsteht eine klar strukturierte Projektstruktur. Anders als Rails setzt Vue auf eine flache Hierarchie mit wenigen, aber wichtigen Ordnern.

🛤️

Convention over Configuration

Rails lebt von Konventionen: Alles hat seinen festen Platz. Vue ist flexibler — es gibt Empfehlungen, aber keine harten Regeln. Die von create-vue erzeugte Struktur ist jedoch der de-facto-Standard und sollte beibehalten werden.

Der Verzeichnisbaum

So sieht ein frisch erstelltes Vue-Projekt aus:

Projektstruktur
mein-vue-projekt/
├── public/                  # Statische Dateien (Favicon, robots.txt)
│   └── favicon.ico
├── src/                     # Quellcode der Anwendung
│   ├── assets/              # CSS, Bilder, Schriften
│   │   ├── base.css
│   │   ├── logo.svg
│   │   └── main.css
│   ├── components/          # Wiederverwendbare Komponenten
│   │   ├── HelloWorld.vue
│   │   ├── TheWelcome.vue
│   │   ├── WelcomeItem.vue
│   │   └── icons/
│   │       └── ...
│   ├── composables/         # Wiederverwendbare Logik (Hooks)
│   ├── router/              # Vue Router Konfiguration
│   │   └── index.ts
│   ├── stores/              # Pinia Stores (State Management)
│   │   └── counter.ts
│   ├── views/               # Seiten-Komponenten (Routen-Ziele)
│   │   ├── HomeView.vue
│   │   └── AboutView.vue
│   ├── App.vue              # Wurzel-Komponente
│   └── main.ts              # Einstiegspunkt der Anwendung
├── .eslintrc.cjs            # ESLint-Konfiguration
├── .prettierrc.json         # Prettier-Konfiguration
├── env.d.ts                 # TypeScript-Umgebungstypen
├── index.html               # HTML-Einstiegspunkt
├── package.json             # Abhängigkeiten und Skripte
├── tsconfig.json            # TypeScript-Konfiguration
├── tsconfig.app.json        # TypeScript-Config für die App
├── tsconfig.node.json       # TypeScript-Config für Node (Vite)
└── vite.config.ts           # Vite Build-Konfiguration

public/ — Statische Dateien

Dateien in public/ werden unverändert in den Build kopiert. Hier gehören Dateien hin, die nicht durch das Build-System verarbeitet werden sollen: Favicons, robots.txt, Open-Graph-Bilder.

🛤️

public/ in Rails vs. Vue

In Rails ist public/ ebenfalls für statische Dateien. Der Unterschied: Rails hat zusätzlich die Asset Pipeline (app/assets/). In Vue übernimmt src/assets/ die Rolle der Asset Pipeline, während public/ identisch funktioniert.

src/ — Der Quellcode

Alles, was du entwickelst, lebt in src/. Das ist das Äquivalent zu app/ in Rails. Schauen wir uns jeden Unterordner an:

src/assets/ — Styles und Medien

CSS-Dateien, Bilder und Schriften, die vom Build-System verarbeitet werden. Vite optimiert diese Dateien automatisch: CSS wird minimiert, Bilder werden mit Hashes versehen (Cache-Busting), und ungenutzte Assets werden entfernt.

src/assets/main.css
/* Globale Styles */
@import './base.css';

#app {
  max-width: 1280px;
  margin: 0 auto;
  padding: 2rem;
  font-weight: normal;
}

src/components/ — Wiederverwendbare Bausteine

Hier leben alle wiederverwendbaren UI-Komponenten. Eine Komponente ist eine in sich geschlossene Einheit aus Template, Logik und optionalem Styling.

Gängige Namenskonventionen:

  • Base* — Basis-Komponenten (BaseButton, BaseInput)
  • The* — Singleton-Komponenten (TheHeader, TheSidebar)
  • App* — App-spezifische Komponenten (AppNotification)
🛤️

Partials vs. Komponenten

Rails-Partials (_header.html.erb) sind reines HTML mit eingebettetem Ruby. Vue-Komponenten enthalten zusätzlich ihre eigene Logik und ihr eigenes Styling. Eine Vue-Komponente ist eher vergleichbar mit einem ViewComponent oder einem Stimulus-Controller mit zugehörigem Partial.

src/composables/ — Wiederverwendbare Logik

Composables sind Funktionen, die reaktive Logik kapseln und in mehreren Komponenten wiederverwendet werden können. Sie beginnen konventionell mit use — z.B. useAuth, useFetch, useLocalStorage.

src/composables/useCounter.ts
import { ref, computed } from 'vue'

export function useCounter(initial = 0) {
  const count = ref(initial)
  const doubled = computed(() => count.value * 2)

  function increment() {
    count.value++
  }

  function reset() {
    count.value = initial
  }

  return { count, doubled, increment, reset }
}
🛤️

Concerns und Service Objects

Composables erfüllen eine ähnliche Rolle wie Rails Concerns oder Service Objects: Sie extrahieren wiederverwendbare Logik aus der Hauptklasse (bzw. Komponente). Der Unterschied: Composables sind reaktiv — sie aktualisieren automatisch alle Komponenten, die sie nutzen.

src/router/ — Routing

Die Router-Konfiguration ordnet URLs zu Vue-Komponenten zu. Jede Route definiert einen Pfad und die zugehörige Komponente:

src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const router = createRouter({
  history: createWebHistory(globalThis._importMeta_.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView
    },
    {
      path: '/about',
      name: 'about',
      // Lazy Loading: wird erst bei Bedarf geladen
      component: () => import('../views/AboutView.vue')
    }
  ]
})

export default router
🛤️

routes.rb vs. router/index.ts

In Rails definierst du Routen in config/routes.rb und sie verweisen auf Controller-Actions. In Vue definierst du Routen in router/index.ts und sie verweisen auf Komponenten. Rails-Routen laufen auf dem Server, Vue-Routen im Browser. Lazy Loading (() => import(...)) ist wie Rails' autoloading — Dateien werden erst geladen, wenn sie gebraucht werden.

src/stores/ — State Management mit Pinia

Pinia Stores verwalten den Anwendungszustand, der über mehrere Komponenten geteilt wird. Jeder Store ist eine eigene Datei mit State, Getters und Actions:

src/stores/counter.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)

  function increment() {
    count.value++
  }

  return { count, doubleCount, increment }
})

src/views/ — Seiten-Komponenten

Views sind die „Seiten" der Anwendung — die Komponenten, auf die der Router verweist. Sie werden oft als Container verwendet, die kleinere Komponenten zusammensetzen.

💡

Views vs. Components

Die Trennung ist rein organisatorisch: Views sind Seiten (werden vom Router angezeigt), Components sind wiederverwendbare Bausteine. Technisch sind beides Vue-Komponenten. In Rails wäre das vergleichbar mit dem Unterschied zwischen einer View (index.html.erb) und einem Partial (_form.html.erb).

Die Wurzel-Dateien

index.html — Der Einstiegspunkt

Die einzige HTML-Datei der gesamten Anwendung. Vue mountet sich in das <div id="app">-Element:

index.html
<!DOCTYPE html>
<html lang="de">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mein Vue Projekt</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>
🛤️

application.html.erb vs. index.html

In Rails ist application.html.erb das Layout, in das Views eingebettet werden. In Vue ist index.html die Shell — aber der gesamte sichtbare Inhalt wird von Vue im <div id="app"> gerendert. Es gibt keine ERB-Tags, kein yield.

main.ts — App-Bootstrap

Hier wird die Vue-App erstellt, Plugins registriert und in das DOM gemountet:

src/main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'
import router from './router'

import './assets/main.css'

const app = createApp(App)

app.use(createPinia())  // State Management
app.use(router)          // Routing

app.mount('#app')        // In <div id="app"> rendern

App.vue — Die Wurzel-Komponente

Die oberste Komponente der Anwendung. Sie enthält typischerweise das Layout (Header, Navigation, Footer) und einen <RouterView /> für den seitenspezifischen Inhalt:

src/App.vue
<template>
  <header>
    <nav>
      <RouterLink to="/">Home</RouterLink>
      <RouterLink to="/about">Über uns</RouterLink>
    </nav>
  </header>

  <RouterView />
</template>

vite.config.ts — Build-Konfiguration

vite.config.ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', globalThis._importMeta_.url))
    }
  }
})
💡

Das @-Alias

@ ist ein Alias für src/. Statt ../../components/MyButton.vue schreibst du @/components/MyButton.vue. Das macht Imports übersichtlicher und unabhängig von der Verzeichnistiefe.

Struktur-Vergleich: Rails vs. Vue

RailsVue / ViteFunktion
app/src/Quellcode-Verzeichnis
app/views/src/views/Seiten / Templates
app/views/ (Partials)src/components/Wiederverwendbare Teile
app/controllers/src/composables/Logik und Steuerung
app/models/src/stores/Datenhaltung
app/assets/src/assets/CSS, Bilder, Fonts
config/routes.rbsrc/router/index.tsRouting-Definition
config/vite.config.tsBuild-Konfiguration
public/public/Statische Dateien (identisch!)
Gemfilepackage.jsonAbhängigkeiten
Gemfile.lockpackage-lock.jsonLock-Datei für exakte Versionen

Was fehlt im Vergleich zu Rails?

Ein Vue-Projekt ist absichtlich schlank. Vieles, was Rails mitbringt, fehlt:

Rails hat…Vue braucht…
Datenbank (ActiveRecord)Externe API (z.B. Rails-API)
Mailer (ActionMailer)Backend-Service für E-Mails
Background Jobs (ActiveJob)Backend-Service für Jobs
Authentifizierung (Devise)Token-basierte Auth über API
Generatoren (rails generate)Manuelles Erstellen von Dateien
ℹ️

Vue ist ein Frontend-Framework

Vue ist bewusst auf das Frontend beschränkt. Für alles, was einen Server braucht (Datenbank, Auth, E-Mails, Jobs), brauchst du ein Backend — und dafür ist Rails perfekt geeignet. Vue + Rails API ist eine sehr beliebte Kombination.

Zusammenfassung

  • src/ ist das Äquivalent zu app/ in Rails
  • Komponenten (components/) ersetzen Partials
  • Composables (composables/) ersetzen Concerns und Service Objects
  • Stores (stores/) ersetzen Models für clientseitigen Zustand
  • Views (views/) sind die Seiten, auf die der Router verweist
  • vite.config.ts entspricht der Build-Konfiguration
  • Vue hat keine Datenbank, keinen Mailer, keine Jobs — dafür brauchst du ein Backend