راهنمای جامع Next.js برای توسعه‌دهندگان React: از مبانی تا SSR و SSG

انتشار در ۱۹ فروردین ۱۴۰۵
نکست جی اس

آیا شما یک توسعه‌دهنده React هستید و به دنبال ارتقاء مهارت‌ها و پروژه‌های خود هستید؟ آیا می‌خواهید وب‌سایت‌هایی سریع‌تر، بهینه‌تر برای سئو و با قابلیت‌های پیشرفته بسازید؟ اگر پاسخ شما مثبت است، Next.js همان فریم‌ورکی است که به دنبال آن بوده‌اید. در این راهنمای جامع، ما شما را از مبانی Next.js گرفته تا تکنیک‌های پیچیده‌تر مانند Server-Side Rendering (SSR) و Static Site Generation (SSG) همراهی خواهیم کرد و نشان می‌دهیم چگونه می‌توانید از این فریم‌ورک قدرتمند برای جذب بازدیدکننده و مشتری بیشتر استفاده کنید.

Next.js چیست و چرا باید از آن استفاده کرد؟

وقتی صحبت از توسعه وب مدرن با React به میان می‌آید، Next.js به سرعت به عنوان یکی از محبوب‌ترین و کارآمدترین فریم‌ورک‌ها مطرح می‌شود. اما Next.js دقیقاً چیست و چرا باید آن را به ابزارهای دیگر ترجیح دهید، به‌خصوص اگر هدف شما ساخت وب‌سایت‌هایی است که هم از نظر فنی قوی باشند و هم در نتایج جستجو بدرخشند؟

Next.js چیست؟

Next.js یک فریم‌ورک متن‌باز مبتنی بر React است که توسط Vercel توسعه داده شده است. هدف اصلی آن، ساده‌سازی فرآیند ساخت اپلیکیشن‌های وب مدرن، به‌ویژه آن‌هایی است که نیاز به رندر سمت سرور (Server-Side Rendering – SSR) یا تولید سایت استاتیک (Static Site Generation – SSG) دارند. برخلاف Create React App که عمدتاً بر Client-Side Rendering (CSR) تمرکز دارد، Next.js به شما این امکان را می‌دهد که صفحات وب خود را هم در سمت سرور و هم در زمان بیلد (Build Time) تولید کنید. این قابلیت‌ها، Next.js را به گزینه‌ای ایده‌آل برای پروژه‌هایی تبدیل می‌کند که سئو (SEO) و عملکرد (Performance) در آن‌ها اولویت بالایی دارد.

چرا Next.js را انتخاب کنیم؟ مزایای کلیدی برای شما:

اگر به دنبال جذب بازدیدکننده بیشتر و تبدیل آن‌ها به مشتری هستید، انتخاب ابزار مناسب حیاتی است. Next.js مزایای قابل توجهی را ارائه می‌دهد که مستقیماً به این اهداف کمک می‌کند:

  • بهبود چشمگیر سئو (SEO):

موتورهای جستجو مانند گوگل، محتوایی را که به سرعت بارگذاری می‌شود و ساختار مشخصی دارد، ترجیح می‌دهند. با استفاده از SSR و SSG در Next.js، محتوای صفحات شما قبل از ارسال به مرورگر، توسط سرور آماده و کامل می‌شود. این امر باعث می‌شود ربات‌های جستجو به راحتی بتوانند تمام محتوای شما را ایندکس کنند، که نتیجه آن رتبه بهتر در نتایج جستجو و در نهایت افزایش بازدیدکنندگان ارگانیک است. این یک مزیت رقابتی بزرگ در دنیای دیجیتال امروز محسوب می‌شود.

  • عملکرد فوق‌العاده بالا (High Performance):

سرعت، یکی از مهم‌ترین عوامل در تجربه کاربری و همچنین سئو است. سایت‌هایی که کند هستند، نرخ پرش (Bounce Rate) بالاتری دارند و کاربران به سرعت آن‌ها را ترک می‌کنند. Next.js با ارائه روش‌هایی مانند رندر سمت سرور و تولید سایت استاتیک، سرعت بارگذاری اولیه صفحات را به شدت کاهش می‌دهد. علاوه بر این، قابلیت‌هایی مانند بهینه‌سازی خودکار تصاویر (Image Optimization) و Code Splitting (تقسیم کد به بخش‌های کوچک‌تر) تضمین می‌کنند که کاربران شما تجربه‌ای روان و سریع داشته باشند، که این خود منجر به رضایت بیشتر و افزایش احتمال تبدیل بازدیدکننده به مشتری می‌شود.

  • تجربه توسعه‌دهنده عالی (Excellent Developer Experience – DX):

یک توسعه‌دهنده خوشحال، پروژه‌های بهتری می‌سازد! Next.js با ویژگی‌هایی مانند Hot Code Reloading (مشاهده تغییرات کد به صورت آنی بدون نیاز به بارگذاری مجدد صفحه)، مسیریابی آسان مبتنی بر فایل سیستم و API های داخلی قدرتمند، فرآیند توسعه را لذت‌بخش‌تر و کارآمدتر می‌کند. این به معنای صرفه‌جویی در زمان و هزینه برای شما یا تیم توسعه‌دهنده‌تان است.

  • پشتیبانی بومی از TypeScript:

برای پروژه‌های بزرگ و پیچیده، استفاده از TypeScript به شدت توصیه می‌شود. Next.js از TypeScript به صورت داخلی پشتیبانی می‌کند و این امکان را به شما می‌دهد که کدهای پایدارتر، خواناتر و با باگ‌های کمتر بنویسید. این امر به ویژه در هنگام ساخت داشبوردهای پیچیده یا اپلیکیشن‌های سازمانی اهمیت پیدا می‌کند.

  • اکوسیستم قوی و جامعه فعال:

Next.js بخشی از اکوسیستم بزرگ React است و از پشتیبانی جامعه‌ای فعال و پرانرژی برخوردار است. این بدان معناست که منابع آموزشی فراوان، کتابخانه‌های جانبی متعدد و راه‌حل‌های سریع برای مشکلات احتمالی در دسترس شما هستند.

