وضع المسودة (Draft Mode)
في توثيق الصفحات وتوثيق جلب البيانات، تحدثنا عن كيفية تقديم صفحة مسبقًا في وقت البناء (التوليد الثابت) باستخدام 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) => {
// تحقق من السر ومعلمة slug
// يجب أن يعرف هذا السر فقط مسار 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، سيحتاج متصفحك إلى السماح بملفات تعريف الارتباط من طرف ثالث والوصول إلى التخزين المحلي.