إنتقل إلى المحتوى الرئيسي

تطوير Vue.js في Cursor: دليل شامل

تطوير Vue.js في Cursor

أصبح Vue.js أحد أكثر أطر عمل JavaScript التقدمية شيوعًا لبناء واجهات المستخدم. مع إدخال Vue 3 لـ Composition API و<script setup> ونظام تفاعلية معاد كتابته، يحتاج المطورون إلى محرر يفهم منظومة Vue الحديثة بعمق. يجمع Cursor بين أساس متوافق مع VS Code ومساعدة ذكية من الدرجة الأولى، مما يجعله بيئة متميزة لتطوير Vue.js.

يأخذك هذا الدليل خلال إعداد سير عمل Vue.js منتج في Cursor، من هيكلة المشروع إلى إدارة الحالة والتوجيه وتوليد المكونات بمساعدة الذكاء الاصطناعي. سواء كنت تقوم بترحيل قاعدة شفرات Options API إلى Vue 3 أو بدء مشروع SFC (مكون ملف واحد) جديد، فإن التقنيات أدناه ستساعدك على التحرك بشكل أسرع مع الحفاظ على نظافة شفرتك وقابلية صيانتها.

إعداد بيئة Vue.js في Cursor​

المتطلبات الأساسية وإعداد Node.js​

قبل كتابة أي شفرة Vue، تأكد من أن نظامك يمتلك الأسس الصحيحة. يرث Cursor تثبيت Node.js على جهازك، لذا تحقق من إصدارك أولًا.

node --version
npm --version

يتطلب Vue 3 وسلسلة أدوات Volar إصدار Node.js 18 أو أحدث. إذا كنت تستخدم إصدارًا أقدم، استخدم مدير إصدارات مثل nvm أو fnm للترقية:

# باستخدام fnm (موصى به للسرعة)
fnm install 20
fnm use 20

# باستخدام nvm
nvm install 20
nvm use 20
تلميح

يدعم الطرفية المدمجة في Cursor جميع أدوات الصدفة الشائعة. يمكنك فتحها باستخدام Ctrl+` (Windows/Linux) أو Cmd+` (macOS) وتشغيل أي أمر CLI دون مغادرة المحرر.

تثبيت إضافة Volar​

أهم إضافة لتطوير Vue.js في Cursor هي Volar (دعم لغة Vue.js الرسمي، الموزع الآن باسم إضافة Vue - Official). توفر فحص الأنواع وIntelliSense والتنسيق والتشخيصات لملفات .vue.

لتثبيتها:

  1. افتح عرض Extensions في Cursor باستخدام Ctrl+Shift+X (أو Cmd+Shift+X على macOS).
  2. ابحث عن "Vue - Official".
  3. انقر على Install.
warning

تجنب إبكان إضافة Vetur القديمة مفعّلة جنبًا إلى جنب مع Volar. صُممت Vetur لـ Vue 2 وتتعارض مع سلسلة الأدوات الحديثة. إذا كانت مثبتة لديك، عطّلها أو أزلها لمنع التشخيصات المكررة واقتراحات IntelliSense غير الصحيحة.

اختياريًا، ثبّت هذه الإضافات المكملة لإكمال سير عملك:

  • ESLint — لتنسيق ملفات .vue و.js/.ts.
  • Prettier — لتنسيق متسق.
  • TypeScript Vue Plugin (Volar) — يحسّن دقة الأنواع داخل القوالب.

هيكلة مشروع Vue 3 جديد​

الطريقة الموصى بها لإنشاء مشروع Vue جديد هي استخدام أداة create-vue الرسمية للهيكلة، التي تديرها فريق Vue الأساسي وتدمج Vite وTypeScript وRouter وPinia اختياريًا.

npm create vue@latest my-vue-app

تتيح لك المطالبة التفاعلية اختيار الميزات:

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

بعد الهيكلة، افتح المشروع في Cursor:

cd my-vue-app
cursor .

ثبّت التبعيات وابدأ خادم التطوير:

npm install
npm run dev
تلميح