در ادامه این راهنما، عمیق‌تر به چگونگی استفاده از این ویژگی‌ها برای ساخت وب‌سایت‌های حرفه‌ای که هم از نظر فنی پیشرفته هستند و هم در جذب مخاطب و مشتری موفق عمل می‌کنند، خواهیم پرداخت.


شروع کار با Next.js: راه‌اندازی پروژه و آشنایی با ساختار آن

حالا که با مزایای Next.js آشنا شدیم، زمان آن رسیده که آستین‌ها را بالا بزنیم و اولین پروژه خود را راه‌اندازی کنیم. خبر خوب این است که Next.js فرآیند راه‌اندازی را بسیار ساده کرده است، به طوری که می‌توانید در عرض چند دقیقه یک پروژه React مدرن با قابلیت‌های SSR/SSG را در اختیار داشته باشید.

۱. راه‌اندازی سریع پروژه با create-next-app:

ساده‌ترین و بهترین راه برای شروع یک پروژه جدید Next.js، استفاده از ابزار رسمی create-next-app است. این ابزار یک پروژه پیش‌فرض با تمام پیکربندی‌های لازم را برای شما ایجاد می‌کند.

برای شروع، ترمینال یا خط فرمان خود را باز کنید و دستور زیر را اجرا کنید:

npx create-next-app@latest my-nextjs-app
  • npx: ابزاری که به شما امکان اجرای بسته‌های npm را بدون نیاز به نصب سراسری آن‌ها می‌دهد.
  • create-next-app@latest: آخرین نسخه از ابزار ایجاد پروژه Next.js.
  • my-nextjs-app: نام پوشه‌ای که پروژه شما در آن ایجاد خواهد شد. می‌توانید این نام را به دلخواه تغییر دهید.

پس از اجرای دستور، create-next-app از شما چند سوال خواهد پرسید تا پروژه را مطابق نیازتان پیکربندی کند:

  • Would you like to use TypeScript? (آیا می‌خواهید از TypeScript استفاده کنید؟) – توصیه شده: Yes (بله)
  • Would you like to use ESLint? (آیا می‌خواهید از ESLint استفاده کنید؟) – توصیه شده: Yes (بله) – برای بررسی کیفیت کد.
  • Would you like to use Tailwind CSS? (آیا می‌خواهید از Tailwind CSS استفاده کنید؟) – اختیاری: Yes یا No (بسته به ترجیح شما برای استایل‌دهی).
  • Would you like to use src/ directory? (آیا می‌خواهید از پوشه src/ استفاده کنید؟) – توصیه شده: Yes (بله) – برای سازماندهی بهتر کد.
  • Would you like to use App Router? (recommended) (آیا می‌خواهید از App Router استفاده کنید؟ – توصیه شده) – توصیه شده: Yes (بله) – App Router روش مدرن و پیشنهادی برای مسیریابی در Next.js است.
  • Would you like to customize the default import alias? (آیا می‌خواهید نام مستعار پیش‌فرض برای ایمپورت‌ها را سفارشی کنید؟) – معمولا: No (خیر) – مگر اینکه دلیل خاصی برای تغییر داشته باشید.

پس از پاسخ به سوالات، create-next-app وابستگی‌های لازم را نصب کرده و ساختار پروژه را ایجاد می‌کند.

۲. اجرای پروژه:

پس از اتمام نصب، وارد پوشه پروژه خود شوید:

cd my-nextjs-app

و سپس پروژه را اجرا کنید:

npm run dev

این دستور سرور توسعه (Development Server) را راه‌اندازی می‌کند. حالا می‌توانید با مراجعه به آدرس http://localhost:3000 در مرورگر خود، اپلیکیشن Next.js خود را مشاهده کنید. سرور توسعه به صورت خودکار تغییرات کد شما را تشخیص داده و صفحه را به‌روزرسانی می‌کند (Hot Reloading).

۳. آشنایی با ساختار پوشه‌ها و فایل‌های کلیدی (با App Router):

وقتی از App Router استفاده می‌کنید (که توصیه شده است)، ساختار پروژه کمی متفاوت از Pages Router قدیمی‌تر است، اما بسیار منطقی و قدرتمند است. پوشه اصلی شما (مثلاً my-nextjs-app) شامل موارد زیر خواهد بود (با فرض انتخاب پوشه src/):

  • src/app/: این پوشه قلب اپلیکیشن شماست و شامل تمام مسیرها (Routes)، صفحات (Pages) و کامپوننت‌های مرتبط با UI می‌شود.
  • layout.tsx (یا .jsx): این فایل یک Layout Root است که ساختار اصلی و مشترک برای تمام صفحات برنامه را تعریف می‌کند (مانند هدر، فوتر، نوار کناری). هر تغییری در اینجا در تمام صفحات اعمال می‌شود.
  • page.tsx (یا .jsx): این فایل نشان‌دهنده صفحه اصلی (Home Page) اپلیکیشن شماست (مسیر /). هر پوشه در app/ می‌تواند یک page.tsx داشته باشد که محتوای آن مسیر را تعریف می‌کند.
  • پوشه‌های دیگر (مثلاً dashboard/, about/): برای ایجاد مسیرهای جدید، کافی است پوشه‌هایی با نام مسیر مورد نظر خود در app/ ایجاد کنید. داخل هر پوشه، می‌توانید یک page.tsx برای تعریف محتوای آن صفحه و یک layout.tsx برای تعریف لی‌اوت خاص همان بخش ایجاد کنید.
  • loading.tsx: کامپوننتی که هنگام بارگذاری محتوای یک صفحه یا بخش نمایش داده می‌شود.
  • error.tsx: کامپوننتی که در صورت بروز خطا در نمایش یک بخش یا صفحه نشان داده می‌شود.
  • src/components/: (در صورت ایجاد) این پوشه برای نگهداری کامپوننت‌های React عمومی و قابل استفاده مجدد شما در بخش‌های مختلف برنامه است.
  • public/: این پوشه برای فایل‌های استاتیک مانند تصاویر، فونت‌ها و آیکون‌ها استفاده می‌شود. فایل‌های داخل این پوشه مستقیماً در ریشه دامنه شما قابل دسترسی هستند (مثلاً public/logo.png از طریق /logo.png قابل دسترسی است).
  • package.json: فایل اصلی پروژه که اطلاعات پروژه، اسکریپت‌ها (مانند dev, build, start) و وابستگی‌ها (Dependencies) را در خود نگهداری می‌کند.
  • next.config.js (یا .mjs): فایل پیکربندی Next.js که در آن می‌توانید تنظیمات مختلف فریم‌ورک را تغییر دهید، مانند پیکربندی تصاویر، تنظیمات redirect یا rewrites، و …
  • .eslintrc.json: پیکربندی ESLint برای بررسی کیفیت و استایل کد.
  • tsconfig.json: (در صورت استفاده از TypeScript) فایل پیکربندی TypeScript.

