|
Getting your Trinity Audio player ready...
|
Next.js: الدليل الشامل لتطوير تطبيقات ويب احترافية وسريعة من الصفر في 2026
Next.js هو إطار العمل الأقوى لتطوير تطبيقات React الحديثة. تستخدمه Netflix, TikTok, Nike, Walmart، وآلاف الشركات الكبرى. في هذا الدليل الشامل، ستتعلم كيف تبني تطبيقات Next.js احترافية مع App Router، Server Components، SSR، SSG، و ISR، مع أمثلة عملية ومشاريع تطبيقية.
ما هو Next.js؟
Next.js هو إطار عمل (Framework) مفتوح المصدر مبني على React، طورته شركة Vercel. يضيف Next.js على React ميزات قوية مثل: Server-Side Rendering (SSR)، Static Site Generation (SSG)، Incremental Static Regeneration (ISR)، وAPI Routes.
💡 لماذا Next.js وليس React فقط؟
- SEO أفضل: SSR يجعل المحتوى قابلاً للفهرسة من محركات البحث
- سرعة فائقة: SSG و ISR يقللان وقت التحميل
- API Routes: Backend مدمج بدون الحاجة لخادم منفصل
- Image Optimization: تحسين الصور تلقائياً
- File-based Routing: التنقل عبر بنية الملفات
- Zero Config: إعدادات جاهزة من البداية
أنواع الرندر في Next.js
🎨 الأنواع الأربعة للرندر
- Static Site Generation (SSG):
- يتم بناؤه مرة واحدة عند البناء (build time)
- يُقدم كملفات HTML ثابتة
- الأسرع والأفضل لـ SEO
- مثالي للمدونات، صفحات المنتجات الثابتة
- Server-Side Rendering (SSR):
- يتم بناؤه في كل طلب على الخادم
- يُقدم HTML جاهز لكل مستخدم
- مثالي للمحتوى الديناميكي
- مثالي للوحات التحكم، صفحات المستخدم
- Incremental Static Regeneration (ISR):
- يبدأ كـ SSG، ثم يُعاد بناؤه دورياً
- أفضل من SSG للمحتوى المتغير
- يجمع بين السرعة والتحديث
- مثالي للمتاجر، الأخبار
- Client-Side Rendering (CSR):
- يُبنى في المتصفح باستخدام JavaScript
- مثل React العادي
- مثالي للتطبيقات التفاعلية
- أقل في SEO
⚖️ مقارنة بين أنواع الرندر
إعداد بيئة التطوير
🛠️ تثبيت Next.js
# إنشاء مشروع Next.js جديد npx create-next-app@latest my-next-app cd my-next-app # أثناء التثبيت، اختر: # ✔ Would you like to use TypeScript? ... Yes # ✔ Would you like to use ESLint? ... Yes # ✔ Would you like to use Tailwind CSS? ... Yes # ✔ Would you like to use `src/` directory? ... Yes # ✔ Would you like to use App Router? ... Yes # ✔ Would you like to customize the default import alias? ... No # تشغيل المشروع npm run dev # فتح المتصفح http://localhost:3000
📁 بنية المشروع
my-next-app/ ├── src/ │ ├── app/ # App Router │ │ ├── layout.tsx # Root Layout │ │ ├── page.tsx # Home Page (/) │ │ ├── about/ │ │ │ └── page.tsx # About Page (/about) │ │ ├── blog/ │ │ │ ├── page.tsx # Blog List (/blog) │ │ │ └── [slug]/ │ │ │ └── page.tsx # Dynamic Route (/blog/:slug) │ │ └── api/ │ │ └── hello/ │ │ └── route.ts # API Route (/api/hello) │ ├── components/ # Shared Components │ ├── lib/ # Utilities & Helpers │ └── styles/ # Global Styles ├── public/ # Static Assets ├── next.config.js # Next.js Config ├── package.json └── tsconfig.json
App Router: التنقل الحديث
🛣️ أساسيات App Router
App Router هو نظام التنقل الجديد في Next.js 13+. يعتمد على بنية الملفات لتحديد المسارات.
// src/app/layout.tsx - Root Layout import { Inter } from 'next/font/google'; import './globals.css'; const inter = Inter({ subsets: ['latin'] }); export const metadata = { title: 'موقعي | الصفحة الرئيسية', description: 'وصف الموقع لمحركات البحث', }; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="ar" dir="rtl"> <body className={inter.className}> <header> <nav> <a href="/">الرئيسية</a> <a href="/about">عن الموقع</a> <a href="/blog">المدونة</a> </nav> </header> <main>{children}</main> <footer> <p>© 2026 موقعي</p> </footer> </body> </html> ); } // src/app/page.tsx - Home Page export default function Home() { return ( <div> <h1>مرحباً بك في موقعي</h1> <p>هذا هو المحتوى الرئيسي للصفحة</p> </div> ); } // src/app/about/page.tsx - About Page export default function About() { return ( <div> <h1>عن الموقع</h1> <p>معلومات عن الموقع...</p> </div> ); }
🔗 المسارات الديناميكية (Dynamic Routes)
// src/app/blog/[slug]/page.tsx interface Post { id: number; title: string; content: string; author: string; } async function getPost(slug: string): Promise<Post> { const res = await fetch(`https://api.example.com/posts/${slug}`); return res.json(); } // Generate static paths at build time export async function generateStaticParams() { const posts = await fetch('https://api.example.com/posts') .then(res => res.json()); return posts.map((post: Post) => ({ slug: post.id.toString(), })); } export default async function BlogPost({ params, }: { params: { slug: string }; }) { const post = await getPost(params.slug); return ( <article> <h1>{post.title}</h1> <p>بقلم: {post.author}</p> <div dangerouslySetInnerHTML={{ __html: post.content }} /> </article> ); }
Server Components vs Client Components
⚖️ الفرق الجوهري
في Next.js 13+، جميع المكونات هي Server Components بشكل افتراضي. لاستخدام Client Components، يجب إضافة 'use client' في بداية الملف.
// Server Component (افتراضي) // يمكن الوصول إلى قواعد البيانات، APIs، الملفات // لا يمكن استخدام useState, useEffect, onClick async function ServerComponent() { // ✅ يمكن استخدام async/await const data = await fetch('https://api.example.com/data'); const posts = await data.json(); return ( <ul> {posts.map(post => ( <li key={post.id}>{post.title}</li> ))} </ul> ); } // Client Component 'use client'; import { useState } from 'react'; function ClientComponent() { // ✅ يمكن استخدام useState, useEffect, onClick const [count, setCount] = useState(0); return ( <button onClick={() => setCount(count + 1)}> Count: {count} </button> ); }
📊 مقارنة بين Server و Client Components
Data Fetching في Next.js
📡 طرق جلب البيانات
// 1. Static Data Fetching (SSG) // يُبنى مرة واحدة عند البناء async function StaticPage() { const data = await fetch('https://api.example.com/data'); const posts = await data.json(); return <PostsList posts={posts} />; } // 2. Dynamic Data Fetching (SSR) // يُبنى في كل طلب async function DynamicPage() { const data = await fetch('https://api.example.com/data', { cache: 'no-store', // تعطيل التخزين المؤقت }); const posts = await data.json(); return <PostsList posts={posts} />; } // 3. Incremental Static Regeneration (ISR) // يُبنى دورياً كل X ثانية async function ISRPage() { const data = await fetch('https://api.example.com/data', { next: { revalidate: 3600 }, // إعادة بناء كل ساعة }); const posts = await data.json(); return <PostsList posts={posts} />; }
API Routes: Backend مدمج
🔌 إنشاء API Routes
// src/app/api/posts/route.ts import { NextRequest, NextResponse } from 'next/server'; import { prisma } from '@/lib/prisma'; // GET /api/posts - Get all posts export async function GET() { try { const posts = await prisma.post.findMany({ orderBy: { createdAt: 'desc' }, }); return NextResponse.json(posts); } catch (error) { return NextResponse.json( { error: 'Failed to fetch posts' }, { status: 500 } ); } } // POST /api/posts - Create new post export async function POST(request: NextRequest) { try { const body = await request.json(); const { title, content, author } = body; const post = await prisma.post.create({ data: { title, content, author }, }); return NextResponse.json(post, { status: 201 }); } catch (error) { return NextResponse.json( { error: 'Failed to create post' }, { status: 500 } ); } } // src/app/api/posts/[id]/route.ts // GET /api/posts/:id - Get single post export async function GET( request: NextRequest, { params }: { params: { id: string } } ) { try { const post = await prisma.post.findUnique({ where: { id: parseInt(params.id) }, }); if (!post) { return NextResponse.json( { error: 'Post not found' }, { status: 404 } ); } return NextResponse.json(post); } catch (error) { return NextResponse.json( { error: 'Failed to fetch post' }, { status: 500 } ); } } // DELETE /api/posts/:id - Delete post export async function DELETE( request: NextRequest, { params }: { params: { id: string } } ) { try { await prisma.post.delete({ where: { id: parseInt(params.id) }, }); return NextResponse.json( { message: 'Post deleted successfully' }, { status: 200 } ); } catch (error) { return NextResponse.json( { error: 'Failed to delete post' }, { status: 500 } ); } }
التحسينات (Optimizations)
🖼️ Image Optimization
import Image from 'next/image'; function ImageExample() { return ( <Image src="/images/hero.jpg" alt="Hero Image" width={1200} height={600} priority={true} // تحميل فوري للأهم placeholder="blur" // تأثير blur أثناء التحميل quality={75} // جودة الصورة (1-100) sizes="(max-width: 768px) 100vw, 1200px" /> ); } // next.config.js - تكوين الصور module.exports = { images: { domains: ['images.example.com'], formats: ['image/avif', 'image/webp'], }, };
🔤 Font Optimization
// src/app/layout.tsx import { Inter, Tajawal } from 'next/font/google'; // تحميل الخطوط محلياً (أسرع) const inter = Inter({ subsets: ['latin'], display: 'swap', // منع FOIT }); const tajawal = Tajawal({ subsets: ['arabic'], weight: ['400', '500', '700'], display: 'swap', }); export default function RootLayout({ children }) { return ( <html lang="ar" dir="rtl" className={tajawal.className}> <body>{children}</body> </html> ); }
مشروع تطبيقي: مدونة كاملة
📝 هيكل المشروع
blog/ ├── src/ │ ├── app/ │ │ ├── layout.tsx │ │ ├── page.tsx # Home - Latest Posts │ │ ├── blog/ │ │ │ ├── page.tsx # All Posts (SSG) │ │ │ └── [slug]/ │ │ │ └── page.tsx # Single Post (ISR) │ │ ├── about/ │ │ │ └── page.tsx │ │ └── api/ │ │ └── posts/ │ │ └── route.ts │ ├── components/ │ │ ├── PostCard.tsx │ │ ├── Header.tsx │ │ └── Footer.tsx │ └── lib/ │ └── prisma.ts └── prisma/ └── schema.prisma
💻 الكود الكامل
// prisma/schema.prisma model Post { id Int @id @default(autoincrement()) title String slug String @unique content String author String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // src/lib/prisma.ts import { PrismaClient } from '@prisma/client'; const globalForPrisma = global as unknown as { prisma: PrismaClient }; export const prisma = globalForPrisma.prisma || new PrismaClient(); if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma; // src/app/blog/page.tsx - All Posts (SSG) import { prisma } from '@/lib/prisma'; import { PostCard } from '@/components/PostCard'; import Link from 'next/link'; export const metadata = { title: 'المدونة | جميع المقالات', description: 'جميع مقالات المدونة', }; export default async function BlogPage() { const posts = await prisma.post.findMany({ orderBy: { createdAt: 'desc' }, }); return ( <div className="container mx-auto px-4 py-8"> <h1 className="text-4xl font-bold mb-8">المدونة</h1> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> {posts.map(post => ( <PostCard key={post.id} post={post} /> ))} </div> </div> ); } // src/app/blog/[slug]/page.tsx - Single Post (ISR) import { prisma } from '@/lib/prisma'; import { notFound } from 'next/navigation'; export const revalidate = 3600; // ISR: إعادة بناء كل ساعة export async function generateStaticParams() { const posts = await prisma.post.findMany(); return posts.map(post => ({ slug: post.slug })); } export default async function PostPage({ params, }: { params: { slug: string }; }) { const post = await prisma.post.findUnique({ where: { slug: params.slug }, }); if (!post) notFound(); return ( <article className="container mx-auto px-4 py-8"> <h1 className="text-4xl font-bold mb-4">{post.title}</h1> <p className="text-gray-600 mb-8">بقلم: {post.author}</p> <div className="prose prose-lg" dangerouslySetInnerHTML={{ __html: post.content }} /> </article> ); } // src/components/PostCard.tsx import Link from 'next/link'; interface Post { id: number; title: string; slug: string; content: string; author: string; } export function PostCard({ post }: { post: Post }) { const excerpt = post.content.substring(0, 150) + '...'; return ( <div className="bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow"> <h2 className="text-2xl font-bold mb-2"> <Link href={`/blog/${post.slug}`} className="hover:text-blue-600"> {post.title} </Link> </h2> <p className="text-gray-600 mb-4">{excerpt}</p> <p className="text-sm text-gray-500">بقلم: {post.author}</p> </div> ); }
النشر على Vercel
🚀 خطوات النشر
# 1. تثبيت Vercel CLI npm i -g vercel # 2. الدخول إلى المجلد cd my-next-app # 3. النشر vercel # 4. اتبع التعليمات: # ? Set up and deploy "~/my-next-app"? [Y/n] y # ? Which scope do you want to deploy to? ... # ? Link to existing project? [y/N] n # ? What's your project's name? my-next-app # ? In which directory is your code located? ./ # ✅ Production: https://my-next-app.vercel.app # 5. للنشر على Production vercel --prod
⚙️ next.config.js
// next.config.js const nextConfig = { // React Strict Mode reactStrictMode: true, // Image Optimization images: { domains: ['images.example.com', 'cdn.example.com'], formats: ['image/avif', 'image/webp'], }, // Redirects async redirects() { return [ { source: '/old-page', destination: '/new-page', permanent: true, }, ]; }, // Rewrites async rewrites() { return [ { source: '/api/:path*', destination: 'https://api.example.com/:path*', }, ]; }, // Headers async headers() { return [ { source: '/:path*', headers: [ { key: 'X-Frame-Options', value: 'DENY', }, ], }, ]; }, }; module.exports = nextConfig;
أفضل الممارسات في Next.js
✅ أفضل الممارسات
- استخدم Server Components افتراضياً:
- أفضل للأداء وSEO
- استخدم Client Components فقط عند الحاجة
- استخدم ISR للمحتوى المتغير:
- أفضل من SSR للأداء
- يجمع بين السرعة والتحديث
- استخدم Image Component:
- تحسين تلقائي للصور
- Lazy loading افتراضي
- استخدم Font Optimization:
- next/font للخطوط
- تحميل محلي أسرع
- استخدم API Routes:
- Backend مدمج
- لا حاجة لخادم منفصل
❌ أخطاء شائعة
- ❌ استخدام Client Components كثيراً: يضر بالأداء
- ❌ عدم استخدام ISR: SSR بطيء للمحتوى المتغير
- ❌ استخدام img بدلاً من Image: فقدان التحسينات
- ❌ عدم استخدام next/font: خطوط بطيئة
- ❌ عدم استخدام API Routes: الحاجة لخادم منفصل
- ❌ عدم تحسين الصور: صور كبيرة تبطئ الموقع
- ❌ عدم استخدام Caching: تحميل متكرر للبيانات
- ❌ عدم استخدام Metadata API: SEO ضعيف
أدوات ومكتبات Next.js
🛠️ المكتبات الأساسية
موارد التعلم
📚 أفضل مصادر تعلم Next.js
- Next.js Official Docs:
- nextjs.org/docs
- التوثيق الرسمي الشامل
- أمثلة تفاعلية
- Vercel YouTube Channel:
- دروس فيديو رسمية
- Next.js Conf
- أمثلة عملية
- دورات مدفوعة:
- Udemy: Next.js 14 & React – Complete Guide
- Frontend Masters: Next.js
- Epic Web by Kent C. Dodds
- مشاريع مفتوحة المصدر:
- Vercel Templates
- Next.js Examples
- GitHub Projects
مؤسسة الصقر للتسويق الرقمي وخدمات Next.js
هل تريد بناء تطبيق Next.js احترافي؟ فريقنا المتخصص في مؤسسة الصقر يساعدك في تطوير تطبيقات ويب حديثة وسريعة باستخدام Next.js، مع أفضل الممارسات والأداء الفائق.
خبرتنا تمتد لأكثر من 10 سنوات في تطوير تطبيقات Next.js، وساعدنا مئات الشركات على بناء تطبيقات ويب احترافية وسريعة.
الخلاصة
Next.js هو إطار العمل الأقوى لتطوير تطبيقات React الحديثة. يجمع بين الأداء الفائق، SEO الممتاز، وسهولة التطوير.
القاعدة الذهبية: استخدم Server Components افتراضياً، ISR للمحتوى المتغير، Image Component للصور، و next/font للخطوط. هذه هي أفضل الممارسات للحصول على أفضل أداء.
تذكر: Next.js سهل التعلم لكن يحتاج ممارسة. ابنِ مشاريع حقيقية، اقرأ التوثيق الرسمي، وشارك في المجتمع.
سواء كنت مبتدئاً أو محترفاً، Next.js سيحدث فرقاً كبيراً في مشاريعك. ابدأ اليوم، وستحصد ثماراً استثنائية غداً.
الأسئلة الشائعة (FAQ)