يتعرّف Cursor تلقائيًا على خادم تطوير Vite. عندما تشغّل npm run dev، تعرض طرفية Cursor عنوان URL المحلي (عادةً http://localhost:5173). يمكنك Ctrl+Click على عنوان URL لفتح التطبيق قيد التشغيل في متصفحك الافتراضي.

إتقان Vue 3 Composition API​

فهم صياغة <script setup>​

صياغة <script setup> هي الطريقة الموصى بها لتأليف مكونات Vue 3. إنها سكر نحوي في وقت الترجمة يقلل بشكل كبير من الشفرة المعيارية مقارنة بـ 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>
warning

defineProps وdefineEmits هما وحدات ماكرو للمترجم. لا تحتاج إلى استيرادهما، وهما متاحتان فقط داخل <script setup>. محاولة استخدامهما في كتلة <script> عادية بدون setup ستؤدي إلى خطأ في الترجمة.

الحالة التفاعلية باستخدام ref وreactive​

يقدم Vue 3 طريقتين رئيسيتين للإعلان عن الحالة التفاعلية. الاختيار بينهما مصدر شائع للارتباك للمبتدئين.

<script setup lang="ts">
import { ref, reactive } from 'vue'

// ref يعمل مع الأنواع الأولية والكائنات
const count = ref(0)
const user = ref({ name: 'Ada', age: 36 })

// reactive يعمل فقط مع الكائنات/المصفوفات
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>
تلميح

قاعدة عملية: استخدم ref للأنواع الأولية وللكائنات التي قد تعيد تعيينها بالكامل، واستخدم reactive لكائنات الحالة المجمعة التي تعدّلها في مكانها. في القوالب، يتم فك المراجع تلقائيًا، لذا تكتب {{ count }} بدلًا من {{ count.value }}.

Composables للمنطق القابل لإعادة الاستخدام​

Composables هي دوال تغلف المنطق التفاعلي القابل لإعادة الاستخدام. تتبع اصطلاح تسمية useSomething. يتفوق مساعد Cursor الذكي في توليد composables من الأوصاف باللغة الطبيعية.

// 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 }
}

الاستخدام في مكوّن:

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

العمل مع إضافة Volar​

قوالب مع فحص الأنواع​

إحدى أقوى ميزات Volar هي فحص الأنواع داخل كتلة <template>. يلتقط هذا الأخطاء المطبعية في خصائص المكونات وأسماء الأحداث وأخطاء التعبيرات في وقت الترجمة بدلًا من وقت التشغيل.

<script setup lang="ts">
import Counter from './Counter.vue'
</script>

<template>
<!-- Volar سيضع علامة على هذا إذا لم تكن الخاصية موجودة -->
<Counter title="Clicks" :count="5" @update="handleChange" />
</template>

إذا لم يعلن Counter عن خاصية count، يعرض Volar خطًا متعرجًا أحمر تحت السمة ورسالة تشخيص في لوحة Problems.

تلميح

شغّل vue-tsc --noEmit كجزء من خط أنابيب CI لفرض فحص أنواع القوالب عبر المشروع بأكمله. أضفه إلى سكربتات package.json:

{
"scripts": {
"type-check": "vue-tsc --noEmit"
}
}

تكوين مساحة العمل​

أنشئ ملف .vscode/settings.json (مشترك بواسطة Cursor) لتثبيت تفضيلات Volar لفريقك بالكامل:

{
"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 (TypeScript مستقل)​

يمكن لـ Volar "الاستيلاء" على إضافة TypeScript المدمجة لتوفير IntelliSense أفضل مدرك لـ Vue عبر ملفات .ts و.vue على حد سواء. في مساحة عمل، أنشئ .vscode/settings.json بـ:

{
"typescript.preferences.importModuleSpecifier": "relative",
"vue.server.includeLanguages": ["vue"]
}
warning

يعطّل وضع Take Over إضافة TS القياسية لتلك مساحة العمل. إذا كنت تعمل في مشاريع مختلطة تحتوي على مكتبات TypeScript غير خاصة بـ Vue، اختبر بعناية لضمان أن دقة الأنواع الخارجية لا تزال تعمل كما هو متوقع.

إدارة الحالة باستخدام Pinia​

لماذا Pinia بدلًا من Vuex​

Pinia هي مكتبة إدارة الحالة الرسمية لـ Vue 3. إنها خليفة Vuex وتقدم عدة مزايا:

  • واجهة برمجية أبسط وآمنة للأنواع بدون طفرات (تعدّل الحالة مباشرة).
  • دعم من الدرجة الأولى لـ TypeScript مع إكمال تلقائي كامل.
  • نمطية — يُعرّف كل متجر بشكل مستقل.
  • تكامل ممتاز مع DevTools.

تعريف متجر​

// 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 }
})