نکات مهم برای سئو و آینده پروژه:

  • ساختار پوشه‌ها: استفاده از پوشه src/ و app/ به سازماندهی بهتر پروژه کمک می‌کند و نگهداری و توسعه آن را آسان‌تر می‌سازد. این نظم به مرور زمان کیفیت کد و در نتیجه سئو را بهبود می‌بخشد.
  • App Router: این سیستم مسیریابی جدید، قابلیت‌های رندرینگ سمت سرور و استاتیک را به صورت بهینه‌تر و منعطف‌تری ارائه می‌دهد که مستقیماً بر سئو و سرعت تاثیرگذار است.
  • مسیریابی منطقی: با ایجاد مسیرهای واضح و معنی‌دار (مثلاً /services/web-design به جای /page?id=123)، هم کاربران و هم موتورهای جستجو درک بهتری از ساختار سایت شما خواهند داشت.

با این مقدمات، اکنون آماده هستیم تا به بخش‌های هیجان‌انگیزتر Next.js، یعنی روش‌های مختلف رندرینگ، بپردازیم.


مبانی رندرینگ در Next.js: SSR، SSG، ISR و CSR

یکی از قدرتمندترین ویژگی‌های Next.js، انعطاف‌پذیری آن در نحوه رندر کردن صفحات وب است. برخلاف فریم‌ورک‌های سنتی که فقط از یک روش رندرینگ (معمولاً CSR) پشتیبانی می‌کنند، Next.js به شما امکان می‌دهد بسته به نیاز هر صفحه، از روش‌های مختلفی استفاده کنید. این انتخاب هوشمندانه، تاثیر مستقیمی بر سئو، سرعت بارگذاری و تجربه کاربری دارد. بیایید با این مفاهیم کلیدی آشنا شویم:

Client-Side Rendering (CSR) – رندر سمت کلاینت:

این روش سنتی در اپلیکیشن‌های SPA (Single Page Application) با React است. در CSR، مرورگر ابتدا یک فایل HTML خالی و جاوا اسکریپت برنامه را دانلود می‌کند. سپس جاوا اسکریپت در مرورگر اجرا شده و محتوای صفحه را تولید و نمایش می‌دهد.

  • مزایا: تجربه کاربری روان پس از بارگذاری اولیه، مناسب برای داشبوردهای تعاملی.
  • معایب: بارگذاری اولیه کندتر، مشکل در ایندکس شدن توسط موتورهای جستجو (چون محتوا پس از اجرای جاوا اسکریپت تولید می‌شود).
  • نحوه استفاده در Next.js (App Router): به صورت پیش‌فرض، کامپوننت‌های React در App Router به صورت Server Components رندر می‌شوند. برای تبدیل یک کامپوننت به Client Component (که CSR انجام می‌دهد)، باید در بالای فایل آن 'use client'; را اضافه کنید.

Server-Side Rendering (SSR) – رندر سمت سرور:

در SSR، هر درخواست کاربر برای یک صفحه، باعث می‌شود سرور قبل از ارسال پاسخ به مرورگر، آن صفحه را تولید و آماده کند. این یعنی HTML کامل صفحه، همراه با داده‌های لازم، توسط سرور ساخته شده و به مرورگر ارسال می‌شود.

  • مزایا: بارگذاری اولیه سریع‌تر (کاربر بلافاصله محتوا را می‌بیند)، سئوی عالی (موتورهای جستجو به HTML کامل دسترسی دارند)، مناسب برای صفحات پویا و با محتوای متغیر (مانند صفحات محصول، اخبار).
  • معایب: بارگذاری مجدد صفحه برای هر درخواست (چون سرور باید دوباره صفحه را بسازد)، فشار بیشتر بر سرور.
  • نحوه استفاده در Next.js (App Router): کامپوننت‌ها به طور پیش‌فرض Server Components هستند. برای دریافت داده در SSR، از Async Server Components استفاده می‌کنیم. داده‌ها مستقیماً در کامپوننت Server fetch می‌شوند.

مثال (در App Router):

    // app/products/[id]/page.tsx
    async function getData(id) {
      const res = await fetch(`https://api.example.com/products/${id}`);
      if (!res.ok) {
        throw new Error('Failed to fetch data');
      }
      return res.json();
    }

    export default async function ProductPage({ params }) {
      const product = await getData(params.id); // داده‌ها در سمت سرور fetch می‌شوند

      return (
        <div>
          <h1>{product.name}</h1>
          <p>{product.description}</p>
          {/* ... سایر محتوا */}
        </div>
      );
    }

Static Site Generation (SSG) – تولید سایت استاتیک:

