Développement Vue.js dans Cursor : Un Guide Complet

Vue.js est devenu l'un des frameworks JavaScript progressifs les plus populaires pour la construction d'interfaces utilisateur. Avec Vue 3 introduisant la Composition API, <script setup> et un système de réactivité réécrit, les développeurs ont besoin d'un éditeur qui comprend profondément l'écosystème Vue moderne. Cursor combine une base compatible VS Code avec une assistance IA de premier ordre, ce qui en fait un environnement exceptionnel pour le développement Vue.js.
Ce guide vous accompagne dans la configuration d'un flux de travail Vue.js productif dans Cursor, du scaffolding de projet à la gestion d'état, au routage et à la génération de composants assistée par IA. Que vous migreriez une base de code Options API vers Vue 3 ou que vous démarriez un nouveau projet SFC (Single File Component), les techniques ci-dessous vous aideront à avancer plus rapidement tout en gardant votre code propre et maintenable.
Configuration de votre environnement Vue.js dans Cursor
Prérequis et configuration de Node.js
Avant d'écrire du code Vue, assurez-vous que votre système dispose des bonnes fondations. Cursor hérite de l'installation Node.js de votre machine, alors vérifiez d'abord votre version.
node --version
npm --version
Vue 3 et la chaîne d'outils Volar nécessitent Node.js 18 ou supérieur. Si vous êtes sur une version plus ancienne, utilisez un gestionnaire de versions tel que nvm ou fnm pour mettre à niveau :
# Utilisation de fnm (recommandé pour la vitesse)
fnm install 20
fnm use 20
# Utilisation de nvm
nvm install 20
nvm use 20
Le terminal intégré de Cursor prend en charge tous les outils shell courants. Vous pouvez l'ouvrir avec Ctrl+` (Windows/Linux) ou Cmd+` (macOS) et exécuter n'importe quelle commande CLI sans quitter l'éditeur.
Installation de l'extension Volar
L'extension la plus importante pour le développement Vue.js dans Cursor est Volar (le support linguistique officiel de Vue.js, désormais distribué sous le nom d'extension Vue - Official). Elle fournit la vérification des types, IntelliSense, le formatage et les diagnostics pour les fichiers .vue.
Pour l'installer :
- Ouvrez la vue Extensions dans Cursor avec
Ctrl+Shift+X(ouCmd+Shift+Xsur macOS). - Recherchez "Vue - Official".
- Cliquez sur Install.
Évitez de garder l'ancienne extension Vetur activée en même temps que Volar. Vetur a été conçu pour Vue 2 et entre en conflit avec la chaîne d'outils moderne. Si vous l'avez installée, désactivez-la ou désinstallez-la pour éviter les diagnostics en double et les suggestions IntelliSense incorrectes.
Installez optionnellement ces extensions complémentaires pour compléter votre flux de travail :
- ESLint — pour le linting des fichiers
.vueet.js/.ts. - Prettier — pour un formatage cohérent.
- TypeScript Vue Plugin (Volar) — améliore la résolution des types dans les modèles.
Scaffolding d'un nouveau projet Vue 3
La méthode recommandée pour créer un nouveau projet Vue est d'utiliser l'outil de scaffolding officiel create-vue, maintenu par l'équipe principale de Vue et intégrant Vite, TypeScript, Router et Pinia de manière optionnelle.
npm create vue@latest my-vue-app
L'invite interactive vous permet de choisir les fonctionnalités :
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
Une fois le scaffolding terminé, ouvrez le projet dans Cursor :
cd my-vue-app
cursor .
Installez les dépendances et démarrez le serveur de développement :
npm install
npm run dev
Cursor reconnaît automatiquement le serveur de développement Vite. Lorsque vous exécutez npm run dev, le terminal de Cursor affiche l'URL locale (généralement http://localhost:5173). Vous pouvez Ctrl+Click sur l'URL pour ouvrir l'application en cours d'exécution dans votre navigateur par défaut.
Maîtriser la Composition API de Vue 3
Comprendre la syntaxe <script setup>
La syntaxe <script setup> est la méthode recommandée pour créer des composants Vue 3. C'est un sucre syntaxique à la compilation qui réduit considérablement le code boilerplate par rapport à l'Options API.
<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 et defineEmits sont des macros du compilateur. Elles n'ont pas besoin d'être importées et ne sont disponibles que dans <script setup>. Tenter de les utiliser dans un bloc <script> normal sans setup générera une erreur de compilation.
État réactif avec ref et reactive
Vue 3 offre deux méthodes principales pour déclarer un état réactif. Choisir entre les deux est une source courante de confusion pour les débutants.
<script setup lang="ts">
import { ref, reactive } from 'vue'
// ref fonctionne avec les primitives et les objets
const count = ref(0)
const user = ref({ name: 'Ada', age: 36 })
// reactive fonctionne uniquement avec les objets/tableaux
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>
Une règle pratique : utilisez ref pour les primitives et les objets que vous pourriez réaffecter entièrement, et reactive pour les objets d'état groupés que vous modifiez sur place. Dans les modèles, les refs sont automatiquement déballées, donc vous écrivez {{ count }} au lieu de {{ count.value }}.
Composables pour la logique réutilisable
Les composables sont des fonctions qui encapsulent une logique réactive réutilisable. Ils suivent une convention de nommage useSomething. L'assistant IA de Cursor excelle dans la génération de composables à partir de descriptions en langage naturel.
// 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 }
}
Utilisation dans un composant :
<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>
Travailler avec l'extension Volar
Modèles vérifiés par typage
L'une des fonctionnalités les plus puissantes de Volar est la vérification des types dans le bloc <template>. Cela permet d'attraper les fautes de frappe dans les props des composants, les noms d'événements et les erreurs d'expression au moment de la compilation plutôt qu'à l'exécution.
<script setup lang="ts">
import Counter from './Counter.vue'
</script>
<template>
<!-- Volar signalera cela si la prop n'existe pas -->
<Counter title="Clicks" :count="5" @update="handleChange" />
</template>
Si Counter ne déclare pas de prop count, Volar affiche un soulignement rouge sous l'attribut et un message de diagnostic dans le panneau Problèmes.
Exécutez vue-tsc --noEmit dans le cadre de votre pipeline CI pour appliquer la vérification des types des modèles sur tout le projet. Ajoutez-le à vos scripts package.json :
{
"scripts": {
"type-check": "vue-tsc --noEmit"
}
}
Configuration de l'espace de travail
Créez un fichier .vscode/settings.json (partagé par Cursor) pour verrouiller les préférences Volar pour toute votre équipe :
{
"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"
}
Mode Take Over (TypeScript autonome)
Volar peut « prendre le contrôle » de l'extension TypeScript intégrée pour fournir un meilleur IntelliSense adapté à Vue sur les fichiers .ts et .vue. Dans un espace de travail, créez .vscode/settings.json avec :
{
"typescript.preferences.importModuleSpecifier": "relative",
"vue.server.includeLanguages": ["vue"]
}
Le mode Take Over désactive l'extension TS standard pour cet espace de travail. Si vous travaillez sur des projets mixtes contenant des bibliothèques TypeScript non-Vue, testez soigneusement pour vous assurer que la résolution des types externes fonctionne toujours comme prévu.
Gestion d'état avec Pinia
Pourquoi Pinia plutôt que Vuex
Pinia est la bibliothèque officielle de gestion d'état pour Vue 3. C'est le successeur de Vuex et offre plusieurs avantages :
- API plus simple et de type sécurisé sans mutations (vous modifiez l'état directement).
- Support TypeScript de premier ordre avec autocomplétion complète.
- Modularité — chaque store est défini indépendamment.
- Excellente intégration DevTools.
Définir un Store
// 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 }
})
Utiliser le Store dans les composants
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useCounterStore } from '../stores/counter'
const counter = useCounterStore()
// Déstructurer l'état réactif en toute sécurité
const { count, doubled } = storeToRefs(counter)
// Les actions peuvent être déstructurées directement
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>
Ne déstructurez jamais l'état du store avec un simple const { count } = counter — vous perdrez la réactivité. Utilisez toujours storeToRefs pour l'état et les getters, et déstructurez les actions directement car ce sont des fonctions simples.
Organiser plusieurs Stores
Pour les grandes applications, divisez les stores par domaine :
src/stores/
├── auth.ts
├── cart.ts
├── products.ts
└── ui.ts
Un modèle inter-store permet à un store d'en appeler un autre :
// 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 }
})
Routage avec Vue Router
Configuration des routes
// 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 et paramètres de route
<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>
Utilisez des composants chargés en différé (() => import(...)) pour les segments de route qui ne sont pas immédiatement nécessaires. Cela produit des bundles initiaux plus petits et un premier rendu plus rapide, ce qui est particulièrement important sur les réseaux mobiles.
Gardes de navigation
router.beforeEach((to, from) => {
const isAuthenticated = localStorage.getItem('token') !== null
if (to.meta.requiresAuth && !isAuthenticated) {
return { name: 'login', query: { redirect: to.fullPath } }
}
})
Appliquez le champ meta par route :
{
path: '/dashboard',
component: () => import('../views/DashboardView.vue'),
meta: { requiresAuth: true },
}
Génération de composants assistée par IA dans Cursor
Générer des SFC à partir de prompts
L'assistant IA de Cursor peut générer des Single File Components complets à partir d'une description en anglais simple. Ouvrez la palette de commandes (Ctrl+Shift+P) et choisissez Cursor: New Chat, ou utilisez Ctrl+K en ligne.
Exemple de 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 produit un fichier .vue échafaudé avec les trois blocs. Examinez la sortie et affinez itérativement — demandez-lui d'ajouter des squelettes de chargement, du tri ou des en-têtes collants selon les besoins.
Soyez précis sur la version de Vue et le style de syntaxe dans votre prompt. Spécifier "Vue 3 with <script setup lang="ts"> and Composition API" empêche le modèle de produire du code Options API ou des modèles Vue 2.
Refactoriser des composants existants
Cursor peut refactoriser d'anciens composants Options API en équivalents Composition API. Sélectionnez le composant, appuyez sur Ctrl+K, et saisissez :
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.
L'IA réécrit le fichier tout en préservant le comportement. Exécutez toujours votre suite de tests par la suite pour confirmer la parité.
Générer des tests avec l'IA
Associez les composants Vue à des tests Vitest générés par Cursor :
// 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])
})
})
Demandez à Cursor : "Generate Vitest unit tests for Counter.vue covering the increment behavior and empty-state rendering."
Débogage et profilage des applications Vue dans Cursor
Intégration de Vue DevTools
Installez l'extension de navigateur Vue.js devtools, ou utilisez l'application Electron autonome. Bien que Cursor lui-même n'héberge pas l'interface DevTools, l'extension Volar affiche les diagnostics des composants en ligne.
Pour déboguer l'état du store Pinia, l'onglet "Pinia" de Vue DevTools affiche chaque store, son état actuel et une chronologie des actions — inestimable pour traquer les bugs d'état périmé.
Source Maps et Vite
Vite génère des source maps pour le développement par défaut. Assurez-vous que votre vite.config.ts les garde activées :
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
sourcemap: true,
},
})
Livrer des source maps en production peut exposer votre code source original. Pour les builds de production, définissez sourcemap: 'hidden' ou utilisez un service de source maps hébergé, et ne commitez jamais de fichiers .map dans un dépôt public.
Profilage des performances
Utilisez l'onglet Performance de Chrome alongside Cursor. Le vite-plugin-vue-inspector (ou unplugin-vue-source) vous permet de cliquer sur n'importe quel élément dans le navigateur pour sauter directement à la ligne source dans Cursor — un gain de productivité massif pour naviguer dans de grandes bases de code.
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()],
})
Meilleures pratiques pour Vue.js dans Cursor
Conventions de structure de projet
Une disposition évolutive ressemble à ceci :
src/
├── assets/
├── components/
│ ├── common/
│ └── forms/
├── composables/
├── layouts/
├── router/
├── stores/
├── views/
├── App.vue
└── main.ts
Linting et formatage
Épinglez les versions d'ESLint et Prettier dans package.json pour que toute l'équipe partage des règles identiques :
{
"devDependencies": {
"eslint": "^9.0.0",
"eslint-plugin-vue": "^9.0.0",
"prettier": "^3.0.0",
"@vue/eslint-config-typescript": "^13.0.0"
}
}
Créez .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'] }],
},
}
Configurez Cursor pour corriger les erreurs de lint lors de la sauvegarde en ajoutant ceci à settings.json :
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
Raccourcis clavier pour le flux de travail Vue
Ctrl+K— édition/refactorisation IA en ligne.Ctrl+Shift+P→ "Cursor: New Chat" — ouvrir le chat IA pour la génération de composants.Alt+Clicksur une balise de composant — aller à la définition (propulsé par Volar).Ctrl+.— menu de correctif rapide pour les diagnostics Volar.
Pièges courants et comment les éviter
Perte de réactivité après déstructuration
L'erreur Vue 3 la plus courante est la déstructuration directe d'objets réactifs ou de refs :
// FAUX — perd la réactivité
const { count } = useCounterStore()
// CORRECT
const { count } = storeToRefs(useCounterStore())
Modification des Props
Les props sont en lecture seule. Si un enfant a besoin de changer une valeur, émettez un événement à la place :
<script setup lang="ts">
const props = defineProps<{ modelValue: string }>()
const emit = defineEmits<{ (e: 'update:modelValue', v: string): void }>()
// Utiliser un setter computed pour le passage v-model
import { computed } from 'vue'
const proxy = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val),
})
</script>
Oubli de :key dans v-for
Liez toujours un :key unique pour que Vue puisse suivre les nœuds efficacement :
<template>
<li v-for="item in items" :key="item.id">{{ item.label }}</li>
</template>
Utiliser l'index du tableau comme :key peut causer des bugs subtils lorsque la liste est réordonnée ou filtrée. Préférez un identifiant unique stable tel qu'un ID de base de données.
Résumé
Cursor offre aux développeurs Vue.js un espace de travail moderne et augmenté par l'IA qui s'intègre bien avec la chaîne d'outils Vue officielle. En combinant Volar pour la création de type sécurisé, Pinia pour une gestion d'état propre, Vue Router pour la navigation et l'IA de Cursor pour la génération et la refactorisation de composants, vous pouvez livrer des applications Vue 3 plus rapidement et avec moins de bugs. Commencez par échafauder un projet avec create-vue, verrouillez vos règles ESLint et de formatage, et laissez l'IA de Cursor gérer le scaffolding répétitif pendant que vous vous concentrez sur la logique produit et l'expérience utilisateur.