توليد المواقع الثابتة (SSG)

أمثلة

إذا كانت الصفحة تستخدم التوليد الثابت، فإن HTML الصفحة يتم إنشاؤه في وقت البناء. هذا يعني في بيئة الإنتاج، يتم إنشاء HTML الصفحة عند تشغيل next build. سيتم بعد ذلك إعادة استخدام هذا HTML في كل طلب. يمكن تخزينه مؤقتًا بواسطة CDN.

في Next.js، يمكنك توليد الصفحات ثابتًا مع أو بدون بيانات. دعونا نلقي نظرة على كل حالة.

التوليد الثابت بدون بيانات

افتراضيًا، يقوم Next.js بتقديم الصفحات مسبقًا باستخدام التوليد الثابت دون جلب البيانات. إليك مثال:

function About() {
  return <div>About</div>
}

export default About

لاحظ أن هذه الصفحة لا تحتاج إلى جلب أي بيانات خارجية ليتم تقديمها مسبقًا. في مثل هذه الحالات، ينشئ Next.js ملف HTML واحد لكل صفحة أثناء وقت البناء.

التوليد الثابت مع البيانات

بعض الصفحات تتطلب جلب بيانات خارجية للتقديم المسبق. هناك سيناريوهان، وقد ينطبق أحدهما أو كلاهما. في كل حالة، يمكنك استخدام هذه الوظائف التي يوفرها Next.js:

  1. إذا كان محتوى صفحتك يعتمد على بيانات خارجية: استخدم getStaticProps.
  2. إذا كانت مسارات صفحتك تعتمد على بيانات خارجية: استخدم getStaticPaths (عادة بالإضافة إلى getStaticProps).

السيناريو 1: محتوى الصفحة يعتمد على بيانات خارجية

مثال: قد تحتاج صفحة المدونة الخاصة بك إلى جلب قائمة منشورات المدونة من نظام إدارة المحتوى (CMS).

// TODO: يجب جلب `posts` (عن طريق استدعاء نقطة نهاية API)
//       قبل أن يمكن تقديم هذه الصفحة مسبقًا.
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

لجلب هذه البيانات عند التقديم المسبق، يسمح لك Next.js بتصدير دالة غير متزامنة تسمى getStaticProps من نفس الملف. يتم استدعاء هذه الدالة في وقت البناء وتتيح لك تمرير البيانات التي تم جلبها إلى props الصفحة عند التقديم المسبق.

export default function Blog({ posts }) {
  // عرض المنشورات...
}

// يتم استدعاء هذه الدالة في وقت البناء
export async function getStaticProps() {
  // استدعاء نقطة نهاية API خارجية للحصول على المنشورات
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // عن طريق إرجاع { props: { posts } }، سيستلم مكون Blog
  // `posts` كخاصية في وقت البناء
  return {
    props: {
      posts,
    },
  }
}

لمعرفة المزيد حول كيفية عمل getStaticProps، راجع توثيق جلب البيانات.

السيناريو 2: مسارات الصفحة تعتمد على بيانات خارجية

يسمح لك Next.js بإنشاء صفحات ذات مسارات ديناميكية. على سبيل المثال، يمكنك إنشاء ملف يسمى pages/posts/[id].js لعرض منشور مدونة واحد بناءً على id. سيسمح لك هذا بعرض منشور المدونة بـ id: 1 عند الوصول إلى posts/1.

لمعرفة المزيد حول التوجيه الديناميكي، راجع توثيق التوجيه الديناميكي.

ومع ذلك، قد يعتمد id الذي تريد تقديمه مسبقًا في وقت البناء على بيانات خارجية.

مثال: لنفترض أنك أضفت منشور مدونة واحد فقط (مع id: 1) إلى قاعدة البيانات. في هذه الحالة، سترغب فقط في تقديم posts/1 مسبقًا في وقت البناء.

لاحقًا، قد تضيف المنشور الثاني مع id: 2. ثم سترغب في تقديم posts/2 مسبقًا أيضًا.

لذا فإن مسارات الصفحة التي يتم تقديمها مسبقًا تعتمد على بيانات خارجية. للتعامل مع هذا، يسمح لك Next.js بتصدير دالة غير متزامنة تسمى getStaticPaths من صفحة ديناميكية (pages/posts/[id].js في هذه الحالة). يتم استدعاء هذه الدالة في وقت البناء وتتيح لك تحديد المسارات التي تريد تقديمها مسبقًا.

// يتم استدعاء هذه الدالة في وقت البناء
export async function getStaticPaths() {
  // استدعاء نقطة نهاية API خارجية للحصول على المنشورات
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // الحصول على المسارات التي نريد تقديمها مسبقًا بناءً على المنشورات
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // سنقوم بتقديم هذه المسارات مسبقًا فقط في وقت البناء.
  // { fallback: false } تعني أن المسارات الأخرى يجب أن تعرض 404.
  return { paths, fallback: false }
}

أيضًا في pages/posts/[id].js، تحتاج إلى تصدير getStaticProps حتى تتمكن من جلب بيانات المنشور مع هذا id واستخدامها لتقديم الصفحة مسبقًا:

export default function Post({ post }) {
  // عرض المنشور...
}

export async function getStaticPaths() {
  // ...
}

// يتم استدعاء هذه الدالة أيضًا في وقت البناء
export async function getStaticProps({ params }) {
  // params تحتوي على `id` المنشور.
  // إذا كان المسار مثل /posts/1، فإن params.id هو 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  // تمرير بيانات المنشور إلى الصفحة عبر الخاصيات
  return { props: { post } }
}

لمعرفة المزيد حول كيفية عمل getStaticPaths، راجع توثيق جلب البيانات.

متى يجب استخدام التوليد الثابت؟

نوصي باستخدام التوليد الثابت (مع وبدون بيانات) كلما أمكن ذلك لأن صفحتك يمكن بناؤها مرة واحدة وتقديمها بواسطة CDN، مما يجعلها أسرع بكثير من جعل الخادم يعرض الصفحة في كل طلب.

يمكنك استخدام التوليد الثابت للعديد من أنواع الصفحات، بما في ذلك:

  • صفحات التسويق
  • منشورات المدونات والمحافظ
  • قوائم منتجات التجارة الإلكترونية
  • المساعدة والوثائق

يجب أن تسأل نفسك: "هل يمكنني تقديم هذه الصفحة مسبقًا قبل طلب المستخدم؟" إذا كانت الإجابة نعم، فيجب عليك اختيار التوليد الثابت.

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

في مثل هذه الحالات، يمكنك القيام بأحد الإجراءات التالية:

  • استخدام التوليد الثابت مع جلب البيانات من جانب العميل: يمكنك تخطي التقديم المسبق لبعض أجزاء الصفحة ثم استخدام JavaScript من جانب العميل لملئها. لمعرفة المزيد حول هذا النهج، راجع توثيق جلب البيانات.
  • استخدام التقديم من جانب الخادم (SSR): يقوم Next.js بتقديم الصفحة مسبقًا في كل طلب. سيكون أبطأ لأنه لا يمكن تخزين الصفحة مؤقتًا بواسطة CDN، ولكن الصفحة المقدمة مسبقًا ستكون دائمًا محدثة. سنتحدث عن هذا النهج أدناه.