در SSG، صفحات وب در زمان بیلد (Build Time)، یعنی زمانی که اپلیکیشن را برای انتشار آماده می‌کنید، تولید می‌شوند. فایل‌های HTML نهایی ساخته شده و سپس به صورت استاتیک روی سرور قرار می‌گیرند. این روش سریع‌ترین حالت بارگذاری را ارائه می‌دهد.

  • مزایا: سریع‌ترین سرعت بارگذاری، امنیت بالا، قابلیت Caching عالی (CDN)، سئوی فوق‌العاده، فشار بسیار کم بر سرور. ایده‌آل برای محتوایی که به ندرت تغییر می‌کند (مانند صفحات درباره ما، تماس با ما، مستندات، پست‌های وبلاگ).
  • معایب: برای محتوای بسیار پویا و لحظه‌ای مناسب نیست (چون برای تغییر محتوا نیاز به بیلد مجدد است).
  • نحوه استفاده در Next.js (App Router): App Router به طور پیش‌فرض تلاش می‌کند تا حد امکان از SSG استفاده کند. کامپوننت‌هایی که هیچ داده‌ای را fetch نمی‌کنند یا داده‌هایشان در زمان بیلد قابل دسترس است، به صورت استاتیک تولید می‌شوند. برای fetch داده‌ها در زمان بیلد، از fetch با تنظیمات خاص یا کتابخانه‌های دیگر استفاده می‌شود.

Incremental Static Regeneration (ISR) – بازسازی استاتیک افزایشی:

ISR ترکیبی هوشمندانه از SSG و SSR است. صفحات با استفاده از SSG ساخته می‌شوند، اما Next.js به شما اجازه می‌دهد تا با تعیین یک بازه زمانی (مانند هر ۶۰ ثانیه)، صفحه را در پس‌زمینه بازسازی کنید. وقتی کاربر صفحه را درخواست می‌کند، اگر زمان بازسازی فرا رسیده باشد، Next.js صفحه را مجدداً تولید کرده و به کاربر نمایش می‌دهد.

  • مزایا: مزایای سرعت و سئوی SSG را حفظ می‌کند، در حالی که امکان به‌روزرسانی محتوا را بدون نیاز به بیلد مجدد فراهم می‌آورد. مناسب برای محتوایی که نسبتاً ثابت است اما نیاز به به‌روزرسانی دوره‌ای دارد (مانند لیست محصولات با قیمت‌های متغیر).
  • معایب: کمی پیچیده‌تر از SSG خالص.
  • نحوه استفاده در Next.js (App Router): از طریق آپشن next: { revalidate: <seconds> } در تابع fetch یا در توابع generateStaticParams (برای صفحات داینامیک) قابل پیاده‌سازی است.

مثال (با fetch):

    // app/page.tsx
    async function getData() {
      const res = await fetch('https://api.example.com/data', {
        cache: 'no-store' // معادل SSR در App Router
      });
      // یا برای ISR:
      // const res = await fetch('https://api.example.com/data', {
      //   next: { revalidate: 60 } // بازسازی هر ۶۰ ثانیه
      // });
      return res.json();
    }

    export default async function HomePage() {
      const data = await getData();
      return (
        <div>
          {/* ... نمایش محتوا */}
        </div>
      );
    }

انتخاب روش رندرینگ مناسب برای سئو و جذب مشتری:

  • صفحات اصلی وب‌سایت، صفحات دسته‌بندی، صفحات محصول، پست‌های وبلاگ: بهترین گزینه SSG یا ISR است. این صفحات معمولاً محتوای ثابت یا نیمه‌ثابت دارند و سرعت و سئوی آن‌ها حیاتی است.
  • داشبوردهای کاربری، صفحات پروفایل، سبد خرید: CSR (با استفاده از Client Components) یا SSR مناسب‌تر است، زیرا محتوا باید به صورت پویا و شخصی‌سازی شده برای هر کاربر نمایش داده شود.
  • صفحات با نیاز به به‌روزرسانی دوره‌ای: ISR بهترین راه‌حل است تا هم سرعت بالا بماند و هم محتوا به‌روز باشد.

درک این روش‌های رندرینگ کلید استفاده حداکثری از Next.js برای ساخت وب‌سایت‌هایی است که هم از نظر فنی بی‌نقص هستند و هم در جذب و نگه داشتن مخاطب موفق عمل می‌کنند.


پیاده‌سازی SSR و SSG در Next.js با مثال‌های عملی

درک نحوه پیاده‌سازی Server-Side Rendering (SSR) و Static Site Generation (SSG) در Next.js، به خصوص با ساختار جدید App Router، برای بهینه‌سازی سئو و عملکرد وب‌سایت شما حیاتی است. در این بخش، با مثال‌های کد، چگونگی استفاده از این روش‌ها را مشاهده خواهید کرد.

۱. رندرینگ سمت سرور Server-Side Rendering (SSR) با App Router

همانطور که پیشتر اشاره شد، در App Router، کامپوننت‌ها به طور پیش‌فرض Server Components هستند. این به این معنی است که اگر کامپوننتی نیازی به تعامل با کاربر (مانند event handlers یا state) نداشته باشد و صرفاً محتوا را نمایش دهد، به صورت پیش‌فرض در سمت سرور رندر می‌شود. برای دریافت داده‌ها در زمان درخواست (SSR)، ما از قابلیت async/await در Server Components استفاده می‌کنیم.

مثال: نمایش لیست محصولات با SSR