استخدام المتجر في المكونات​

<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useCounterStore } from '../stores/counter'

const counter = useCounterStore()

// تفكيك الحالة التفاعلية بأمان
const { count, doubled } = storeToRefs(counter)
// يمكن تفكيك الإجراءات مباشرة
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>
warning

لا تفكّك حالة المتجر أبدًا باستخدام const { count } = counter العادية — ستفقد التفاعلية. استخدم دائمًا storeToRefs للحالة والـ getters، وفكّك الإجراءات مباشرة لأنها دوال عادية.

تنظيم متاجر متعددة​

للتطبيقات الأكبر، قسّم المتاجر حسب النطاق:

src/stores/
├── auth.ts
├── cart.ts
├── products.ts
└── ui.ts

نمط المتاجر المتقاطعة يتيح لمتجر استدعاء آخر:

// 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 }
})

التوجيه باستخدام Vue Router​

تكوين المسارات​

// 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>
تلميح

استخدم مكونات محمّلة بشكل كسول (() => import(...)) لمقاطع المسار غير المطلوبة فورًا. ينتج عن هذا حزم أولية أصغر ورسم أول أسرع، وهو أمر مهم بشكل خاص على شبكات الهاتف المحمول.

حراس التنقل​

router.beforeEach((to, from) => {
const isAuthenticated = localStorage.getItem('token') !== null
if (to.meta.requiresAuth && !isAuthenticated) {
return { name: 'login', query: { redirect: to.fullPath } }
}
})

طبّق حقل meta لكل مسار:

{
path: '/dashboard',
component: () => import('../views/DashboardView.vue'),
meta: { requiresAuth: true },
}

توليد المكونات بمساعدة الذكاء الاصطناعي في Cursor​

توليد SFCs من المطالبات​

يمكن لمساعد Cursor الذكي توليد مكونات ملف واحد كاملة من وصف باللغة الإنجليزية البسيطة. افتح لوحة الأوامر (Ctrl+Shift+P) واختر Cursor: New Chat، أو استخدم Ctrl+K مضمّنًا.

مثال على مطالبة:

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 ملف .vue مهيكل بجميع الكتل الثلاث. راجع المخرجات وحسّنها تكراريًا — اطلب منه إضافة هياكل تحميل أو فرز أو رؤوس ثابتة حسب الحاجة.

تلميح

كن محددًا بشأن إصدار Vue ونمط الصياغة في مطالبتك. تحديد "Vue 3 مع <script setup lang="ts"> وComposition API" يمنع النموذج من إصدار شفرات Options API أو أنماط Vue 2.

إعادة هيكلة المكونات الموجودة​

يمكن لـ Cursor إعادة هيكلة مكونات Options API القديمة إلى ما يعادلها بـ Composition API. حدد المكوّن، اضغط Ctrl+K، واطلب:

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.

يعيد الذكاء الاصطناعي كتابة الملف مع الحفاظ على السلوك. شغّل مجموعة الاختبارات دائمًا بعد ذلك للتأكد من التطابق.

توليد الاختبارات بالذكاء الاصطناعي​

اقران مكونات Vue باختبارات Vitest يولّدها 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])
})
})

اطلب من Cursor: "Generate Vitest unit tests for Counter.vue covering the increment behavior and empty-state rendering."

تصحيح الأخطاء وتحليل أداء تطبيقات Vue في Cursor​

تكامل Vue DevTools​

ثبّت إضافة متصفح Vue.js devtools، أو استخدم تطبيق Electron المستقل. بينما لا يستضيف Cursor نفسه واجهة DevTools، تعرض إضافة Volar تشخيصات المكونات مضمّنة.

لتصحيح حالة متجر Pinia، تعرض علامة تبويب "Pinia" في Vue DevTools كل متجر وحالته الحالية وخط زمني للإجراءات — لا تقدر بثمن لتتبع أخطاء الحالة القديمة.

خرائط المصدر وVite​

يولّد Vite خرائط مصدر للتطوير افتراضيًا. تأكد من أن vite.config.ts يبقيها مفعّلة:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
plugins: [vue()],
build: {
sourcemap: true,
},
})
warning

