Zum Hauptinhalt springen

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

Vue.js development in Cursor

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
tipp

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:

  1. Öffnen Sie die Erweiterungsansicht in Cursor mit Ctrl+Shift+X (oder Cmd+Shift+X auf macOS).
  2. Suchen Sie nach "Vue - Official".
  3. Klicken Sie auf Install.
warnung

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
tipp

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>
warnung

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>
tipp

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.

tipp

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"]
}
warnung

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>
warnung

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
<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>
tipp

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.

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.

tipp

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,
},
})
warnung

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'] }],
},
}
tipp

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+Click auf 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>
warnung

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.