فرض کنید می‌خواهیم لیستی از محصولات را از یک API دریافت و نمایش دهیم. این لیست ممکن است دائماً تغییر کند، بنابراین SSR گزینه مناسبی است.

  • ایجاد یک کامپوننت Server Component:
    // app/products/page.tsx

    // تابعی برای fetch داده‌ها از API
    async function getProducts() {
      // استفاده از fetch API داخلی Next.js که به طور پیش‌فرض کش نمی‌کند (SSR)
      // برای اطمینان از SSR، می‌توانیم از 'no-store' استفاده کنیم:
      const res = await fetch('https://api.example.com/products', {
        cache: 'no-store', // این خط تضمین می‌کند که داده‌ها در هر درخواست از API گرفته شوند
        // alternatively, you can use:
        // next: { revalidate: 0 } // این هم مشابه no-store عمل می‌کند
      });

      if (!res.ok) {
        // اگر پاسخ با خطا همراه بود، خطا پرتاب می‌شود
        throw new Error('Failed to fetch products');
      }
      return res.json(); // تبدیل پاسخ به JSON
    }

    // کامپوننت اصلی صفحه که به صورت async تعریف شده است
    export default async function ProductsPage() {
      const products = await getProducts(); // منتظر می‌مانیم تا داده‌ها fetch شوند

      return (
        <div>
          <h1>لیست محصولات</h1>
          <ul>
            {products.map((product) => (
              <li key={product.id}>
                <h2>{product.name}</h2>
                <p>{product.price} تومان</p>
                {/* لینک به صفحه جزئیات محصول */}
                <a href={`/products/${product.id}`}>مشاهده جزئیات</a>
              </li>
            ))}
          </ul>
        </div>
      );
    }
  • مدیریت خطا:

برای مدیریت خطاهایی که ممکن است در حین fetch داده‌ها رخ دهد، می‌توانیم یک فایل error.tsx در همین پوشه app/products/ ایجاد کنیم:

    // app/products/error.tsx
    'use client'; // فایل خطا باید Client Component باشد

    import { useEffect } from 'react';

    export default function Error({
      error,
      reset,
    }: {
      error: Error;
      reset: () => void;
    }) {
      useEffect(() => {
        // Log the error to an error reporting service
        console.error(error);
      }, [error]);

      return (
        <div>
          <h2>مشکلی در بارگذاری محصولات رخ داد!</h2>
          <button
            onClick={
              // Attempt to recover by trying to re-render the products page
              () => reset()
            }
          >
            تلاش مجدد
          </button>
        </div>
      );
    }

۲. Static Site Generation (SSG) با App Router

SSG در App Router به طور پیش‌فرض زمانی اتفاق می‌افتد که کامپوننت‌ها داده‌های خود را در زمان بیلد fetch کنند یا اصلاً داده‌ای fetch نکنند. Next.js به طور هوشمند کامپوننت‌هایی که شرایط SSG را دارند، شناسایی و به صورت استاتیک تولید می‌کند.

مثال ۱: صفحه استاتیک ساده (بدون نیاز به داده خارجی)

صفحاتی مانند “درباره ما” یا “تماس با ما” که محتوای ثابتی دارند، به طور خودکار SSG می‌شوند.

// app/about/page.tsx

export default function AboutPage() {
  return (
    <div>
      <h1>درباره ما</h1>
      <p>این صفحه درباره شرکت ما اطلاعاتی ارائه می‌دهد...</p>
      {/* ... سایر محتوای ثابت */}
    </div>
  );
}

این کامپوننت به دلیل نداشتن fetch یا استفاده از async/await، به صورت استاتیک در زمان بیلد تولید می‌شود.

مثال ۲: صفحات داینامیک با SSG و generateStaticParams

برای صفحات داینامیک (مانند صفحات جزئیات محصول که ID محصول در URL مشخص است)، ما نیاز داریم Next.js بداند که چه پارامترهایی (مثلاً ID محصولات) را باید در زمان بیلد تولید کند. این کار با تابع generateStaticParams انجام می‌شود.

  • فایل صفحه جزئیات محصول:
    // app/products/[id]/page.tsx

    // تابعی برای fetch داده‌های یک محصول خاص بر اساس ID
    async function getProduct(id) {
      // در اینجا از fetch با cache: 'force-cache' (پیش‌فرض) استفاده می‌کنیم
      // یا می‌توانیم به صورت صریح بگوییم که این داده‌ها باید در زمان بیلد fetch شوند
      const res = await fetch(`https://api.example.com/products/${id}`, {
        next: { revalidate: 86400 } // مثال: ISR با بازسازی روزانه
        // برای SSG خالص: cache: 'force-cache' یا بدون هیچ آپشنی (پیش‌فرض)
      });

      if (!res.ok) {
        // اگر محصول پیدا نشد، خطا پرتاب می‌کنیم (که توسط error.tsx مدیریت می‌شود)
        throw new Error('Product not found');
      }
      return res.json();
    }

    // تابع برای تولید پارامترهای داینامیک در زمان بیلد
    export async function generateStaticParams() {
      // این تابع باید لیستی از پارامترها را برگرداند
      // معمولاً این لیست از یک API دریافت می‌شود که تمام ID ها را برمی‌گرداند
      const products = await fetch('https://api.example.com/products?fields=id').then((res) => res.json());

      // باید خروجی را به این فرمت تبدیل کنیم: [{ id: '1' }, { id: '2' }, ...]
      return products.map((product) => ({
        id: product.id.toString(), // مطمئن شوید که ID به صورت رشته است
      }));
    }

    // کامپوننت اصلی صفحه جزئیات محصول
    export default async function ProductDetailPage({ params }) {
      const product = await getProduct(params.id); // params.id از generateStaticParams می‌آید

      return (
        <div>
          <h1>{product.name}</h1>
          <p>{product.description}</p>
          <p>قیمت: {product.price} تومان</p>
        </div>
      );
    }

نکات کلیدی برای سئو و جذب مشتری:

  • SSR برای محتوای پویا: استفاده از SSR برای صفحاتی که نیاز به نمایش اطلاعات به‌روز و شخصی‌سازی شده دارند (مانند صفحه محصول با قیمت لحظه‌ای، وضعیت موجودی)، به موتورهای جستجو اجازه می‌دهد تا این اطلاعات را به درستی ایندکس کنند و کاربران همواره آخرین داده‌ها را ببینند.
  • SSG برای محتوای ثابت و نیمه‌ثابت: برای پست‌های وبلاگ، صفحات محصول، صفحات اطلاعاتی و …، SSG (یا ISR) بهترین گزینه است. سرعت بارگذاری فوق‌العاده بالا و قابلیت ایندکس شدن عالی توسط گوگل، مستقیماً به بهبود رتبه سئو و تجربه کاربری کمک می‌کند که منجر به جذب بیشتر مشتری می‌شود.
  • ISR به عنوان راه حل میانه: اگر محتوایی دارید که باید به طور منظم به‌روز شود (مثلاً لیست قیمت‌ها در یک فروشگاه)، ISR با تنظیم زمان revalidate مناسب، تعادل خوبی بین تازگی محتوا و عملکرد عالی ایجاد می‌کند.
  • مدیریت خطا: همیشه برای بخش‌هایی که داده‌ها را از API دریافت می‌کنند، مکانیزم مدیریت خطا (مانند error.tsx) در نظر بگیرید تا در صورت بروز مشکل، تجربه کاربری منفی ایجاد نشود.

