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

تطوير إطار عمل Astro في Cursor: دليل شامل

تطوير Astro في Cursor

Astro هو إطار عمل ويب حديث مصمم للمواقع التي تعتمد على المحتوى والتي لا ترسل أي JavaScript افتراضياً. قدّم Astro 4+ واجهة Content Layer المُحدثة، وأداءً أسرع لخادم التطوير، ودعماً رسمياً لـ View Transitions. يُعد Cursor، بأساسه المتوافق مع VS Code ومساعد الذكاء الاصطناعي المدمج، محرراً ممتازاً للعمل مع Astro -- فهو يفهم ملفات .astro، ويوفر IntelliSense لـ frontmatter وخصائص المكونات، ويمكنه إنشاء المكونات والمجموعات والتكاملات من أوامر لغة طبيعية.

يغطي هذا الدليل سير عمل تطوير Astro الكامل في Cursor: إعداد المشروع، مجموعات المحتوى، واجهة View Transitions API، معمارية الجزر، التكاملات، وإنشاء المكونات بمساعدة الذكاء الاصطناعي.

إعداد تطوير Astro في Cursor​

المتطلبات الأساسية​

يتطلب Astro 4+ إصدار Node.js 18.14.1 أو أحدث (يُوصى بـ Node 20 LTS). تحقق من التثبيت:

node --version
npm --version

إذا كنت بحاجة إلى إصدار أحدث، استخدم fnm أو nvm:

fnm install 20
fnm use 20
تلميح

