توليد المواقع الثابتة (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()

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

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

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

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

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

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

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

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

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

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