با استفاده صحیح از این تکنیک‌ها، می‌توانید وب‌سایت‌هایی با عملکرد بالا، سئوی عالی و تجربه کاربری فوق‌العاده بسازید که در نهایت به جذب مشتریان بیشتر منجر خواهد شد.


بهینه‌سازی عملکرد و سئو در نکست جی اس

ساخت یک وب‌سایت با Next.js تنها شروع کار است. برای اینکه بتوانید حداکثر استفاده را از مزایای سئو و عملکرد این فریم‌ورک ببرید و مشتریان بیشتری جذب کنید، بهینه‌سازی مداوم ضروری است. در این بخش، به چند تکنیک کلیدی برای ارتقاء عملکرد و سئو در پروژه‌های Next.js می‌پردازیم.

۱. بهینه‌سازی تصاویر (Image Optimization)

تصاویر اغلب بزرگترین بخش حجم یک صفحه وب را تشکیل می‌دهند و می‌توانند تاثیر منفی شدیدی بر سرعت بارگذاری و در نتیجه سئو داشته باشند. Next.js با کامپوننت next/image راه حل قدرتمندی برای این مشکل ارائه می‌دهد.

ویژگی‌های کلیدی next/image:

  • تغییر اندازه خودکار (Automatic Resizing): تصویر بر اساس ابعاد نمایش داده شده در مرورگر، تغییر اندازه داده می‌شود.
  • بهینه‌سازی فرمت (Format Optimization): تصویر به طور خودکار به فرمت‌های مدرن و بهینه مانند WebP تبدیل می‌شود (اگر مرورگر پشتیبانی کند).
  • بارگذاری تنبل (Lazy Loading): تصاویر خارج از دید کاربر (Off-screen) تا زمانی که کاربر به آن‌ها اسکرول نکند، بارگذاری نمی‌شوند. این امر سرعت بارگذاری اولیه صفحه را به شدت افزایش می‌دهد.
  • جلوگیری از پرش محتوا (Layout Shift Prevention): با تعیین ابعاد width و height، فضای مورد نیاز تصویر از قبل رزرو می‌شود تا از پرش ناگهانی محتوا هنگام بارگذاری تصویر جلوگیری شود (CLS – Cumulative Layout Shift).
  • نحوه استفاده:
    import Image from 'next/image';

    // فرض کنید تصویر شما در پوشه public قرار دارد
    import myImage from '../public/my-image.jpg';

    function HomePage() {
      return (
        <div>
          <h1>صفحه اصلی</h1>
          <Image
            src={myImage} // مسیر تصویر (از پوشه public)
            alt="توضیح تصویر برای سئو و دسترس‌پذیری"
            width={500} // عرض تصویر در پیکسل
            height={300} // ارتفاع تصویر در پیکسل
            // priority // اگر تصویر در بخش بالای صفحه (Above the fold) است، priority را True قرار دهید تا زودتر بارگذاری شود
          />
          {/* ... سایر محتوا */}
        </div>
      );
    }

    export default HomePage;

۲. Code Splitting و Lazy Loading کامپوننت‌ها

Code Splitting به معنی تقسیم کد جاوا اسکریپت برنامه به قطعات کوچکتر است که فقط در صورت نیاز بارگذاری می‌شوند. این کار حجم اولیه دانلود را کاهش داده و سرعت بارگذاری را بهبود می‌بخشد. Next.js به طور خودکار برای صفحات (Page-based routing) این کار را انجام می‌دهد، اما برای کامپوننت‌های داخل یک صفحه نیز می‌توانید از آن بهره ببرید.

  • استفاده از next/dynamic:

با next/dynamic می‌توانید کامپوننت‌هایی که همیشه مورد نیاز نیستند را به صورت دینامیک و تنبل بارگذاری کنید.

    import dynamic from 'next/dynamic';

    // کامپوننت Modal که فقط در صورت نیاز بارگذاری می‌شود
    const DynamicModal = dynamic(() => import('../components/Modal'), {
      loading: () => <p>در حال بارگذاری...</p>, // نمایش یک پیغام هنگام بارگذاری
      ssr: false, // اگر کامپوننت فقط در مرورگر کار می‌کند (Client-side)، ssr را false قرار دهید
    });

    function MyComponent() {
      const [showModal, setShowModal] = React.useState(false);

      return (
        <div>
          <button onClick={() => setShowModal(true)}>نمایش مودال</button>
          {showModal && <DynamicModal />}
        </div>
      );
    }

    export default MyComponent;

۳. بهینه‌سازی فونت‌ها (Font Optimization)

فونت‌ها نیز می‌توانند بر سرعت بارگذاری تاثیر بگذارند. Next.js روش‌هایی برای بهینه‌سازی بارگذاری فونت‌ها ارائه می‌دهد:

  • استفاده از Google Fonts:

می‌توانید فونت‌های خود را از Google Fonts به صورت بهینه در next.config.js یا مستقیماً در layout.tsx (برای App Router) لینک دهید. Next.js سعی می‌کند این فونت‌ها را به صورت استاتیک (SSG) یا با استفاده از preconnect برای بارگذاری سریع‌تر، مدیریت کند.

    // app/layout.tsx
    import localFont from 'next/font/local'

    // Font files can be imported.
    const myFont = localFont({ src: '../public/fonts/my-font.woff2' })

    export default function RootLayout({
      children,
    }: {
      children: React.ReactNode
    }) {
      return (
        <html lang="fa" className={myFont.className}> {/* اعمال فونت */}
          <body>{children}</body>
        </html>
      )
    }
  • فونت‌های خود میزبان (Self-hosting Fonts):