الطرفية المدمجة في Cursor (Ctrl+`) تحافظ على مزامنة دليل العمل الحالي مع لوحة Explorer، لذا يمكنك إنشاء مشروع وفتح الملفات المُنشأة فوراً دون تبديل السياق.

تثبيت أدوات لغة Astro​

يعتمد Cursor على إضافة Astro الرسمية لدعم اللغة. ثبّتها من عرض الإضافات (Ctrl+Shift+X):

  1. ابحث عن "Astro".
  2. ثبّت الإضافة التي نشرها فريق Astro.
  3. أعد تحميل Cursor إذا طُلب منك ذلك.

توفر الإضافة:

  • تمييز الصياغة لملفات .astro.
  • التشخيصات وفحص الأنواع عبر @astrojs/language-server.
  • التنسيق عبر Prettier باستخدام حزمة prettier-plugin-astro.
  • IntelliSense لاستيراد المكونات والخصائص وتعبيرات frontmatter.
warning

إذا قمت بتثبيت إضافة Astro مجتمعية سابقاً، عطّلها قبل تثبيت الرسمية. الإضافات المتعارضة تسبب تشخيصات مكررة وتنسيقاً غير موثوق.

إنشاء مشروع Astro​

استخدم أداة create-astro الرسمية لإنشاء مشروع جديد:

# Create a new project with the minimal template
npm create astro@latest my-astro-site -- --template minimal --no-install --no-git --typescript strict

cd my-astro-site
npm install

افتح مجلد المشروع في Cursor:

cursor .

هيكل المشروع الافتراضي يبدو كالتالي:

my-astro-site/
├── src/
│ ├── components/
│ ├── layouts/
│ │ └── Layout.astro
│ ├── pages/
│ │ └── index.astro
│ └── styles/
│ └── global.css
├── public/
├── astro.config.mjs
├── tsconfig.json
└── package.json
تلميح

اطلب من Cursor إنشاء مشروع كامل لك: "Create an Astro 4 project with TypeScript, Tailwind CSS, and MDX support." سيقوم Cursor بإنشاء ملفات التكوين وتثبيت التبعيات في خطوة واحدة.

العمل مع مجموعات المحتوى​

مجموعات المحتوى هي طريقة Astro الآمنة نوعياً لإدارة المحتوى المحلي مثل منشورات المدونة والتوثيق وقوائم المنتجات. توفر واجهة Content Layer المُقدمة في Astro 4 واجهة موحدة للملفات المحلية وواجهات API الخارجية وتكاملات CMS.

تعريف مجموعة​

أنشئ مخطط مجموعة في src/content/config.ts:

import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: ({ image }) =>
z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
author: z.string().default('Anonymous'),
tags: z.array(z.string()).default([]),
cover: image().optional(),
draft: z.boolean().default(false),
}),
});

const docs = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/docs' }),
schema: z.object({
title: z.string(),
order: z.number(),
section: z.string(),
}),
});

export const collections = { blog, docs };
تلميح

اطلب من Cursor: "Generate a content collection schema for a product catalog with name, price, description, images array, and category enum." يفهم Cursor مكتبة Zod وسينتج مخططاً صالحاً مع المدققين المناسبين.

كتابة إدخالات المحتوى​

أنشئ ملفات Markdown في دليل المجموعة:

---
title: "Getting Started with Astro 4"
description: "Learn the new Content Layer API and View Transitions in Astro 4."
pubDate: 2024-06-15
author: "Jane Doe"
tags: ["astro", "tutorial"]
cover: "../../assets/blog/astro-cover.jpg"
---

Astro 4 brings a faster dev server, improved Content Layer API,
and native View Transitions support.

الاستعلام عن المجموعات في الصفحات​

استخدم getCollection لجلب الإدخالات مع أمان كامل للأنواع:

---
// src/pages/blog/index.astro
import { getCollection } from 'astro:content';
import Layout from '../../layouts/Layout.astro';

const posts = (await getCollection('blog'))
.filter((post) => !post.data.draft)
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
---

<Layout title="Blog">
<main>
<h1>Blog</h1>
<ul>
{posts.map((post) => (
<li>
<a href={`/blog/${post.id}/`}>
<time datetime={post.data.pubDate.toISOString()}>
{post.data.pubDate.toLocaleDateString('en-US')}
</time>
{post.data.title}
</a>
</li>
))}
</ul>
</main>
</Layout>
warning

استخدم دائماً post.id (وليس post.slug) عند بناء عناوين URL باستخدام Content Layer API. يختلف سلوك حقل slug بين Astro 3 و Astro 4 -- id هو المعرف المستقر والفريد في Astro 4+.

صفحات المحتوى الديناميكية​

أنشئ صفحات فردية لكل إدخال في المجموعة:

---
// src/pages/blog/[...id].astro
import { getCollection, render } from 'astro:content';
import Layout from '../../layouts/Layout.astro';

export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { id: post.id },
props: { post },
}));
}

const { post } = Astro.props;
const { Content } = await render(post);
---

<Layout title={post.data.title}>
<article>
<header>
<h1>{post.data.title}</h1>
<p>By {post.data.author}</p>
</header>
<Content />
</article>
</Layout>

واجهة View Transitions API​

مكوّن <ClientRouter /> في Astro (المعروف سابقاً بـ <ViewTransitions />) يُفعّل View Transitions الأصلية للمتصفح للتنقل من جانب العميل دون الحاجة إلى إطار عمل SPA كامل.

تفعيل View Transitions​

أضف المكوّن إلى التخطيط الأساسي:

---
// src/layouts/Layout.astro
import { ClientRouter } from 'astro:transitions';

interface Props {
title: string;
}

const { title } = Astro.props;
---

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{title}</title>
<ClientRouter />
</head>
<body>
<slot />
</body>
</html>

تحريك انتقالات الصفحة​

استخدم view-transition-name في CSS لتعريف أهداف الانتقال المسماة:

/* src/styles/global.css */
::view-transition-old(root) {
animation: fade-out 0.3s ease;
}

::view-transition-new(root) {
animation: fade-in 0.3s ease;
}

@keyframes fade-out {
to { opacity: 0; }
}

@keyframes fade-in {
from { opacity: 0; }
}

/* Named transition for a hero image */
.hero-image {
view-transition-name: hero-image;
}

::view-transition-old(hero-image) {
animation: scale-down 0.4s ease;
}

::view-transition-new(hero-image) {
animation: scale-up 0.4s ease;
}
تلميح

اطلب من Cursor: "Add View Transitions to my Astro site with a slide-in effect for navigation and a cross-fade for content." سيقوم Cursor بإنشاء إطارات CSS الرئيسية وشرح كيفية تحديدها لعناصر معينة باستخدام view-transition-name.

أحداث دورة الحياة​

استمع لأحداث الانتقال في البرامج النصية من جانب العميل:

<script>
document.addEventListener('astro:page-load', () => {
console.log('New page loaded after transition');
initAnalytics();
});

document.addEventListener('astro:before-swap', (event) => {
// Modify the new document before it swaps in
const newDoc = event.newDocument;
const theme = localStorage.getItem('theme') ?? 'light';
newDoc.documentElement.dataset.theme = theme;
});

document.addEventListener('astro:after-swap', () => {
console.log('DOM swapped, scripts re-executed');
});
</script>
warning

تتم معالجة البرامج النصية من جانب العميل في ملفات .astro بواسطة مجمع Astro. إذا كنت بحاجة إلى برنامج نصي يعمل عند كل تنقل مع View Transitions، استمع لحدث astro:page-load بدلاً من الاعتماد على الكود ذي المستوى الأعلى، الذي ينفذ عند التحميل الأول فقط.

معمارية الجزر​

تتيح لك معمارية الجزر في Astro تضمين مكونات تفاعلية (React، Vue، Svelte، Solid، إلخ) داخل HTML ثابت. فقط مكونات الجزر ترسل JavaScript -- بقية الصفحة تبقى ثابتة.

إضافة تكامل إطار عمل واجهة​

ثبّت تكامل React:

npx astro add react

يُعدّل هذا الأمر astro.config.mjs تلقائياً:

import { defineConfig } from 'astro/config';
import react from '@astrojs/react';

export default defineConfig({
integrations: [react()],
});

إنشاء جزيرة تفاعلية​

أنشئ مكون React:

// src/components/Counter.tsx
import { useState } from 'react';

interface CounterProps {
initialCount?: number;
step?: number;
}

export default function Counter({ initialCount = 0, step = 1 }: CounterProps) {
const [count, setCount] = useState(initialCount);

return (
<div className="counter">
<button onClick={() => setCount((c) => c - step)}>-</button>
<span>{count}</span>
<button onClick={() => setCount((c) => c + step)}>+</button>
</div>
);
}

استخدم توجيه client: في صفحة Astro لترطيب الجزيرة:

---
// src/pages/index.astro
import Layout from '../layouts/Layout.astro';
import Counter from '../components/Counter.tsx';
---

<Layout title="Home">
<h1>Welcome</h1>

<!-- Hydrates on page load -->
<Counter client:load initialCount={0} step={2} />

<!-- Hydrates when visible in viewport -->
<Counter client:visible initialCount={10} />

<!-- Hydrates on idle -->
<Counter client:idle initialCount={5} />

<!-- Hydrates on media query match -->
<Counter client:media="(max-width: 768px)" initialCount={0} />

<!-- No hydration -- server-rendered only -->
<Counter initialCount={100} />
</Layout>
تلميح

اطلب من Cursor: "Create a React island for a newsletter signup form with email validation, and render it as client:visible in my Astro layout." سيقوم Cursor بإنشاء المكون ومعالجة حالة النموذج وإضافة التحقق وربطه بملف التخطيط.

اختيار توجيه الترطيب المناسب​

التوجيهمتى يُستخدم
client:loadتفاعلية مطلوبة فوراً (تنقل، بحث)
client:idleعناصر واجهة ذات أولوية منخفضة تُحمّل وقت فراغ المتصفح
client:visibleعناصر واجهة أسفل الصفحة تُرطب عند التمرير إلى عرضها
client:mediaمكونات يجب أن تُحمّل فقط على أحجام شاشات معينة
client:onlyتخطي العرض من جانب الخادم بالكامل (مفيد لواجهات API للمتصفح فقط)
warning

استخدم client:only بحذر. المكونات المُعرضة بهذا التوجيه تتخطى العرض من جانب الخادم، مما يعني أنها لن تظهر في HTML الأولي. هذا يضر بـ SEO ويسبب إزاحة في التخطيط. استخدمه فقط للمكونات التي تعتمد على واجهات API للمتصفح فقط مثل window أو localStorage عند العرض الأول.

التكاملات والمنظومة​

توسع تكاملات Astro الإطار بقدرات إضافية. يمكن لذكاء Cursor الاصطناعي مساعدتك في تكوين التكاملات واستكشاف أخطائها وإصلاحها بسرعة.

تكامل Tailwind CSS​

npx astro add tailwind

يثبّت هذا @tailwindcss/vite ويُكوّن إضافة Vite. أنشئ ملف CSS مع استيراد Tailwind:

/* src/styles/global.css */
@import "tailwindcss";

استورد ورقة الأنماط في تخطيطك:

---
// src/layouts/Layout.astro
import '../styles/global.css';
---
تلميح

اطلب من Cursor: "Set up Tailwind CSS v4 with my Astro project and create a responsive navigation bar component." سيقوم Cursor بتكوين إضافة Vite وإنشاء مدخل CSS وبناء شريط تنقل متجاوب مع فئات الأدوات.

تكامل MDX​

npx astro add mdx

استخدم ملفات .mdx في مجموعات المحتوى لتضمين مكونات تفاعلية داخل Markdown:

---
title: "Interactive Blog Post"
description: "A post with embedded React components."
pubDate: 2024-06-20
---

import Counter from '../components/Counter.tsx';

This is a paragraph in MDX.

<Counter client:visible initialCount={0} />

More content after the island.

تكاملات Sitemap و RSS​

npx astro add sitemap
npx astro add rss

كوّنها في astro.config.mjs:

import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
import mdx from '@astrojs/mdx';

export default defineConfig({
site: 'https://example.com',
integrations: [mdx(), sitemap()],
});

أنشئ موجز RSS في نقطة نهاية مستقلة:

// src/pages/rss.xml.ts
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';

export async function GET(context) {
const posts = await getCollection('blog');
return rss({
title: 'My Astro Blog',
description: 'Latest posts',
site: context.site,
items: posts
.filter((post) => !post.data.draft)
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())
.map((post) => ({
title: post.data.title,
description: post.data.description,
pubDate: post.data.pubDate,
link: `/blog/${post.id}/`,
})),
customData: '<language>en-us</language>',
});
}

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

يتفوق مساعد الذكاء الاصطناعي في Cursor في إنشاء مكونات Astro والتخطيطات ومخططات المجموعات من أوصاف اللغة الطبيعية.

إنشاء المكونات من الأوامر​

افتح Cursor Chat (Ctrl+L) أو استخدم التحرير المضمن (Ctrl+I) وصف ما تحتاجه:

Generate an Astro component for a responsive pricing table with three tiers:
Starter ($9), Pro ($29), and Enterprise ($99). Include a "Popular" badge on
the Pro tier, feature lists with checkmarks, and CTA buttons. Use Tailwind
classes and accept props for the tier data.

سينتج Cursor مكوناً كاملاً ومُنمقاً ومُحدد الأنواع:

---
// src/components/PricingTable.astro
interface PricingTier {
name: string;
price: number;
description: string;
features: string[];
popular?: boolean;
ctaText: string;
ctaLink: string;
}

interface Props {
tiers: PricingTier[];
}

const { tiers } = Astro.props;
---

<section class="py-12">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-5xl mx-auto">
{tiers.map((tier) => (
<div
class:list={[
'relative rounded-2xl border p-8',
tier.popular
? 'border-blue-500 shadow-xl scale-105'
: 'border-gray-200',
]}
>
{tier.popular && (
<span class="absolute -top-3 left-1/2 -translate-x-1/2 rounded-full bg-blue-500 px-4 py-1 text-sm text-white font-semibold">
Popular
</span>
)}
<h3 class="text-xl font-bold">{tier.name}</h3>
<p class="text-gray-500 text-sm mt-1">{tier.description}</p>
<p class="text-4xl font-bold mt-4">
${tier.price}<span class="text-base font-normal text-gray-500">/mo</span>
</p>
<ul class="mt-6 space-y-3">
{tier.features.map((feature) => (
<li class="flex items-center gap-2">
<svg class="w-5 h-5 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
{feature}
</li>
))}
</ul>
<a
href={tier.ctaLink}
class:list={[
'mt-8 block rounded-lg py-3 text-center font-semibold transition-colors',
tier.popular
? 'bg-blue-500 text-white hover:bg-blue-600'
: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
]}
>
{tier.ctaText}
</a>
</div>
))}
</div>
</section>
تلميح

عند إنشاء المكونات، أدرج واجهة الخصائص في أمرك. هذا يضمن أن ينتج Cursor خصائص مُحددة الأنواع يمكن إعادة استخدامها عبر الصفحات. مثلاً: "Create a Card component that accepts a title, description, href, and optional image prop."

إنشاء التخطيط بمساعدة الذكاء الاصطناعي​

اطلب من Cursor إنشاء تخطيط قابل لإعادة الاستخدام:

Create a base Astro layout with a sticky header containing a logo, navigation
links (Home, Blog, About, Contact), and a theme toggle button. Include a footer
with social links and copyright. Add View Transitions and a dark mode toggle
using a script that reads from localStorage.

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

يمكن لـ Cursor المساعدة في استكشاف أخطاء التكامل وإصلاحها. إذا لم تُطبّق فئات Tailwind، اسأل:

My Tailwind CSS v4 classes are not being applied in my Astro project.
Here is my astro.config.mjs and global.css. What is wrong?

سيحلل Cursor التكوين، ويتحقق من الأخطاء الشائعة (إضافة Vite مفقودة، مسارات استيراد غير صحيحة، تكوين المحتوى)، ويقترح الإصلاحات.

warning

عند استخدام ذكاء Cursor الاصطناعي لتعديل astro.config.mjs، راجع دائماً مصفوفة integrations المُنشأة. يجب أن تُدرج التكاملات بالترتيب الصحيح -- على سبيل المثال، يجب أن يأتي mdx() قبل sitemap() إذا كان يجب تضمين صفحات MDX في الخريطة.

البناء والنشر​

إنشاء المواقع الثابتة​

افتراضياً يُخرج Astro مخرجات ثابتة. ابنِ الموقع:

npm run build

تُحفظ المخرجات في dist/. معاينة بناء الإنتاج محلياً:

npm run preview

العرض من جانب الخادم (SSR)​

للمحتوى الديناميكي، فعّل وضع SSR:

// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
});

العرض الهجين​

يدعم Astro 4 العرض الهجين، مما يتيح لك خلط الصفحات الثابتة والمعروضة من جانب الخادم:

// astro.config.mjs
export default defineConfig({
output: 'hybrid',
});

حدد الصفحات الفردية كمعروضة من جانب الخادم باستخدام export const prerender = false;.

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

تحليل حجم الحزمة​

ثبّت محلل الحزمة:

npm install -D astro-bundle-analyzer

أضفه إلى تكاملاتك:

import bundleAnalyzer from 'astro-bundle-analyzer';

export default defineConfig({
integrations: [bundleAnalyzer()],
});
تلميح

اطلب من Cursor: "My Astro build is shipping too much JavaScript. Analyze my components and tell me which islands can be changed from client:load to client:visible or client:idle." سيراجع Cursor استخدام مكوناتك ويوصي بتحسينات توجيه الترطيب.

تحسين الصور​

استخدم مكوّن <Image> المدمج في Astro للتحسين التلقائي:

---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---

<Image
src={heroImage}
alt="Hero image"
width={1200}
height={600}
loading="eager"
formats={['avif', 'webp']}
quality={80}
/>
warning

تتطلب الصور البعيدة إدخال config.image.service أو إعداد img.config. إذا رأيت أخطاء بناء حول نطاقات الصور البعيدة، أضف النطاقات المسموح بها إلى astro.config.mjs تحت image.domains أو image.remotePatterns.

الخلاصة​

يجعل اقتران Astro 4+ مع Cursor بيئة تطوير قوية لبناء مواقع سريعة تعتمد على المحتوى. مزيج المخرجات بدون JavaScript افتراضياً، ومجموعات المحتوى الآمنة نوعياً، و View Transitions، ومعمارية الجزر يعني أنك تحصل على أداء ممتاز دون التضحية بتجربة المطور. يسرّع مساعد الذكاء الاصطناعي في Cursor كل خطوة -- من إنشاء الهيكل وتصميم المخطط إلى إنشاء المكونات واستكشاف أخطاء التكامل وإصلاحها. ابدأ بقالب بسيط، أضف مجموعات المحتوى لبياناتك المنظمة، أدخل الجزر التفاعلية فقط عند الحاجة، ودع Cursor يُنشئ الكود المتكرر لتركز على المحتوى والتصميم.