يمكن أن يؤدي شحن خرائط المصدر إلى الإنتاج إلى كشف شفرتك المصدرية الأصلية. لبناء الإنتاج، اضبط sourcemap: 'hidden' أو استخدم خدمة خرائط مصدر مستضافة، ولا تلتزم أبدًا بملفات .map في مستودع عام.

تحليل الأداء​

استخدم علامة تبويب Chrome Performance جنبًا إلى جنب مع Cursor. يتيح لك vite-plugin-vue-inspector (أو unplugin-vue-source) النقر على أي عنصر في المتصفح للقفز مباشرة إلى سطر المصدر في Cursor — تعزيز كبير للإنتاجية للتنقل في قواعد الشفرات الكبيرة.

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()],
})

أفضل الممارسات لـ Vue.js في Cursor​

اصطلاحات هيكل المشروع​

يبدو تخطيط قابل للتوسع هكذا:

src/
├── assets/
├── components/
│ ├── common/
│ └── forms/
├── composables/
├── layouts/
├── router/
├── stores/
├── views/
├── App.vue
└── main.ts

التنسيق والتنسيق التلقائي​

ثبّت إصدارات ESLint وPrettier في package.json ليتشارك الفريق بأكمله القواعد نفسها:

{
"devDependencies": {
"eslint": "^9.0.0",
"eslint-plugin-vue": "^9.0.0",
"prettier": "^3.0.0",
"@vue/eslint-config-typescript": "^13.0.0"
}
}

أنشئ .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'] }],
},
}
تلميح

تكوين Cursor لإصلاح أخطاء lint عند الحفظ بإضافة هذا إلى settings.json:

{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}

اختصارات لوحة المفاتيح لسير عمل Vue​

  • Ctrl+K — تحرير/إعادة هيكلة ذكي مضمّن.
  • Ctrl+Shift+P ← "Cursor: New Chat" — افتح الدردشة الذكية لتوليد المكونات.
  • Alt+Click على وسم مكوّن — انتقل إلى التعريف (مدعوم بـ Volar).
  • Ctrl+. — قائمة الإصلاح السريع لتشخيصات Volar.

الأخطاء الشائعة وكيفية تجنبها​

فقدان التفاعلية بعد التفكيك​

الخطأ الأكثر شيوعًا في Vue 3 هو تفكيك الكائنات التفاعلية أو المراجع مباشرة:

// خطأ — يفقد التفاعلية
const { count } = useCounterStore()

// صحيح
const { count } = storeToRefs(useCounterStore())

تعديل الخصائص​

الخصائص للقراءة فقط. إذا احتاج المكوّن الفردي إلى تغيير قيمة، أصدر حدثًا بدلًا من ذلك:

<script setup lang="ts">
const props = defineProps<{ modelValue: string }>()
const emit = defineEmits<{ (e: 'update:modelValue', v: string): void }>()

// استخدم setter محسوب لتمرير v-model
import { computed } from 'vue'
const proxy = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val),
})
</script>

نسيان :key في v-for​

اربط دائمًا :key فريدًا حتى يتمكن Vue من تتبع العقد بكفاءة:

<template>
<li v-for="item in items" :key="item.id">{{ item.label }}</li>
</template>
warning

استخدام فهرس المصفوفة كـ :key يمكن أن يسبب أخطاء خفية عند إعادة ترتيب القائمة أو تصفيتها. فضّل معرّفًا فريدًا ثابتًا مثل معرّف قاعدة البيانات.

الخلاصة​

يمنح Cursor مطوري Vue.js مساحة عمل حديثة ومعززة بالذكاء الاصطناعي تتوافق جيدًا مع سلسلة أدوات Vue الرسمية. من خلال الجمع بين Volar للتأليف الآمن للأنواع وPinia لإدارة الحالة النظيفة وVue Router للتنقل وذكاء Cursor لتوليد المكونات وإعادة الهيكلة، يمكنك شحن تطبيقات Vue 3 بشكل أسرع وبأخطاء أقل. ابدأ بهيكلة مشروع باستخدام create-vue، وثبّت قواعد ESLint والتنسيق، ودع ذكاء Cursor يتعامل مع الهيكلة المتكررة بينما تركز على منطق المنتج وتجربة المستخدم.