برای کنترل بیشتر و جلوگیری از درخواست‌های خارجی، می‌توانید فونت‌های خود را دانلود کرده و در پوشه public قرار دهید و سپس با استفاده از localFont (برای App Router) یا لینک دادن مستقیم در HTML، آن‌ها را بارگذاری کنید. Next.js این فونت‌ها را در زمان بیلد بهینه‌سازی و ارائه می‌کند.

۴. متا تگ‌ها و سئوی On-Page

برای اینکه موتورهای جستجو محتوای شما را بهتر درک کنند و رتبه بهتری به آن بدهند، بهینه‌سازی متا تگ‌ها حیاتی است.

  • عنوان صفحه (Title) و توضیحات متا (Meta Description):

این تگ‌ها در <head> صفحه قرار می‌گیرند و در نتایج جستجو نمایش داده می‌شوند. در App Router، این کار به سادگی با استفاده از کامپوننت Metadata انجام می‌شود:

    // app/page.tsx
    import type { Metadata } from 'next';

    export const metadata: Metadata = {
      title: 'راهنمای جامع Next.js | سئو و جذب مشتری',
      description: 'با این راهنمای جامع، Next.js را برای توسعه وب‌سایت‌های سئو شده و جذب مشتری یاد بگیرید.',
      // ... سایر متا تگ‌ها مانند keywords, openGraph, etc.
    };

    export default function HomePage() {
      // ... محتوای صفحه
      return (
        <div>
          <h1>بهینه‌سازی Next.js</h1>
          {/* ... */}
        </div>
      );
    }
  • تگ‌های alt برای تصاویر:

همانطور که در بخش بهینه‌سازی تصویر دیدیم، استفاده از alt توصیفی و حاوی کلمات کلیدی مرتبط، به سئو کمک شایانی می‌کند.

  • ساختار صحیح هدینگ‌ها (H1, H2, H3, …):

استفاده منطقی از تگ‌های هدینگ به موتورهای جستجو کمک می‌کند تا ساختار و سلسله مراتب محتوای شما را درک کنند.

۵. استفاده از ابزارهای تحلیل عملکرد

برای سنجش میزان موفقیت بهینه‌سازی‌های خود، از ابزارهای زیر استفاده کنید:

  • Google PageSpeed Insights: عملکرد صفحه شما را در موبایل و دسکتاپ تحلیل کرده و پیشنهاداتی برای بهبود ارائه می‌دهد.
  • Lighthouse (در Chrome DevTools): ابزار داخلی مرورگر کروم که عملکرد، سئو، دسترس‌پذیری و PWA را بررسی می‌کند.
  • WebPageTest: یک ابزار آنلاین قدرتمند برای تست سرعت و عملکرد وب‌سایت از نقاط مختلف جهان.

چگونه این بهینه‌سازی‌ها به جذب مشتری کمک می‌کنند؟

  • سرعت بارگذاری بالا: کاربران امروزی صبور نیستند. وب‌سایت‌های کند منجر به نرخ پرش (Bounce Rate) بالا و از دست دادن مشتریان بالقوه می‌شوند.
  • رتبه بهتر در گوگل: موتورهای جستجو، وب‌سایت‌های سریع و با سئوی قوی را بالاتر نمایش می‌دهند. این یعنی دیده شدن بیشتر و ترافیک ارگانیک بالاتر.
  • تجربه کاربری بهتر: وب‌سایتی که سریع، روان و بدون مشکل (مانند پرش محتوا) است، تجربه خوشایندی را برای کاربر رقم می‌زند و احتمال تبدیل او به مشتری را افزایش می‌دهد.

مدیریت داده‌ها و API Routes در Next.js

یکی از قدرت‌های بزرگ Next.js، توانایی آن در ترکیب فریم‌ورک فرانت‌اند با قابلیت‌های بک‌اند سبک است. این امکان از طریق مدیریت داده‌ها و ساخت API Routes فراهم می‌شود که به شما اجازه می‌دهد منطق سمت سرور را مستقیماً در پروژه Next.js خود پیاده‌سازی کنید، بدون نیاز به راه‌اندازی یک سرور جداگانه.

۱. دریافت داده‌ها (Data Fetching) در App Router (H3)

همانطور که در بخش‌های قبلی اشاره شد، App Router رویکرد جدید و قدرتمندی برای مدیریت داده‌ها دارد. کامپوننت‌های سمت سرور (Server Components) به طور پیش‌فرض قادر به fetch کردن داده‌ها هستند.

  • fetch به صورت پیش‌فرض با Caching:

تابع fetch در App Router به صورت هوشمند عمل می‌کند. به طور پیش‌فرض، درخواست‌های fetch که URL یکسان دارند، Caching (کش) می‌شوند. این بدان معناست که اگر چندین کامپوننت یک داده را از یک URL مشابه درخواست کنند، فقط یک بار آن داده از سرور دریافت شده و نتیجه برای بقیه استفاده می‌شود.

  • کنترل Caching و Revalidation:

شما می‌توانید رفتار fetch را با استفاده از آپشن cache و next.revalidate کنترل کنید:

  • cache: 'force-cache' (پیش‌فرض): تلاش می‌کند داده‌ها را از کش برگرداند. اگر داده در کش نباشد، دریافت و سپس کش می‌شود.
  • cache: 'no-store': درخواست همیشه به سرور ارسال می‌شود و نتیجه هرگز کش نمی‌شود. این برای داده‌هایی که دائماً تغییر می‌کنند (مانند وضعیت لحظه‌ای کاربر) مناسب است و معادل SSR است.
  • next: { revalidate: <seconds> }: داده‌ها پس از گذشت تعداد ثانیه مشخص شده، منقضی (revalidate) می‌شوند. این همان مکانیزم ISR (Incremental Static Regeneration) است که قبلاً بررسی کردیم.
    // app/products/page.tsx
    async function getProducts() {
      const res = await fetch('https://api.example.com/products', {
        cache: 'no-store', // یا next: { revalidate: 60 } برای ISR
      });

      if (!res.ok) {
        // مدیریت خطا
        throw new Error('Failed to fetch products');
      }
      return res.json();
    }

    export default async function ProductsPage() {
      const products = await getProducts();

      return (
        <div>
          <h1>لیست محصولات</h1>
          <ul>
            {products.map((product) => (
              <li key={product.id}>{product.name}</li>
            ))}
          </ul>
        </div>
      );
    }

