كيفية معاينة المحتوى باستخدام وضع المسودة (Draft Mode) في Next.js
في توثيق الصفحات وتوثيق جلب البيانات، تحدثنا عن كيفية تقديم صفحة مسبقًا في وقت البناء (التوليد الثابت) باستخدام getStaticProps
وgetStaticPaths
.
يكون التوليد الثابت مفيدًا عندما تقوم صفحاتك بجلب البيانات من نظام إدارة المحتوى (CMS) بدون واجهة أمامية. ومع ذلك، فهو ليس مثاليًا عندما تكتب مسودة على نظام إدارة المحتوى الخاص بك وتريد معاينة المسودة فورًا على صفحتك. سترغب في أن يقوم Next.js بعرض هذه الصفحات في وقت الطلب بدلاً من وقت البناء وجلب محتوى المسودة بدلاً من المحتوى المنشور. سترغب في أن يتجاوز Next.js التوليد الثابت فقط لهذه الحالة المحددة.
يحتوي Next.js على ميزة تسمى وضع المسودة (Draft Mode) التي تحل هذه المشكلة. إليك التعليمات حول كيفية استخدامها.
الخطوة 1: إنشاء مسار API والوصول إليه
ألق نظرة على توثيق مسارات API أولاً إذا لم تكن معتادًا على مسارات API في Next.js.
أولاً، قم بإنشاء مسار API. يمكن أن يكون له أي اسم - على سبيل المثال pages/api/draft.ts
في مسار API هذا، تحتاج إلى استدعاء setDraftMode
على كائن الاستجابة.
export default function handler(req, res) {
// ...
res.setDraftMode({ enable: true })
// ...
}
سيؤدي هذا إلى تعيين كوكي لتمكين وضع المسودة. ستؤدي الطلبات اللاحقة التي تحتوي على هذا الكوكي إلى تشغيل وضع المسودة مما يغير سلوك الصفحات المولدة بشكل ثابت (المزيد عن هذا لاحقًا).
يمكنك اختبار هذا يدويًا عن طريق إنشاء مسار API مثل أدناه والوصول إليه يدويًا من متصفحك:
// مثال بسيط لاختباره يدويًا من متصفحك.
export default function handler(req, res) {
res.setDraftMode({ enable: true })
res.end('تم تمكين وضع المسودة')
}
إذا فتحت أدوات المطور في متصفحك وقمت بزيارة /api/draft
، ستلاحظ رأس استجابة Set-Cookie
مع كوكي باسم __prerender_bypass
.
الوصول إليه بأمان من نظام إدارة المحتوى الخاص بك
عمليًا، سترغب في استدعاء مسار API هذا بأمان من نظام إدارة المحتوى الخاص بك. ستختلف الخطوات المحددة اعتمادًا على نظام إدارة المحتوى الذي تستخدمه، ولكن إليك بعض الخطوات الشائعة التي يمكنك اتخاذها.
تفترض هذه الخطوات أن نظام إدارة المحتوى الذي تستخدمه يدعم تعيين عنوان URL مخصص للمسودات. إذا لم يكن كذلك، فلا يزال بإمكانك استخدام هذه الطريقة لتأمين عناوين URL للمسودات، ولكنك ستحتاج إلى إنشاء عنوان URL للمسودة والوصول إليه يدويًا.
أولاً، يجب عليك إنشاء رمز سري باستخدام أداة توليد الرموز التي تختارها. سيعرف هذا السر فقط تطبيق Next.js الخاص بك ونظام إدارة المحتوى الخاص بك. يمنع هذا السر الأشخاص الذين لا يمكنهم الوصول إلى نظام إدارة المحتوى الخاص بك من الوصول إلى عناوين URL للمسودات.
ثانيًا، إذا كان نظام إدارة المحتوى الخاص بك يدعم تعيين عناوين URL مخصصة للمسودات، فحدد ما يلي كعنوان URL للمسودة. يفترض هذا أن مسار API للمسودة موجود في pages/api/draft.ts
.
https://<your-site>/api/draft?secret=<token>&slug=<path>
<your-site>
يجب أن يكون نطاق النشر الخاص بك.<token>
يجب استبداله بالرمز السري الذي قمت بتوليده.<path>
يجب أن يكون المسار للصفحة التي تريد معاينتها. إذا كنت تريد معاينة/posts/foo
، فيجب عليك استخدام&slug=/posts/foo
.
قد يسمح لك نظام إدارة المحتوى الخاص بتضمين متغير في عنوان URL للمسودة بحيث يمكن تعيين <path>
ديناميكيًا بناءً على بيانات نظام إدارة المحتوى مثل: &slug=/posts/{entry.fields.slug}
أخيرًا، في مسار API للمسودة:
- تحقق من تطابق السر وأن معلمة
slug
موجودة (إذا لم تكن كذلك، يجب أن يفشل الطلب). - استدعِ
res.setDraftMode
. - ثم قم بتوجيه المتصفح إلى المسار المحدد بواسطة
slug
. (يستخدم المثال التالي إعادة توجيه 307).
export default async (req, res) => {
// تحقق من المعلمة السرية والمعلمة التالية
// يجب أن يعرف هذا السر فقط مسار API هذا ونظام إدارة المحتوى
if (req.query.secret !== 'MY_SECRET_TOKEN' || !req.query.slug) {
return res.status(401).json({ message: 'رمز غير صالح' })
}
// اتصل بنظام إدارة المحتوى للتحقق مما إذا كان `slug` المقدم موجودًا
// ستنفذ getPostBySlug منطق الجلب المطلوب لنظام إدارة المحتوى
const post = await getPostBySlug(req.query.slug)
// إذا لم يكن slug موجودًا، امنع تمكين وضع المسودة
if (!post) {
return res.status(401).json({ message: 'slug غير صالح' })
}
// تمكين وضع المسودة عن طريق تعيين الكوكي
res.setDraftMode({ enable: true })
// إعادة توجيه إلى المسار من المنشور الذي تم جلبه
// لا نعيد التوجيه إلى req.query.slug لأن ذلك قد يؤدي إلى ثغرات إعادة توجيه مفتوحة
res.redirect(post.slug)
}
إذا نجح ذلك، فسيتم إعادة توجيه المتصفح إلى المسار الذي تريد معاينته مع كوكي وضع المسودة.
الخطوة 2: تحديث getStaticProps
الخطوة التالية هي تحديث getStaticProps
لدعم وضع المسودة.
إذا قمت بطلب صفحة تحتوي على getStaticProps
مع تعيين الكوكي (عبر res.setDraftMode
)، فسيتم استدعاء getStaticProps
في وقت الطلب (بدلاً من وقت البناء).
علاوة على ذلك، سيتم استدعاؤه مع كائن context
حيث سيكون context.draftMode
true
.
export async function getStaticProps(context) {
if (context.draftMode) {
// بيانات ديناميكية
}
}
لقد استخدمنا res.setDraftMode
في مسار API للمسودة، لذا سيكون context.draftMode
true
.
إذا كنت تستخدم أيضًا getStaticPaths
، فسيكون context.params
متاحًا أيضًا.
جلب بيانات المسودة
يمكنك تحديث getStaticProps
لجلب بيانات مختلفة بناءً على context.draftMode
.
على سبيل المثال، قد يحتوي نظام إدارة المحتوى الخاص بك على نقطة نهاية API مختلفة للمسودات. إذا كان الأمر كذلك، يمكنك تعديل عنوان URL لنقطة نهاية API كما يلي:
export async function getStaticProps(context) {
const url = context.draftMode
? 'https://draft.example.com'
: 'https://production.example.com'
const res = await fetch(url)
// ...
}
هذا كل شيء! إذا قمت بالوصول إلى مسار API للمسودة (مع secret
و slug
) من نظام إدارة المحتوى الخاص بك أو يدويًا، فيجب أن تكون قادرًا الآن على رؤية محتوى المسودة. وإذا قمت بتحديث مسودتك دون نشر، فيجب أن تكون قادرًا على معاينة المسودة.
قم بتعيين هذا كعنوان URL للمسودة على نظام إدارة المحتوى الخاص بك أو قم بالوصول إليه يدويًا، ويجب أن تكون قادرًا على رؤية المسودة.
https://<your-site>/api/draft?secret=<token>&slug=<path>
المزيد من التفاصيل
مسح كوكي وضع المسودة
افتراضيًا، تنتهي جلسة وضع المسودة عند إغلاق المتصفح.
لمسح كوكي وضع المسودة يدويًا، قم بإنشاء مسار API يستدعي setDraftMode({ enable: false })
:
export default function handler(req, res) {
res.setDraftMode({ enable: false })
}
ثم، أرسل طلبًا إلى /api/disable-draft
لاستدعاء مسار API. إذا كنت تستدعي هذا المسار باستخدام next/link
، فيجب عليك تمرير prefetch={false}
لمنع حذف الكوكي عن طريق الخطأ أثناء الجلب المسبق.
يعمل مع getServerSideProps
يعمل وضع المسودة مع getServerSideProps
، وهو متاح كمفتاح draftMode
في كائن context
.
معلومة مفيدة: لا يجب عليك تعيين رأس
Cache-Control
عند استخدام وضع المسودة لأنه لا يمكن تجاوزه. بدلاً من ذلك، نوصي باستخدام ISR.
يعمل مع مسارات API
سيكون لمسارات API حق الوصول إلى draftMode
على كائن الطلب. على سبيل المثال:
export default function myApiRoute(req, res) {
if (req.draftMode) {
// جلب بيانات المسودة
}
}
فريد لكل next build
سيتم إنشاء قيمة كوكي تجاوز جديدة في كل مرة تقوم فيها بتشغيل next build
.
هذا يضمن أنه لا يمكن تخمين كوكي التجاوز.
معلومة مفيدة: لاختبار وضع المسودة محليًا عبر HTTP، سيحتاج متصفحك إلى السماح بملفات تعريف الارتباط من طرف ثالث والوصول إلى التخزين المحلي.