Vue.js-Entwicklung in Cursor: Ein vollständiger Leitfaden

Vue.js hat sich zu einem der beliebtesten progressiven JavaScript-Frameworks für die Entwicklung von Benutzeroberflächen entwickelt. Mit Vue 3, das die Composition API, <script setup> und ein neu geschriebenes Reaktivitätssystem einführte, benötigen Entwickler einen Editor, der das moderne Vue-Ökosystem tiefgreifend versteht. Cursor kombiniert eine VS Code-kompatible Basis mit erstklassiger KI-Unterstützung und ist damit eine hervorragende Umgebung für die Vue.js-Entwicklung.
Dieser Leitfaden führt Sie durch die Einrichtung eines produktiven Vue.js-Workflows in Cursor, vom Projekt-Scaffolding über Zustandsverwaltung und Routing bis hin zur KI-gestützten Komponentengenerierung. egal, ob Sie eine Options-API-Codebasis zu Vue 3 migrieren oder ein neues SFC-Projekt (Single File Component) starten – die folgenden Techniken helfen Ihnen, schneller voranzukommen und dabei Ihren Code sauber und wartbar zu halten.
Einrichtung Ihrer Vue.js-Umgebung in Cursor
Voraussetzungen und Node.js-Setup
Bevor Sie Vue-Code schreiben, stellen Sie sicher, dass Ihr System die richtigen Grundlagen aufweist. Cursor erbt die Node.js-Installation auf Ihrem Rechner, daher sollten Sie zuerst Ihre Version überprüfen.
node --version
npm --version
Vue 3 und die Volar-Toolchain benötigen Node.js 18 oder höher. Wenn Sie eine ältere Version verwenden, aktualisieren Sie mit einem Versionsmanager wie nvm oder fnm:
# Mit fnm (für Geschwindigkeit empfohlen)
fnm install 20
fnm use 20
# Mit nvm
nvm install 20
nvm use 20
Das integrierte Terminal von Cursor unterstützt alle gängigen Shell-Tools. Sie können es mit Ctrl+` (Windows/Linux) oder Cmd+` (macOS) öffnen und jeden CLI-Befehl ausführen, ohne den Editor zu verlassen.
Installation der Volar-Erweiterung
Die wichtigste Erweiterung für die Vue.js-Entwicklung in Cursor ist Volar (die offizielle Vue.js-Sprachunterstützung, jetzt als Vue - Official-Erweiterung vertrieben). Sie bietet Typprüfung, IntelliSense, Formatierung und Diagnostik für .vue-Dateien.
Installation:
- Öffnen Sie die Erweiterungsansicht in Cursor mit
Ctrl+Shift+X(oderCmd+Shift+Xauf macOS). - Suchen Sie nach "Vue - Official".
- Klicken Sie auf Install.
Vermeiden Sie es, die veraltete Vetur-Erweiterung parallel zu Volar aktiviert zu lassen. Vetur wurde für Vue 2 entwickelt und steht im Konflikt mit der modernen Toolchain. Wenn Sie sie installiert haben, deaktivieren oder deinstallieren Sie sie, um doppelte Diagnosen und falsche IntelliSense-Vorschläge zu vermeiden.
Optional können Sie diese ergänzenden Erweiterungen installieren, um Ihren Workflow abzurunden:
- ESLint — für das Linten von
.vue- und.js/.ts-Dateien. - Prettier — für einheitliche Formatierung.
- TypeScript Vue Plugin (Volar) — verbessert die Typauflösung in Templates.
Scaffolding eines neuen Vue 3-Projekts
Der empfohlene Weg, ein neues Vue-Projekt zu erstellen, ist das offizielle create-vue-Scaffolding-Tool, das vom Vue-Kernteam gepflegt wird und Vite, TypeScript, Router und Pinia optional integriert.
npm create vue@latest my-vue-app
Die interaktive Eingabeaufforderung lässt Sie Funktionen wählen:
Vue.js - The Progressive JavaScript Framework
? Project name: my-vue-app
? Add TypeScript? Yes
? Add JSX Support? No
? Add Vue Router for Single Page Application development? Yes
? Add Pinia for state management? Yes
? Add Vitest for Unit Testing? Yes
? Add ESLint for code quality? Yes
? Add Prettier for code formatting? Yes
Öffnen Sie nach dem Scaffolding das Projekt in Cursor:
cd my-vue-app
cursor .
Installieren Sie Abhängigkeiten und starten Sie den Dev-Server:
npm install
npm run dev
Cursor erkennt den Vite-Dev-Server automatisch. Wenn Sie npm run dev ausführen, zeigt das Terminal von Cursor die lokale URL (typischerweise http://localhost:5173). Sie können Ctrl+Click auf die URL ausführen, um die laufende App in Ihrem Standardbrowser zu öffnen.
Die Vue 3 Composition API meistern
Die <script setup>-Syntax verstehen
Die <script setup>-Syntax ist die empfohlene Methode zum Erstellen von Vue 3-Komponenten. Es ist ein Compile-Time-Syntaxzucker, der den Boilerplate-Code im Vergleich zur Options API drastisch reduziert.
<script setup lang="ts">
import { ref, computed } from 'vue'
interface Props {
title: string
count?: number
}
const props = withDefaults(defineProps<Props>(), {
count: 0,
})
const emit = defineEmits<{
(e: 'update', value: number): void
}>()
const doubled = computed(() => props.count * 2)
function increment() {
const next = props.count + 1
emit('update', next)
}
</script>
<template>
<div class="counter">
<h2>{{ title }}</h2>
<p>Count: {{ count }} (doubled: {{ doubled }})</p>
<button @click="increment">Increment</button>
</div>
</template>
<style scoped>
.counter {
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
}
</style>
defineProps und defineEmits sind Compiler-Makros. Sie müssen nicht importiert werden und sind nur innerhalb von <script setup> verfügbar. Der Versuch, sie in einem regulären <script>-Block ohne Setup zu verwenden, führt zu einem Kompilierungsfehler.
Reaktiver Zustand mit ref und reactive
Vue 3 bietet zwei primäre Möglichkeiten, reaktiven Zustand zu deklarieren. Die Wahl zwischen beiden ist eine häufige Verwirrungsquelle für Einsteiger.
<script setup lang="ts">
import { ref, reactive } from 'vue'
// ref funktioniert mit Primitiven und Objekten
const count = ref(0)
const user = ref({ name: 'Ada', age: 36 })
// reactive funktioniert nur mit Objekten/Arrays
const settings = reactive({
theme: 'light',
notifications: true,
})
function toggleTheme() {
settings.theme = settings.theme === 'light' ? 'dark' : 'light'
}
</script>
<template>
<button @click="count++">{{ count }}</button>
<p>{{ user.name }} — theme: {{ settings.theme }}</p>
<button @click="toggleTheme">Toggle Theme</button>
</template>
Eine praktische Faustregel: Verwenden Sie ref für Primitive und Objekte, die Sie möglicherweise vollständig neu zuweisen, und reactive für gruppierte Zustandsobjekte, die Sie an Ort und Stelle verändern. In Templates werden Refs automatisch entpackt, daher schreiben Sie {{ count }} statt {{ count.value }}.
Composables für wiederverwendbare Logik
Composables sind Funktionen, die wiederverwendbare reaktive Logik einkapseln. Sie folgen der Namenskonvention useSomething. Der KI-Assistent von Cursor ist hervorragend darin, Composables aus natürlichsprachlichen Beschreibungen zu generieren.
// composables/useFetch.ts
import { ref, watchEffect, type Ref } from 'vue'
export function useFetch<T>(url: Ref<string>) {
const data = ref<T | null>(null) as Ref<T | null>
const error = ref<string | null>(null)
const loading = ref(false)
watchEffect(async () => {
loading.value = true
error.value = null
try {
const response = await fetch(url.value)
if (!response.ok) throw new Error(`HTTP ${response.status}`)
data.value = (await response.json()) as T
} catch (err) {
error.value = err instanceof Error ? err.message : 'Unknown error'
} finally {
loading.value = false
}
})
return { data, error, loading }
}
Verwendung in einer Komponente:
<script setup lang="ts">
import { ref } from 'vue'
import { useFetch } from '../composables/useFetch'
interface Post {
id: number
title: string
body: string
}
const endpoint = ref('https://jsonplaceholder.typicode.com/posts/1')
const { data: post, error, loading } = useFetch<Post>(endpoint)
</script>
<template>
<div v-if="loading">Loading...</div>
<div v-else-if="error" class="error">{{ error }}</div>
<article v-else-if="post">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</article>
</template>
Arbeiten mit der Volar-Erweiterung
Typgeprüfte Templates
Eine der leistungsstärksten Funktionen von Volar ist die Typprüfung innerhalb des <template>-Blocks. Dadurch werden Tippfehler in Komponenten-Props, Ereignisnamen und Ausdrucksfehlern zur Kompilierzeit statt zur Laufzeit abgefangen.
<script setup lang="ts">
import Counter from './Counter.vue'
</script>
<template>
<!-- Volar markiert dies, wenn die Prop nicht existiert -->
<Counter title="Clicks" :count="5" @update="handleChange" />
</template>
Wenn Counter keine count-Prop deklariert, zeigt Volar eine rote Wellenlinie unter dem Attribut und eine Diagnosemeldung im Probleme-Panel an.
Führen Sie vue-tsc --noEmit als Teil Ihrer CI-Pipeline aus, um die Template-Typprüfung im gesamten Projekt zu erzwingen. Fügen Sie es zu Ihren package.json-Skripten hinzu:
{
"scripts": {
"type-check": "vue-tsc --noEmit"
}
}
Workspace-Konfiguration
Erstellen Sie eine .vscode/settings.json-Datei (von Cursor geteilt), um die Volar-Einstellungen für Ihr gesamtes Team festzulegen:
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "Vue.volar",
"vue.codeActions.askNewComponentName": false,
"vue.inlayHints.missingProps": true,
"vue.inlayHints.inlineHandlerLeading": true,
"typescript.tsdk": "node_modules/typescript/lib"
}
Take Over Mode (eigenständiges TypeScript)
Volar kann die eingebaute TypeScript-Erweiterung "übernehmen", um ein besseres Vue-bewusstes IntelliSense für .ts- und .vue-Dateien zu bieten. Erstellen Sie in einem Workspace .vscode/settings.json mit:
{
"typescript.preferences.importModuleSpecifier": "relative",
"vue.server.includeLanguages": ["vue"]
}
Der Take Over Mode deaktiviert die Standard-TS-Erweiterung für diesen Workspace. Wenn Sie in gemischten Projekten arbeiten, die Non-Vue-TypeScript-Bibliotheken enthalten, testen Sie sorgfältig, um sicherzustellen, dass die externe Typauflösung weiterhin wie erwartet funktioniert.
Zustandsverwaltung mit Pinia
Warum Pinia statt Vuex
Pinia ist die offizielle Zustandsverwaltungsbibliothek für Vue 3. Sie ist der Nachfolger von Vuex und bietet mehrere Vorteile:
- Einfachere, typsichere API ohne Mutationen (Sie verändern den Zustand direkt).
- Erstklassige TypeScript-Unterstützung mit vollständiger Autovervollständigung.
- Modularität — jeder Store wird unabhängig definiert.
- Ausgezeichnete DevTools-Integration.
Einen Store definieren
// stores/counter.ts
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubled = computed(() => count.value * 2)
function increment() {
count.value++
}
async function incrementAsync() {
await new Promise((resolve) => setTimeout(resolve, 200))
count.value++
}
return { count, doubled, increment, incrementAsync }
})
Den Store in Komponenten verwenden
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useCounterStore } from '../stores/counter'
const counter = useCounterStore()
// Reaktiven Zustand sicher destrukturieren
const { count, doubled } = storeToRefs(counter)
// Actions können direkt destrukturiert werden
const { increment, incrementAsync } = counter
</script>
<template>
<div class="counter">
<p>Count: {{ count }} / Doubled: {{ doubled }}</p>
<button @click="increment">+1</button>
<button @click="incrementAsync">+1 (async)</button>
</div>
</template>
Destrukturieren Sie niemals Store-Zustand mit einem einfachen const { count } = counter — Sie verlieren die Reaktivität. Verwenden Sie immer storeToRefs für Zustand und Getter, und destrukturieren Sie Actions direkt, da sie einfache Funktionen sind.
Mehrere Stores organisieren
Für größere Anwendungen teilen Sie Stores nach Domäne auf:
src/stores/
├── auth.ts
├── cart.ts
├── products.ts
└── ui.ts
Ein store-übergreifendes Muster ermöglicht es einem Store, einen anderen aufzurufen:
// stores/cart.ts
import { defineStore } from 'pinia'
import { useProductsStore } from './products'
export const useCartStore = defineStore('cart', () => {
const items = ref<{ id: number; qty: number }[]>([])
function addToCart(productId: number) {
const products = useProductsStore()
if (!products.exists(productId)) {
throw new Error('Product not found')
}
items.value.push({ id: productId, qty: 1 })
}
return { items, addToCart }
})
Routing mit Vue Router
Routen konfigurieren
// router/index.ts
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const routes: RouteRecordRaw[] = [
{ path: '/', name: 'home', component: HomeView },
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue'),
},
{
path: '/users/:id',
name: 'user-detail',
component: () => import('../views/UserDetailView.vue'),
props: true,
},
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
})
export default router
Navigation und Routenparameter
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'
import { computed } from 'vue'
const route = useRoute()
const router = useRouter()
const userId = computed(() => route.params.id as string)
function goHome() {
router.push({ name: 'home' })
}
</script>
<template>
<div>
<p>Viewing user #{{ userId }}</p>
<button @click="goHome">Back to Home</button>
</div>
</template>
Verwenden Sie lazy-loaded Komponenten (() => import(...)) für Routensegmente, die nicht sofort benötigt werden. Dies erzeugt kleinere anfängliche Bundles und schnelleren First Paint, was besonders in mobilen Netzwerken wichtig ist.
Navigationsguards
router.beforeEach((to, from) => {
const isAuthenticated = localStorage.getItem('token') !== null
if (to.meta.requiresAuth && !isAuthenticated) {
return { name: 'login', query: { redirect: to.fullPath } }
}
})
Wenden Sie das Meta-Feld pro Route an:
{
path: '/dashboard',
component: () => import('../views/DashboardView.vue'),
meta: { requiresAuth: true },
}
KI-gestützte Komponentengenerierung in Cursor
SFCs aus Prompts generieren
Der KI-Assistent von Cursor kann vollständige Single File Components aus einer Klartextbeschreibung generieren. Öffnen Sie die Befehlspalette (Ctrl+Shift+P) und wählen Sie Cursor: New Chat oder verwenden Sie Ctrl+K inline.
Beispiel-Prompt:
Create a Vue 3 component using script setup and TypeScript for a paginated
data table. It should accept a columns prop (array of { key, label }),
a rows prop (array of records), and emit a page-change event with the new
page number. Include scoped styles and show empty-state messaging.
Cursor erzeugt eine per Scaffolding erstellte .vue-Datei mit allen drei Blöcken. Überprüfen Sie die Ausgabe und verfeinern Sie sie iterativ — bitten Sie es, Loading-Skeletons, Sortierung oder Sticky-Headers hinzuzufügen, je nach Bedarf.
Seien Sie spezifisch bezüglich der Vue-Version und des Syntaxstils in Ihrem Prompt. Die Angabe "Vue 3 with <script setup lang="ts"> and Composition API" verhindert, dass das Modell Options-API-Code oder Vue 2-Muster ausgibt.
Bestehende Komponenten refaktorieren
Cursor kann ältere Options-API-Komponenten in Composition-API-Äquivalente umwandeln. Markieren Sie die Komponente, drücken Sie Ctrl+K, und geben Sie ein:
Convert this Options API component to script setup using the Composition API.
Keep all existing props, emits, and methods. Use composables for any logic
that could be reused elsewhere.
Die KI schreibt die Datei um, wobei das Verhalten erhalten bleibt. Führen Sie danach immer Ihre Test-Suite aus, um die Übereinstimmung zu bestätigen.
Tests mit KI generieren
Koppeln Sie Vue-Komponenten mit von Cursor generierten Vitest-Tests:
// Counter.spec.ts
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import Counter from './Counter.vue'
describe('Counter.vue', () => {
it('renders the title prop', () => {
const wrapper = mount(Counter, { props: { title: 'Clicks', count: 0 } })
expect(wrapper.text()).toContain('Clicks')
})
it('emits update with incremented value on click', async () => {
const wrapper = mount(Counter, { props: { title: 'Clicks', count: 5 } })
await wrapper.find('button').trigger('click')
expect(wrapper.emitted('update')?.[0]).toEqual([6])
})
})
Prompten Sie Cursor mit: "Generate Vitest unit tests for Counter.vue covering the increment behavior and empty-state rendering."
Debugging und Profiling von Vue-Apps in Cursor
Vue DevTools-Integration
Installieren Sie die Vue.js devtools-Browsererweiterung oder verwenden Sie die eigenständige Electron-App. Cursor selbst hostet zwar nicht die DevTools-Oberfläche, aber die Volar-Erweiterung zeigt Komponentendiagnosen inline an.
Um den Pinia-Store-Zustand zu debuggen, zeigt der "Pinia"-Tab in den Vue DevTools jeden Store, seinen aktuellen Zustand und eine Timeline von Actions an — unschätzbar für die Verfolgung von veralteten Zustands-Bugs.
Source Maps und Vite
Vite generiert standardmäßig Source Maps für die Entwicklung. Stellen Sie sicher, dass Ihre vite.config.ts sie aktiviert lässt:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
sourcemap: true,
},
})
Das Ausliefern von Source Maps in Produktion kann Ihren Original-Quellcode offenlegen. Für Produktions-Builds setzen Sie sourcemap: 'hidden' oder verwenden Sie einen gehosteten Source-Map-Service, und committen Sie niemals .map-Dateien in ein öffentliches Repository.
Performance-Profiling
Verwenden Sie den Chrome-Performance-Tab zusammen mit Cursor. Das vite-plugin-vue-inspector (oder unplugin-vue-source) ermöglicht es Ihnen, auf ein beliebiges Element im Browser zu klicken, um direkt zur Quellzeile in Cursor zu springen — ein massiver Produktivitätsschub für die Navigation in großen Codebasen.
npm install -D vite-plugin-vue-devtools
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import VueDevTools from 'vite-plugin-vue-devtools'
export default defineConfig({
plugins: [vue(), VueDevTools()],
})
Best Practices für Vue.js in Cursor
Projektstruktur-Konventionen
Eine skalierbare Struktur sieht so aus:
src/
├── assets/
├── components/
│ ├── common/
│ └── forms/
├── composables/
├── layouts/
├── router/
├── stores/
├── views/
├── App.vue
└── main.ts
Linting und Formatierung
Fixieren Sie ESLint- und Prettier-Versionen in package.json, damit das gesamte Team identische Regeln teilt:
{
"devDependencies": {
"eslint": "^9.0.0",
"eslint-plugin-vue": "^9.0.0",
"prettier": "^3.0.0",
"@vue/eslint-config-typescript": "^13.0.0"
}
}
Erstellen Sie .eslintrc.cjs:
module.exports = {
root: true,
env: { browser: true, node: true },
extends: [
'plugin:vue/vue3-recommended',
'@vue/eslint-config-typescript',
],
rules: {
'vue/multi-word-component-names': 'off',
'vue/component-tags-order': ['error', { order: ['script', 'template', 'style'] }],
},
}
Konfigurieren Sie Cursor so, dass Lint-Fehler beim Speichern behoben werden, indem Sie Folgendes zu settings.json hinzufügen:
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
Tastenkürzel für den Vue-Workflow
Ctrl+K— Inline-KI-Bearbeitung/Refaktorierung.Ctrl+Shift+P→ "Cursor: New Chat" — den KI-Chat für Komponentengenerierung öffnen.Alt+Clickauf ein Komponenten-Tag — zur Definition springen (powered by Volar).Ctrl+.— Quick-Fix-Menü für Volar-Diagnosen.
Häufige Fallstricke und wie man sie vermeidet
Verlust der Reaktivität nach Destrukturierung
Der häufigste Vue 3-Fehler ist das direkte Destrukturieren von reaktiven Objekten oder Refs:
// FALSCH — verliert Reaktivität
const { count } = useCounterStore()
// RICHTIG
const { count } = storeToRefs(useCounterStore())
Mutieren von Props
Props sind schreibgeschützt. Wenn ein Kind einen Wert ändern muss, emittieren Sie stattdessen ein Ereignis:
<script setup lang="ts">
const props = defineProps<{ modelValue: string }>()
const emit = defineEmits<{ (e: 'update:modelValue', v: string): void }>()
// Computed-Setter für v-model-Passthrough verwenden
import { computed } from 'vue'
const proxy = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val),
})
</script>
Vergessen von :key in v-for
Binden Sie immer einen eindeutigen :key, damit Vue Knoten effizient verfolgen kann:
<template>
<li v-for="item in items" :key="item.id">{{ item.label }}</li>
</template>
Die Verwendung des Array-Index als :key kann subtile Bugs verursachen, wenn die Liste neu geordnet oder gefiltert wird. Bevorzugen Sie einen stabilen eindeutigen Bezeichner wie eine Datenbank-ID.
Zusammenfassung
Cursor bietet Vue.js-Entwicklern einen modernen, KI-erweiterten Arbeitsbereich, der gut mit der offiziellen Vue-Toolchain harmoniert. Durch die Kombination von Volar für typsicheres Schreiben, Pinia für saubere Zustandsverwaltung, Vue Router für Navigation und der KI von Cursor für Komponentengenerierung und Refaktorierung können Sie Vue 3-Anwendungen schneller und mit weniger Bugs ausliefern. Beginnen Sie mit dem Scaffolding eines Projekts mit create-vue, fixieren Sie Ihre ESLint- und Formatierungsregeln, und lassen Sie die KI von Cursor das wiederholte Scaffolding übernehmen, während Sie sich auf Produktlogik und Benutzererfahrung konzentrieren.