۲. API Routes در Next.js

API Routes به شما اجازه می‌دهند تا نقاط پایانی (Endpoints) API را مستقیماً در پوشه app/api (در App Router) یا pages/api (در Pages Router) ایجاد کنید. این APIها روی سرور Node.js اجرا می‌شوند.

  • ساختار در App Router:

برای ایجاد یک API Route، یک پوشه با نام api در داخل پوشه app ایجاد کنید و سپس زیرپوشه‌هایی برای مسیرهای API خود بسازید. هر مسیر باید یک فایل route.ts (یا .js) داشته باشد که توابع هندلر HTTP (مانند GET, POST, PUT, DELETE) را export می‌کند.

مثال: API Route برای دریافت لیست کاربران (app/api/users/route.ts)

    // app/api/users/route.ts
    import { NextResponse } from 'next/server';

    // داده‌های نمونه (در یک برنامه واقعی، این داده‌ها از دیتابیس می‌آیند)
    const users = [
      { id: 1, name: 'علی احمدی' },
      { id: 2, name: 'مریم رضایی' },
    ];

    // هندلر برای درخواست GET
    export async function GET(request: Request) {
      // می‌توانید پارامترهای کوئری را از request.url استخراج کنید
      // const { searchParams } = new URL(request.url);
      // const query = searchParams.get('query');

      return NextResponse.json(users);
    }

    // هندلر برای درخواست POST
    export async function POST(request: Request) {
      const newUser = await request.json();
      // اینجا می‌توانید newUser را به دیتابیس اضافه کنید
      newUser.id = users.length + 1; // اختصاص ID نمونه
      users.push(newUser);
      return NextResponse.json(newUser, { status: 201 }); // 201 Created
    }

مثال: فراخوانی API Route از یک کامپوننت فرانت‌اند:

    // app/users/page.tsx (یک کامپوننت سمت کلاینت یا سرور)
    async function getUsers() {
      const res = await fetch('http://localhost:3000/api/users'); // فراخوانی API Route
      if (!res.ok) {
        throw new Error('Failed to fetch users');
      }
      return res.json();
    }

    export default async function UsersPage() {
      const users = await getUsers();

      return (
        <div>
          <h1>لیست کاربران</h1>
          <ul>
            {users.map((user) => (
              <li key={user.id}>{user.name}</li>
            ))}
          </ul>
        </div>
      );
    }

۳. استفاده از سرورهای Edge (Edge Runtime)

Next.js به شما اجازه می‌دهد که API Routes و Server Components خود را روی Edge Runtime (مانند Vercel Edge Functions یا Cloudflare Workers) اجرا کنید. این محیط‌ها سریع‌تر بارگذاری می‌شوند و تأخیر کمتری دارند، اما محدودیت‌هایی نسبت به Node.js دارند (مانند عدم دسترسی به تمام APIهای Node.js).

  • نحوه فعال‌سازی:

برای فعال کردن Edge Runtime برای یک API Route، کافی است در فایل route.ts، گزینه runtime: 'edge' را در export const runtime مشخص کنید:

    // app/api/edge-example/route.ts
    export const runtime = 'edge'; // فعال‌سازی Edge Runtime

    export async function GET(request: Request) {
      // این کد روی Edge اجرا می‌شود
      const response = new Response(JSON.stringify({ message: 'Hello from Edge!' }), {
        headers: { 'Content-Type': 'application/json' },
      });
      return response;
    }

۴. مدیریت فرم‌ها و تعاملات کاربر

API Routes برای پردازش داده‌های ارسالی از فرم‌های HTML یا درخواست‌های API کلاینت‌ها ایده‌آل هستند. با استفاده از HTTP methods مانند POST، PUT، DELETE می‌توانید عملیات CRUD (Create, Read, Update, Delete) را بر روی داده‌های خود پیاده‌سازی کنید.

  • مثال: ارسال داده فرم با POST:

در بخش قبل، یک API Route برای POST کردن کاربر جدید را دیدیم. در فرانت‌اند، می‌توانید با استفاده از fetch یا کتابخانه‌هایی مانند react-hook-form، داده‌های فرم را به این API ارسال کنید.

اهمیت API Routes برای سئو و تجربه کاربری:

  • APIهای متمرکز: تمام منطق بک‌اند و فرانت‌اند در یک پروژه Next.js مدیریت می‌شود که توسعه و استقرار را ساده‌تر می‌کند.
  • SSR/SSG با داده‌های داینامیک: می‌توانید صفحات را به صورت استاتیک تولید کنید (SSG) اما داده‌های لازم را از API Routes خود در زمان بیلد دریافت کنید، یا صفحات را به صورت داینامیک با داده‌های تازه از API Routes خود رندر کنید (SSR).
  • قابلیت مقیاس‌پذیری: با استفاده از Edge Runtime، می‌توانید APIهایی بسازید که بسیار سریع و با تأخیر کم در سراسر جهان اجرا شوند، که برای تجربه کاربری بهتر و سئو حیاتی است.

با تسلط بر مدیریت داده‌ها و API Routes، شما کنترل کاملی بر نحوه دریافت، پردازش و ارائه اطلاعات در برنامه Next.js خود خواهید داشت و می‌توانید برنامه‌های کاربردی پیچیده‌تر و کارآمدتری بسازید.