الفرق بين المراجعتين لصفحة: «Next.js/next.config.js»
لا ملخص تعديل |
جميل-بيلوني (نقاش | مساهمات) ط مراجعة |
||
(15 مراجعة متوسطة بواسطة مستخدمين اثنين آخرين غير معروضة) | |||
سطر 2: | سطر 2: | ||
بإمكانك إنشاء الملف <code>next.config.js</code> أو <code>next.config.mjs</code> في جذر مشروعك وإلى جوار الملف <code>package.json</code>، إن كنت ترغب في تطبيق إعدادت متقدمة على تطبيق Next.js. | بإمكانك إنشاء الملف <code>next.config.js</code> أو <code>next.config.mjs</code> في جذر مشروعك وإلى جوار الملف <code>package.json</code>، إن كنت ترغب في تطبيق إعدادت متقدمة على تطبيق Next.js. | ||
يُعد الملف <code>next.config.js</code>وحدة | يُعد الملف <code>next.config.js</code>وحدة Node.js وليس ملف JSON، ويُستخدم من قبل خادم Next.js وخلال مراحل بناء التطبيق ولا يُضمَّن في تجميعة المتصفح. | ||
إليك مثالًا عن ملف التهيئة <code>next.config.js</code>:<syntaxhighlight lang="javascript"> | إليك مثالًا عن ملف التهيئة <code>next.config.js</code>:<syntaxhighlight lang="javascript"> | ||
سطر 42: | سطر 42: | ||
return nextConfig | return nextConfig | ||
} | } | ||
</syntaxhighlight>يُعد السياق <code>phase</code> هو السياق الحالي لتحميل الإعدادات | </syntaxhighlight>يُعد السياق <code>phase</code> هو السياق الحالي لتحميل الإعدادات وتوجد سياقات أخرى أيضًا. يمكن إدراج المراحل phases من الوحدة <code>next/constants</code>:<syntaxhighlight lang="javascript"> | ||
const { PHASE_DEVELOPMENT_SERVER } = require('next/constants') | const { PHASE_DEVELOPMENT_SERVER } = require('next/constants') | ||
سطر 56: | سطر 56: | ||
} | } | ||
} | } | ||
</syntaxhighlight>تُوضع الإعدادات المسموحة) في <code>next.config.js</code> مكان أسطر التعليقات في الشيفرات السابقة. مع ذلك، لا حاجة إلى أية إعدادات، وليس من الضرورة فهم عمل كل إعداد. كل ما عليك هو البحث عن الميزات التي تريد تفعيلها أو تعديلها في هذه الصفحة وستريك ما العمل.<blockquote>تفادى استخدام ميزات JavaScript الجديدة في اصدار | </syntaxhighlight>تُوضع الإعدادات المسموحة) في <code>next.config.js</code> مكان أسطر التعليقات في الشيفرات السابقة. مع ذلك، لا حاجة إلى أية إعدادات، وليس من الضرورة فهم عمل كل إعداد. كل ما عليك هو البحث عن الميزات التي تريد تفعيلها أو تعديلها في هذه الصفحة وستريك ما العمل.<blockquote>تفادى استخدام ميزات JavaScript الجديدة في اصدار Node.js الذي تستهدفه. فلن يُحلل الملف <code>next.config.js</code> من قبل Webpack أو Babel أو [[TypeScript]].</blockquote> | ||
== متغيرات البيئة == | == متغيرات البيئة == | ||
<blockquote>تقدم ابتداءً من الإصدار تجربة تعليمية وعملية في [[Next.js/environment variables|إضافة متغيرات البيئة]]. حاول أن تجربها.</blockquote>لإضافة متغيرات بيئة إلى تجميعة | <blockquote>تقدم ابتداءً من الإصدار 9.4 تجربة تعليمية وعملية في [[Next.js/environment variables|إضافة متغيرات البيئة]]. حاول أن تجربها.</blockquote>لإضافة متغيرات بيئة إلى تجميعة [[JavaScript]]، افتح الملف <code>next.config.js</code> وأضف الإعداد <code>env</code>:<syntaxhighlight lang="javascript"> | ||
module.exports = { | module.exports = { | ||
env: { | env: { | ||
سطر 71: | سطر 71: | ||
export default Page | export default Page | ||
</syntaxhighlight>تستبدل Next.js أثناء البناء المفاتيح | </syntaxhighlight>تستبدل Next.js أثناء البناء المفاتيح <code>process.env.customKey</code> بالقيمة <code>'my-value'</code>. وانتبه إلى أنك لن تستطيع تفكيك متغيرات <code>process.env</code> نظرًا لطبيعة الإضافة [https://webpack.js.org/plugins/define-plugin/ DefinePlugin] في webpack. فلو ألقينا نظرة مثلًا على السطر البرمجي التالي:<syntaxhighlight lang="javascript"> | ||
return <h1>The value of customKey is: {process.env.customKey}</h1> | return <h1>The value of customKey is: {process.env.customKey}</h1> | ||
</syntaxhighlight>سينتهي الأمر على النحو:<syntaxhighlight lang="javascript"> | </syntaxhighlight>سينتهي الأمر على النحو:<syntaxhighlight lang="javascript"> | ||
return <h1>The value of customKey is: {'my-value'}</h1> | return <h1>The value of customKey is: {'my-value'}</h1> | ||
</syntaxhighlight>'''تحذير''': متغيرات البيئة المُعرَّفة بهذه الطريقة ستُضاف إلى تجميعة JavaScript المُرسلة إلى العميل خلاف إضافتها في [[Next.js/environment variables|ملف <code>env.</code>]] والسلوك الذي تسلكه إلى أضفنا العبارة <code>NEXT_PUBLIC_</code> أو لا في بداية اسم متغير البيئة. | |||
انظر المثال [https://github.com/vercel/next.js/tree/canary/examples/with-env-from-next-config-js With env]. | |||
== المسار الأساسي basePath == | |||
<blockquote>أضيف بدءا من الإصدار 9.5.0.</blockquote>بإمكانك استخدام الإعداد <code>basePath</code> لنشر تطبيق Next.js ضمن مسار فرعي لنطاق، إذ يسمح لك هذا الإعداد بضبط بادئة للمسار في تطبيقك. ولكي تستخدم مثلًا المسار <code>docs/</code> بدلًا من المسار الأساسي الافتراضي <code>/</code>، افتح الملف <code>next.config.js</code> وأضف الإعداد <code>basePath</code> كالتالي: | |||
<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
basePath: '/docs', | |||
} | |||
</syntaxhighlight>'''ملاحظة''': لا بد من ضبط هذه القيمة أثناء البناء ولا يمكن تغييرها دون إعادة بناء التطبيق، لأن القيمة ستضاف مباشرة إلى تجميعة الشيفرة الخاصة بجانب العميل. | |||
=== الروابط === | |||
عند ربط الصفحة بغيرها باستخدام <code>next/link</code> و <code>next/router</code> سيُطبق الإعداد <code>basePath</code> تلقائيًا. إذ سيتحول على سبيل المثال المسار <code>about/</code> إلى <code>docs/about/</code> تلقائيًا عند ضبط قيمة الإعداد <code>basePath</code> على <code>docs/</code>.<syntaxhighlight lang="javascript"> | |||
export default function HomePage() { | |||
return ( | |||
<> | |||
<Link href="/about"> | |||
<a>About Page</a> | |||
</Link> | |||
</> | |||
) | |||
} | |||
</syntaxhighlight>وسيكون خرج HTML كالتالي:<syntaxhighlight lang="javascript"> | |||
<a href="/docs/about">About Page</a> | |||
</syntaxhighlight>يضمن ذلك أنك لن تُضطر إلى تغيير كل الروابط في تطبيقك عند تغيير قيمة الإعداد <code>basePath</code>. | |||
=== الصور === | |||
لا بد من إضافة قيمة الإعداد <code>basePath</code> قبل قيمة الخاصية <code>src</code> إن كنت تريد استخدام المكوّن <code>next/image</code>. فالمسار <code>docs/me.png/</code> سيخدّم صورتك بالشكل الصحيح إن قررت أن تكون قيمة الإعداد <code>basePath</code> هي <code>docs/</code>.<syntaxhighlight lang="javascript"> | |||
import Image from 'next/image' | |||
function Home() { | |||
return ( | |||
<> | |||
<h1>My Homepage</h1> | |||
<Image | |||
src="/docs/me.png" | |||
alt="Picture of the author" | |||
width={500} | |||
height={500} | |||
/> | |||
<p>Welcome to my homepage!</p> | |||
</> | |||
) | |||
} | |||
export default Home | |||
</syntaxhighlight> | |||
== إعادة الكتابة Rewrites == | |||
{| class="wikitable" | |||
|+سجل التغييرات | |||
!الإصدار | |||
!التغييرات | |||
|- | |||
|13.3.1 | |||
|إضافة missing | |||
|- | |||
|10.2.0 | |||
|إضافة has | |||
|- | |||
|9.5.0 | |||
|إضافة خاصية إعادة الكتابة | |||
|} | |||
تتيح لك عملية إعادة الكتابة Rewrites ربط مسار طلب وارد إلى مسار وجهة أخرى. تعمل إعادة الكتابة مثل وسيط لعناوين URL وتقنِّع المسار إلى الوجهة ليظهر المستخدم وكأنه لم يغير مكانه في الموقع. بالمقابل تعيد عملية إعادة التوجيه redirects توجيه المستخدم إلى صفحة جديدة وتُظهر التغييرات على العنوان. | |||
ولتستخدم إعادة الكتابة أضف المفتاح <code>rewrites</code> إلى ملف التهيئة <code>next.config.js</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/about', | |||
destination: '/', | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>تُطبق إعادة الكتابة على التوجيه في جانب العميل، وتطبق إعادة الكتابة في المثال السابق مثلًا على العنصر <code><"Link href="/about></code>. | |||
إن الدالة هي دالة غير متزامنة تتوقع إعادة مصفوفة تضم كائنات تمتلك الخاصيتين <code>source</code> و <code>destination</code>: | |||
* <code>source</code>: من النوع <code>String</code>، وهو نموذج مسار الطلب الوارد. | |||
* <code>destination</code>: من النوع <code>String</code>، وهو المسار الذي تريد التوجه إليه. | |||
* <code>basePath</code>: تأخذ أحد القيمتين <code>false</code> أو <code>undefined</code>، فإن كانت القيمة <code>false</code>، لن يضاف المسار الأساسي إلى العنوان عند المطابقة، ويستخدم في إعادة الكتابة الخارجية. | |||
* <code>locale</code>: تأخذ أحد القيمتين <code>false</code> أو <code>undefined</code>، يحدد إن كان سُضاف الإعداد المحلي إلى المسار عند المطابقة. | |||
* <code>has</code>: مصفوفة من الكائنات <code>has objects</code> لها الخاصيات <code>type</code> و <code>key</code> و <code>value</code>. | |||
* <code>missing</code>: مصفوفة من كائنات لها الخاصيات <code>type</code> و <code>key</code> و <code>value</code>. | |||
تجري عملية إعادة الكتابة بعد التحقق من منظومة الملفات (ملفات المجلدين <code>pages</code> و <code>public</code>) وقبل التوجه الديناميكي افتراضيًا. يمكن تغيير هذا السلوك بإعادة كائن بدلًا من المصفوفة من الدالة <code>rewrites</code> ابتداءً من الإصدار <code>10.1</code> من Next.js:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return { | |||
beforeFiles: [ | |||
//يجري التحقق من عمليات إعادة الكتابة هذه بعد الترويسات | |||
// أو إعادة التوجيه | |||
//_next/public وقبل كل الملفات بما فيها ملفات المجلد | |||
// مما يسمح بتغيير ملفات الصفحة | |||
{ | |||
source: '/some-page', | |||
destination: '/somewhere-else', | |||
has: [{ type: 'query', key: 'overrideMe' }], | |||
}, | |||
], | |||
afterFiles: [ | |||
// pages/public يجري التحقق من عمليات إعادة الكتابة هذه بعد ملفات | |||
// لكن قبل الوجهات الديناميكية | |||
{ | |||
source: '/non-existent', | |||
destination: '/somewhere-else', | |||
}, | |||
], | |||
fallback: [ | |||
// pages/public يجري التحقق من عمليات إعادة الكتابة هذه بعد ملفات | |||
// وقبل الوجهات الديناميكية | |||
{ | |||
source: '/:path*', | |||
destination: `https://my-old-site.com/:path*`, | |||
}, | |||
], | |||
} | |||
}, | |||
} | |||
</syntaxhighlight>'''ملاحظة''': إنّ إجراء إعادة كتابة ضمن <code>beforeFiles</code> لا يتضمن التحقق المباشر من نظام الملفات والوجهات الديناميكية بعد مطابقة المصدر، بل تستمر حتى يجري التحقق من جميع الإجراءات ضمن <code>beforeFiles</code>. إليك ترتيب التحقق من وجهات Next.js: | |||
# يجري التحقق من الترويسات headers أو تطبيقها. | |||
# يجري التحقق من عمليات إعادة التوجيه redirects أو تطبيقها. | |||
# يجري التحقق من عمليات إعادة الكتابة ضمن <code>beforeFiles</code> أو تطبيقها. | |||
# يجري التحقق من الملفات الساكنة في المجلد <code>public</code> و <code>next/static_</code> والصفحات غير الديناميكية أو تخديمها. | |||
# يجري التحقق من عمليات إعادة الكتابة ضمن <code>afterFiles</code> أو تطبيقها، فإن تطابقت إحدى عمليات إعادة الكتابة، نتحقق من الوجهة الديناميكية أو الملفات الساكنة بعد كل تطابق. | |||
# يجري التحقق من إعادة الكتابة ضمن <code>fallback</code> أو تطبيقها، ويجري تطبيقها قبل تصيير الصفحة 404، وبعد التحقق من الوجهات الديناميكية وجميع الموجودات الساكنة. إن كنت تستخدم fallback: true/'blocking' في <code>getStaticPaths</code> فلن تعمل عملية إعادة الكتابة ضمن <code>fallback</code>. | |||
=== معاملات الدالة <code>rewrites</code> === | |||
عند استخدام المعاملات، تُمرر هذه المعاملات إلى الدالة عبر الاستعلام افتراضيًا إن لم يُستخدم أيًا منها في الخاصية <code>destination</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/old-about/:path*', | |||
destination: '/about', //وبالتالي سيُمرر path لم يُستخدم المعامل | |||
// تلقائيًا ضمن الاستعلام | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>أما إن استُخدم معامل في الوجهة <code>destination</code>، فلن يُمرر أي من المعاملات تلقائيًا ضمن الاستعلام:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/docs/:path*', | |||
destination: '/:path*',//وبالتالي لن يُمرر path استُخدم المعامل | |||
// أي معامل تلقائيًا من خلال الاستعلام | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>لكن لا يزال بإمكانك تمرير المعاملات يدويًا ضمن الاستعلام إن استُخدم أحدها في الخاصية <code>destination</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/:first/:second', | |||
destination: '/:first?second=:second', | |||
//قد استُخدم في الوجهة فلن يُضاف first طالما أن المعامل | |||
// تلقائيًا second المعامل الثاني | |||
// إلى الاستعلام على الرغم من إمكانية إضافته يدويًا كما في الأعلى | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>'''ملاحظة''': تُحلَّل معاملات إعادة الكتابة للصفحات الساكنة الناتجة عن [[Next.js/automatic static optimization|التحسين التلقائي الساكن]] أو [[Next.js/data fetching|التصيير المسبق]] من جانب العميل بعد الترطيب ويُزوَّد به الاستعلام. | |||
=== مطابقة المسارات === | |||
يُسمح بمطابقة المسارات كأن يُطابق المسار <code>blog/:slug/</code> المسار <code>blog/hello-world/</code> (دون تداخل في المسارات).<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/blog/:slug', | |||
destination: '/news/:slug', // يمكن مطابقة المعاملات هنا | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== مطابقة المسارات بوجود محارف بديلة ==== | |||
لمطابقة مسار باستخدام محارف بديلة، بإمكانك استعمال <code>*</code> بعد المعامل، إذ سيُطابق المسار <code>*blog/:slug/</code> مثلًا المسار <code>/blog/a/b/c/d/hello-world</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/blog/:slug*', | |||
destination: '/news/:slug*', // يمكن مطابقة المعاملات هنا | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== مطابقة المسارات من خلال التعابير النمطية Regex ==== | |||
لمطابقة مسار من خلال التعابير النمطية، غلِّف التعبير النمطي ضمن قوسين بعد المعامل. سيطابق المسار <code>blog/:slug(\\d{1,})/</code> مثلًا المسار <code>blog/123/</code> وليس المسار <code>blog/abc/</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/old-blog/:post(\\d{1,})', | |||
destination: '/blog/:post', // يمكن مطابقة المعاملات هنا | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>تُستخدم المحارف التالية <code>(</code> و <code>)</code> و <code>{</code> و <code>}</code> و <code>:</code> و <code>*</code> و <code>+</code> و <code>?</code> في صياغة التعابير النمطية المستخدمة لمطابقة المسارات، فإن استُخدمت في الخاصية <code>source</code> كقيم غير خاصة non-special لا بد من تجاوزها بإضافة الصيغة <code>\\</code> قبلها:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return [ | |||
{ | |||
//`/english(default)/something` سيثطابق ذلك | |||
source: '/english\\(default\\)/:slug', | |||
destination: '/en-us/:slug', | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
=== مطابقة الترويسات وملفات تعريف الارتباط والاستعلام === | |||
بالإمكان مطابقة عملية إعادة كتابة عندما تُطابِق قيم الترويسات أو ملف تعريف الارتباط أو الاستعلام قيمة الحقل <code>has</code> أو لا تطابق قيمة الحقل <code>missing</code>. أي يجب أن تتطابق الخاصية <code>source</code> وجميع عناصر <code>has</code> حتى تُطبَّق إعادة الكتابة ولا يجب أن تتطابق جميع عناصر <code>missing</code>. تمتلك العناصر <code>has</code> و <code>missing</code> الحقول التالية: | |||
* <code>type</code>: من النوع <code>String</code>، وسيكون إما <code>header</code> أو <code>cookie</code> أو <code>host</code> أو <code>query</code>. | |||
* <code>key</code>: من النوع <code>String</code>، مفتاح النوع المختار <code>type</code> الذي سيُطابق. | |||
* <code>value</code>: من النوع <code>String</code> أو <code>undefined</code>، القيمة التي سيجري التحقق منها، وإن كانت غير محددة ستُطابق أي قيمة. يمكن استخدام سلسلة نصية تشابه التعبير النمطي لالتقاط جزء محدد من القيمة. فإن استُخدمت القيمة <code>first-(?<paramName>.*)</code> لمطابقة <code>first-second</code>، ستتمكن حينها من استخدام <code>second</code> في الوجهة مع المعامل <code>:paramName</code>. | |||
<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return [ | |||
// `x-rewrite-me` إن وجدت الترويسة | |||
// تُطبق إعادة الكتابة | |||
{ | |||
source: '/:path*', | |||
has: [ | |||
{ | |||
type: 'header', | |||
key: 'x-rewrite-me', | |||
}, | |||
], | |||
destination: '/another-page', | |||
}, | |||
// `x-rewrite-me` إن فقدت الترويسة | |||
// تُطبق إعادة الكتابة | |||
{ | |||
source: '/:path*', | |||
missing: [ | |||
{ | |||
type: 'header', | |||
key: 'x-rewrite-me', | |||
}, | |||
], | |||
destination: '/another-page', | |||
}, | |||
// إن تطابقت الترويسة أو ملف الارتباط أو الاستعلام | |||
// تُطبق إعادة الكتابة | |||
{ | |||
source: '/specific/:path*', | |||
has: [ | |||
{ | |||
type: 'query', | |||
key: 'page', | |||
//لن تكون قيمة الصفحة متاحة في الوجهة لأن القيمة موجودة | |||
//(?<page>home) ولا تُستخدم مجموعة التقاط مُسماة مثل | |||
value: 'home', | |||
}, | |||
{ | |||
type: 'cookie', | |||
key: 'authorized', | |||
value: 'true', | |||
}, | |||
], | |||
destination: '/:path*/home', | |||
}, | |||
//وتحتوي على قيمة التطابق `x-authorized` إن وجدت الترويسة | |||
//ستُطيّق إعادة الكتابة | |||
{ | |||
source: '/:path*', | |||
has: [ | |||
{ | |||
type: 'header', | |||
key: 'x-authorized', | |||
value: '(?<authorized>yes|true)', | |||
}, | |||
], | |||
destination: '/home?authorized=:authorized', | |||
}, | |||
//ستُطبّق إعادة الكتابة `example.com` إن كان المضيف | |||
{ | |||
source: '/:path*', | |||
has: [ | |||
{ | |||
type: 'host', | |||
value: 'example.com', | |||
}, | |||
], | |||
destination: '/another-page', | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
=== إعادة الكتابة إلى عنوان URL خارجي === | |||
بإمكانك إعادة الكتابة إلى عنوان URL خارجي، وهذا مفيد لتبني Next.js تدريجيًا. إليك مثالًا عن إعادة كتابة لتحويل الوجهة <code>blog/</code> لتطبيقك الرئيسي إلى موقع خارجي:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/blog', | |||
destination: 'https://example.com/blog', | |||
}, | |||
{ | |||
source: '/blog/:slug', | |||
destination: 'https://example.com/blog/:slug', | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>إن كنت تستخدم الحقل <code>trailingSlash: true</code> فستحتاج أيضًا إلى حشر محرف <code>/</code> في نهاية قيمة المعامل <code>source</code>. وإن كان الخادم الهدف يتوقع وجود المحرف <code>/</code> في نهاية القيمة، فلا بد من وضعها في المعامل <code>destination</code> أيضًا.<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
trailingSlash: true, | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/blog/', | |||
destination: 'https://example.com/blog/', | |||
}, | |||
{ | |||
source: '/blog/:path*/', | |||
destination: 'https://example.com/blog/:path*/', | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>راجع هذين المثالين: | |||
* [https://github.com/vercel/next.js/tree/canary/examples/custom-routes-proxying Incremental adoption of Next.js] | |||
* [https://github.com/vercel/next.js/tree/canary/examples/with-zones Using Multiple Zones] | |||
==== تبني Next.js تدريجيًا ==== | |||
يمكنك دفع Next.js للتراجع كي تلعب دور الوسيط لموقع ويب موجود بعد التحقق من كل وجهات Next.js. لا حاجة في هذه الحالة لتغيير إعدادات إعادة الكتابة عند نقل صفحات أكثر إلى Next.js.<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async rewrites() { | |||
return { | |||
fallback: [ | |||
{ | |||
source: '/:path*', | |||
destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`, | |||
}, | |||
], | |||
} | |||
}, | |||
} | |||
</syntaxhighlight>لمزيد من المعلومات راجع الصفحة "[[Next.js/migrating|الانتقال إلى Next.js]]" من هذا التوثيق. | |||
==== إعادة الكتابة مع دعم للمسار الأساسي ==== | |||
عند استخدام <code>basePath</code> مع إعادة الكتابة ستُضاف تلقائيًا البادئة إلى المعاملين <code>source</code> و <code>destination</code> ما لم تضف الإعداد <code>basePath: false</code> إلى دالة إعادة الكتابة:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
basePath: '/docs', | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/with-basePath', // /docs/with-basePath يصبج تلقائيًا | |||
destination: '/another', // /docs/another يصبح تلقائيًا | |||
}, | |||
{ | |||
//basePath: false لأن /without-basePath إلى /docs لا يضيف | |||
// لا يمكن استخدام ذلك في عمليات إعادة الكتابة الداخلية | |||
// destination: '/another' مثال | |||
source: '/without-basePath', | |||
destination: 'https://example.com', | |||
basePath: false, | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== إعادة الكتابة مع دعم التوجه i18n ==== | |||
عند استخدام <code>i18n</code> مع إعادة الكتابة ستُضاف تلقائيًا البادئة المهيأة مسبقًا <code>locales</code> إلى المعاملين <code>source</code> و <code>destination</code> ما لم تضف الإعداد <code>locale: false</code> إلى دالة إعادة الكتابة، وفي حال استخدامه لا بد من إضافة تلك البادئة يدويًا حتى تُطابق بشكل صحيح:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
i18n: { | |||
locales: ['en', 'fr', 'de'], | |||
defaultLocale: 'en', | |||
}, | |||
async rewrites() { | |||
return [ | |||
{ | |||
source: '/with-locale', // يتعامل مع الإعداد المحلي تلقائيًا | |||
destination: '/another', // يمرر الإعداد المحلي تلقائيًا | |||
}, | |||
{ | |||
// لا يُعالج الإعداد المحلي تلقائيًا | |||
source: '/nl/with-locale-manual', | |||
destination: '/nl/another', | |||
locale: false, | |||
}, | |||
{ | |||
// '/' يطابق | |||
// `en` لأن الإعداد المحلي الافتراضي | |||
source: '/en', | |||
destination: '/en/another', | |||
locale: false, | |||
}, | |||
{ | |||
// locale: false بإمكانك مطابقة جميع الإعدادات المحلية عندما يكون | |||
source: '/:locale/api-alias/:path*', | |||
destination: '/api/:path*', | |||
locale: false, | |||
}, | |||
{ | |||
// /(en|fr|de)/(.*) سيحول هذا إلى | |||
// لذا لن يُطابق المستوى الأعلى | |||
// `/` أو `/fr` | |||
source: '/(.*)', | |||
destination: '/another', | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>انظر المثال [https://github.com/vercel/next.js/tree/canary/examples/rewrites Rewrites]. | |||
== إعادة التوجيه == | |||
{| class="wikitable" | |||
|+سجل التغييرات | |||
!الإصدار | |||
!التغييرات | |||
|- | |||
|10.2.0 | |||
|إضافة <code>has</code> | |||
|- | |||
|9.5.0 | |||
|إضافة خاصية إعادة التوجيه | |||
|} | |||
يسمح لك إعادة التوجيه أن تحوّل مسار الطلب الوارد إلى وجهة مختلفة. ولاستخدام إعادة التوجيه، لا بد من إضافة المفتاح <code>redirects</code> إلى ملف التهيئة <code>next.config.js</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async redirects() { | |||
return [ | |||
{ | |||
source: '/about', | |||
destination: '/', | |||
permanent: true, | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>تُعد الدالة <code>redirects</code> دالة غير متزامنة تتوقع إعادة مصفوفة تضم كائنات تمتلك الخاصيات <code>source</code> و <code>destination</code> و <code>permanent</code>: | |||
* <code>source</code>: من النوع <code>String</code>، وهو نموذج مسار الطلب الوارد. | |||
* <code>destination</code>: من النوع <code>String</code>، وهو المسار الذي تريد التوجه إليه. | |||
* <code>permanent</code>: من النوع المنطقي، فإن كانت قيمتها <code>true</code> سيُستخدم رمز الحالة 308 الذي يملي على العميل أو محرك البحث تخزين إعادة التوجيه إلى ما لا نهاية. أما في حال كان <code>false</code> سيُستخدم رمز الحالة 307 وهو مؤقت ولا حاجة لتخزينه.<blockquote>قد تلاحظ استخدام رمز الحالة <code>307</code> لإعادة التوجه المؤقت و <code>308</code> لإعادة التوجه الدائم مع <code>()redirect</code>. وعلى الرغم من استخدام الرمزين <code>302</code> و <code>301</code> على الترتيب تقليديًا، إلا أن العديد من المتصفحات قد غيرت نوع طلب إعادة التوجه إلى <code>GET</code> بغض النظر عن أصول نوع الطلب. فلو أنشأ المتصفح طلبًا إلى <code>POST /v1/users</code> وأعاد رمز الحالة <code>302</code> مع الموقع <code>v2/users/</code>، فقد تكون الطلبات التالية من النوع <code>GET /v2/users</code> بدلًا من النوع المتوقع <code>POST /v2/users</code>. وبالتالي استخدمت Next.js رمزي الحالة 308 و 307 لحفظ نوع الطلب صراحة.</blockquote> | |||
* <code>basePath</code>: تأخذ أحد القيمتين <code>false</code> أو <code>undefined</code>، فإن كانت القيمة <code>false</code>، لن يضاف المسار الأساسي إلى العنوان عند المطابقة، ويستخد في إعادة الكتابة الخارجية. | |||
* <code>locale</code>: تأخذ أحد القيمتين <code>false</code> أو <code>undefined</code>، يحدد إن كان سُضاف الإعداد المحلي إلى المسار عند المطابقة. | |||
* <code>has</code>: مصفوفة من الكائنات <code>has objects</code> لها الخاصيات <code>type</code> و <code>key</code> و <code>value</code>. | |||
* <code>missing</code>: مصفوفة من كائنات لها الخاصيات <code>type</code> و <code>key</code> و <code>value</code>. | |||
يجري التحقق من عمليات إعادة التوجه قبل التحقق من نظام الملفات الذي يضم ملفات المجلدين <code>pages</code> و <code>public</code>. ولا تُطبَّق عمليات إعادة التوجيه على التوجيه من طرف العميل (<code>Link</code> أو <code>router.push</code>) إلا إن تدخلت [[Next.js/middleware|البرمجيات الوسيطة Middleware]] وطابقت المسار. | |||
عندما يُطبق إعادة التوجيه، ستُمرر أي قيم للاستعلام ضمن الطلب إلى الوجهة الجديدة. ألق نظرة على الإعدادات التالية:<syntaxhighlight lang="javascript"> | |||
{ | |||
source: '/old-blog/:path*', | |||
destination: '/blog/:path*', | |||
permanent: false | |||
} | |||
</syntaxhighlight>فعندما يكون الطلب من الشكل <code>old-blog/post-1?hello=world/</code> مثلًا سيُعاد توجيه العميل إلى <code>blog/post-1?hello=world/</code>. | |||
=== مطابقة المسارات === | |||
يُسمح بمطابقة المسارات كأن يُطابق المسار <code>blog/:slug/</code> المسار <code>blog/hello-world/</code> (دون تداخل في المسارات).<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async redirects() { | |||
return [ | |||
{ | |||
source: '/old-blog/:slug', | |||
destination: '/news/:slug', // Matched parameters can be used in the destination | |||
permanent: true, | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== مطابقة المسارات بوجود محارف بديلة ==== | |||
لمطابقة مسار باستخدام محارف بديلة، بإمكانك استعمال <code>*</code> بعد المعامل، إذ سيُطابق المسار <code>*blog/:slug/</code> مثلًا المسار <code>blog/a/b/c/d/hello-world/</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async redirects() { | |||
return [ | |||
{ | |||
source: '/blog/:slug*', | |||
destination: '/news/:slug*', // Matched parameters can be used in the destination | |||
permanent: true, | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== مطابقة المسارات من خلال التعابير النمطية Regex ==== | |||
لمطابقة مسار من خلال التعابير النمطية، غلِّف التعبير النمطي ضمن قوسين بعد المعامل. سيطابق المسار <code>post/:slug(\\d{1,})/</code> مثلًا المسار <code>post/123/</code> وليس المسار <code>post/abc/</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async redirects() { | |||
return [ | |||
{ | |||
source: '/post/:slug(\\d{1,})', | |||
destination: '/news/:slug', // Matched parameters can be used in the destination | |||
permanent: false, | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>تُستخدم المحارف التالية <code>(</code> و <code>)</code> و <code>{</code> و <code>}</code> و <code>:</code> و <code>*</code> و <code>+</code> و <code>?</code> في صياغة التعابير النمطية المستخدمة لمطابقة المسارات، فإن استُخدمت في الخاصية <code>source</code> كقيم غير خاصة non-special لا بد من تجاوزها بإضافة الصيغة <code>\\</code> قبلها:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async redirects() { | |||
return [ | |||
{ | |||
// this will match `/english(default)/something` being requested | |||
source: '/english\\(default\\)/:slug', | |||
destination: '/en-us/:slug', | |||
permanent: false, | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
=== مطابقة الترويسات وملفات تعريف الارتباط والاستعلام === | |||
بالإمكان مطابقة عملية إعادة كتابة عندما تُطابِق قيم الترويسات أو ملف تعريف الارتباط أو الاستعلام قيمة الحقل <code>has</code> فقط. أي يجب أن تتطابق الخاصية <code>source</code> وجميع عناصر <code>has</code> حتى تُطبَّق إعادة الكتابة. تمتلك العناصر <code>has</code> و <code>missing</code> الحقول التالية: | |||
* <code>type</code>: من النوع <code>String</code>، وسيكون إما <code>header</code> أو <code>cookie</code> أو <code>host</code> أو <code>query</code>. | |||
* <code>key</code>: من النوع <code>String</code>، مفتاح النوع المختار <code>type</code> الذي سيُطابق. | |||
* <code>value</code>: من النوع <code>String</code> أو <code>undefined</code>، القيمة التي سيجري التحقق منها، وإن كانت غير محددة ستُطابق أي قيمة. يمكن استخدام سلسلة نصية تشابه التعبير النمطي لالتقاط جزء محدد من القيمة. فإن استُخدمت القيمة <code>first-(?<paramName>.*)</code> لمطابقة <code>first-second</code>، ستتمكن حينها من استخدام <code>second</code> في الوجهة مع المعامل <code>:paramName</code>. | |||
<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async redirects() { | |||
return [ | |||
// if the header `x-redirect-me` is present, | |||
// this redirect will be applied | |||
{ | |||
source: '/:path((?!another-page$).*)', | |||
has: [ | |||
{ | |||
type: 'header', | |||
key: 'x-redirect-me', | |||
}, | |||
], | |||
permanent: false, | |||
destination: '/another-page', | |||
}, | |||
// if the header `x-dont-redirect` is present, | |||
// this redirect will be applied | |||
{ | |||
source: '/:path((?!another-page$).*)', | |||
missing: [ | |||
{ | |||
type: 'header', | |||
key: 'x-do-not-redirect', | |||
}, | |||
], | |||
permanent: false, | |||
destination: '/another-page', | |||
}, | |||
// if the source, query, and cookie are matched, | |||
// this redirect will be applied | |||
{ | |||
source: '/specific/:path*', | |||
has: [ | |||
{ | |||
type: 'query', | |||
key: 'page', | |||
// the page value will not be available in the | |||
// destination since value is provided and doesn't | |||
// use a named capture group e.g. (?<page>home) | |||
value: 'home', | |||
}, | |||
{ | |||
type: 'cookie', | |||
key: 'authorized', | |||
value: 'true', | |||
}, | |||
], | |||
permanent: false, | |||
destination: '/another/:path*', | |||
}, | |||
// if the header `x-authorized` is present and | |||
// contains a matching value, this redirect will be applied | |||
{ | |||
source: '/', | |||
has: [ | |||
{ | |||
type: 'header', | |||
key: 'x-authorized', | |||
value: '(?<authorized>yes|true)', | |||
}, | |||
], | |||
permanent: false, | |||
destination: '/home?authorized=:authorized', | |||
}, | |||
// if the host is `example.com`, | |||
// this redirect will be applied | |||
{ | |||
source: '/:path((?!another-page$).*)', | |||
has: [ | |||
{ | |||
type: 'host', | |||
value: 'example.com', | |||
}, | |||
], | |||
permanent: false, | |||
destination: '/another-page', | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== إعادة التوجيه مع دعم للمسار الأساسي basePath ==== | |||
عند استخدام <code>basePath</code> مع إعادة التوجيه ستُضاف تلقائيًا البادئة إلى المعاملين <code>source</code> و <code>destination</code> ما لم تضف الإعداد <code>basePath: false</code> إلى دالة إعادة التوجيه:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
basePath: '/docs', | |||
async redirects() { | |||
return [ | |||
{ | |||
source: '/with-basePath', // automatically becomes /docs/with-basePath | |||
destination: '/another', // automatically becomes /docs/another | |||
permanent: false, | |||
}, | |||
{ | |||
// does not add /docs since basePath: false is set | |||
source: '/without-basePath', | |||
destination: '/another', | |||
basePath: false, | |||
permanent: false, | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== إعادة التوجيه مع دعم التوجه i18n ==== | |||
عند استخدام <code>i18n</code> مع إعادة الكتابة ستُضاف تلقائيًا البادئة المهيأة مسبقًا <code>locales</code> إلى المعاملين <code>source</code> و <code>destination</code> ما لم تضف الإعداد <code>locale: false</code> إلى دالة إعادة التوجيه، وفي حال استخدامه لا بد من إضافة تلك البادئة يدويًا حتى تُطابق بشكل صحيح:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
i18n: { | |||
locales: ['en', 'fr', 'de'], | |||
defaultLocale: 'en', | |||
}, | |||
async redirects() { | |||
return [ | |||
{ | |||
source: '/with-locale', // automatically handles all locales | |||
destination: '/another', // automatically passes the locale on | |||
permanent: false, | |||
}, | |||
{ | |||
// does not handle locales automatically since locale: false is set | |||
source: '/nl/with-locale-manual', | |||
destination: '/nl/another', | |||
locale: false, | |||
permanent: false, | |||
}, | |||
{ | |||
// this matches '/' since `en` is the defaultLocale | |||
source: '/en', | |||
destination: '/en/another', | |||
locale: false, | |||
permanent: false, | |||
}, | |||
// it's possible to match all locales even when locale: false is set | |||
{ | |||
source: '/:locale/page', | |||
destination: '/en/newpage', | |||
permanent: false, | |||
locale: false, | |||
} | |||
{ | |||
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level | |||
// `/` or `/fr` routes like /:path* would | |||
source: '/(.*)', | |||
destination: '/another', | |||
permanent: false, | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>قد تحتاج في حالات نادرة تعيين رموز حالة مخصصة لعملاء HTTP الأقدم كي يُعاد توجيههم بالشكل الصحيح. في حالات كهذه، استخدم الخاصية <code>statusCode</code> بدلًا من <code>permanent</code> لكن لا تستخدمهما معًا. تجدر الإشارة إلى إضافة الترويسة <code>Refresh</code> تلقائيًا إلى رمز الحالة 308 لضمان التوافق مع المتصفح IE11. | |||
=== أنواع أخرى لإعادة التوجيه === | |||
* بإمكانك استخدام <code>()res.redirect</code> ضمن وجهات API. | |||
* يمكنك إعاة توجيه صفحات محددة عند الطلب ضمن <code>getStaticProps</code> و <code>getServerSideProps</code>. | |||
انظر مثال [https://github.com/vercel/next.js/tree/canary/examples/redirects Redirects]. | |||
== الترويسات == | |||
{| class="wikitable" | |||
|+سجل التغييرات | |||
!الإصدار | |||
!التغييرات | |||
|- | |||
|10.2.0 | |||
|إضافة <code>has</code> | |||
|- | |||
|9.5.0 | |||
|إضافة خاصية الترويسات | |||
|} | |||
تتيح لك إعداد ترويسات HTTP مخصصة عند الاستجابة إلى طلب وارد عبر مسار معين. ولإعداد ترويسة مخصصة، استخدم المفتاح <code>headers</code> ضمن الملف <code>next.config.js</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async headers() { | |||
return [ | |||
{ | |||
source: '/about', | |||
headers: [ | |||
{ | |||
key: 'x-custom-header', | |||
value: 'my custom header value', | |||
}, | |||
{ | |||
key: 'x-another-custom-header', | |||
value: 'my other custom header value', | |||
}, | |||
], | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>تُعد الدالة <code>headers</code> دالة غير متزامنة تتوقع إعادة مصفوفة تضم كائنات تمتلك الخاصيات <code>source</code> و <code>headers</code>: | |||
* <code>source</code>: من النوع <code>String</code>، وهو نموذج مسار الطلب الوارد. | |||
* <code>headers</code>: مصفوفة من كائنات ترويسة الاستجابة، ولها الخاصيتان <code>key</code> و <code>value</code>. | |||
* <code>basePath</code>: تأخذ أحد القيمتين <code>false</code> أو <code>undefined</code>، فإن كانت القيمة <code>false</code>، لن يضاف المسار الأساسي إلى العنوان عند المطابقة، ويستخدم في إعادة الكتابة الخارجية. | |||
* <code>locale</code>: تأخذ أحد القيمتين <code>false</code> أو <code>undefined</code>، يحدد إن كان سُضاف الإعداد المحلي إلى المسار عند المطابقة. | |||
* <code>has</code>: مصفوفة من الكائنات <code>has objects</code> لها الخاصيات <code>type</code> و <code>key</code> و <code>value</code>. | |||
* <code>missing</code>: مصفوفة من كائنات لها الخاصيات <code>type</code> و <code>key</code> و <code>value</code>. | |||
يجري التحقق من الترويسات قبل التحقق من منظومة الملفات التي تضم ملفات المجلدين <code>pages</code> و <code>public</code>. | |||
=== سلوك الإلغاء في الترويسات === | |||
إن تطابقت ترويستان مع المسار ذاته واستهدفتا نفس المفتاح، سيُلغي مفتاح الترويسة الأخيرة مفتاح الأولى ويحل محله. في المثال التالي، سينتج المسار <code>hello/</code> عن الترويسة <code>x-hello</code> التي قيمتها <code>world</code> لأنها الترويسة الأخيرة من ترويستين لهما نفس المفتاح <code>x-hello</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async headers() { | |||
return [ | |||
{ | |||
source: '/:path*', | |||
headers: [ | |||
{ | |||
key: 'x-hello', | |||
value: 'there', | |||
}, | |||
], | |||
}, | |||
{ | |||
source: '/hello', | |||
headers: [ | |||
{ | |||
key: 'x-hello', | |||
value: 'world', | |||
}, | |||
], | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
=== مطابقة المسارات === | |||
يُسمح بمطابقة المسارات كأن يُطابق المسار <code>blog/:slug/</code> المسار <code>blog/hello-world/</code> (دون تداخل في المسارات).<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async headers() { | |||
return [ | |||
{ | |||
source: '/blog/:slug', | |||
headers: [ | |||
{ | |||
key: 'x-slug', | |||
value: ':slug', // Matched parameters can be used in the value | |||
}, | |||
{ | |||
key: 'x-slug-:slug', // Matched parameters can be used in the key | |||
value: 'my other custom header value', | |||
}, | |||
], | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== مطابقة المسارات بوجود محارف بديلة ==== | |||
لمطابقة مسار باستخدام محارف بديلة، بإمكانك استعمال <code>*</code> بعد المعامل، إذ سيُطابق المسار <code>*blog/:slug/</code> مثلًا المسار <code>blog/a/b/c/d/hello-world/</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async headers() { | |||
return [ | |||
{ | |||
source: '/blog/:slug*', | |||
headers: [ | |||
{ | |||
key: 'x-slug', | |||
value: ':slug*', // Matched parameters can be used in the value | |||
}, | |||
{ | |||
key: 'x-slug-:slug*', // Matched parameters can be used in the key | |||
value: 'my other custom header value', | |||
}, | |||
], | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== مطابقة المسارات من خلال التعابير النمطية Regex ==== | |||
لمطابقة مسار من خلال التعابير النمطية، غلِّف التعبير النمطي ضمن قوسين بعد المعامل. سيطابق المسار <code>blog/:slug(\\d{1,})/</code> مثلًا المسار <code>blog/123/</code> وليس المسار <code>blog/abc/</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async headers() { | |||
return [ | |||
{ | |||
source: '/blog/:post(\\d{1,})', | |||
headers: [ | |||
{ | |||
key: 'x-post', | |||
value: ':post', | |||
}, | |||
], | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight>تُستخدم المحارف التالية <code>(</code> و <code>)</code> و <code>{</code> و <code>}</code> و <code>:</code> و <code>*</code> و <code>+</code> و <code>?</code> في صياغة التعابير النمطية المستخدمة لمطابقة المسارات، فإن استُخدمت في الخاصية <code>source</code> كقيم غير خاصة non-special لا بد من تجاوزها بإضافة الصيغة <code>\\</code> قبلها:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async headers() { | |||
return [ | |||
{ | |||
// this will match `/english(default)/something` being requested | |||
source: '/english\\(default\\)/:slug', | |||
headers: [ | |||
{ | |||
key: 'x-header', | |||
value: 'value', | |||
}, | |||
], | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
=== مطابقة الترويسات وملفات تعريف الارتباط والاستعلام === | |||
بالإمكان مطابقة ترويسة عندما تُطابِق قيم ترويسة أو ملف تعريف الارتباط أو الاستعلام قيمة الحقل <code>has</code> فقط. أي يجب أن تتطابق الخاصية <code>source</code> وجميع عناصر <code>has</code> حتى تُطبَّق إعادة الكتابة. تمتلك العناصر <code>has</code> و <code>missing</code> الحقول التالية: | |||
* <code>type</code>: من النوع <code>String</code>، وسيكون إما <code>header</code> أو <code>cookie</code> أو <code>host</code> أو <code>query</code>. | |||
* <code>key</code>: من النوع <code>String</code>، مفتاح النوع المختار <code>type</code> الذي سيُطابق. | |||
* <code>value</code>: من النوع <code>String</code> أو <code>undefined</code>، القيمة التي سيجري التحقق منها، وإن كانت غير محددة ستُطابق أي قيمة. يمكن استخدام سلسلة نصية تشابه التعبير النمطي لالتقاط جزء محدد من القيمة. فإن استُخدمت القيمة <code>first-(?<paramName>.*)</code> لمطابقة <code>first-second</code>، ستتمكن حينها من استخدام <code>second</code> في الوجهة مع المعامل <code>:paramName</code>. | |||
<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
async headers() { | |||
return [ | |||
// if the header `x-add-header` is present, | |||
// the `x-another-header` header will be applied | |||
{ | |||
source: '/:path*', | |||
has: [ | |||
{ | |||
type: 'header', | |||
key: 'x-add-header', | |||
}, | |||
], | |||
headers: [ | |||
{ | |||
key: 'x-another-header', | |||
value: 'hello', | |||
}, | |||
], | |||
}, | |||
// if the header `x-no-header` is not present, | |||
// the `x-another-header` header will be applied | |||
{ | |||
source: '/:path*', | |||
missing: [ | |||
{ | |||
type: 'header', | |||
key: 'x-no-header', | |||
}, | |||
], | |||
headers: [ | |||
{ | |||
key: 'x-another-header', | |||
value: 'hello', | |||
}, | |||
], | |||
}, | |||
// if the source, query, and cookie are matched, | |||
// the `x-authorized` header will be applied | |||
{ | |||
source: '/specific/:path*', | |||
has: [ | |||
{ | |||
type: 'query', | |||
key: 'page', | |||
// the page value will not be available in the | |||
// header key/values since value is provided and | |||
// doesn't use a named capture group e.g. (?<page>home) | |||
value: 'home', | |||
}, | |||
{ | |||
type: 'cookie', | |||
key: 'authorized', | |||
value: 'true', | |||
}, | |||
], | |||
headers: [ | |||
{ | |||
key: 'x-authorized', | |||
value: ':authorized', | |||
}, | |||
], | |||
}, | |||
// if the header `x-authorized` is present and | |||
// contains a matching value, the `x-another-header` will be applied | |||
{ | |||
source: '/:path*', | |||
has: [ | |||
{ | |||
type: 'header', | |||
key: 'x-authorized', | |||
value: '(?<authorized>yes|true)', | |||
}, | |||
], | |||
headers: [ | |||
{ | |||
key: 'x-another-header', | |||
value: ':authorized', | |||
}, | |||
], | |||
}, | |||
// if the host is `example.com`, | |||
// this header will be applied | |||
{ | |||
source: '/:path*', | |||
has: [ | |||
{ | |||
type: 'host', | |||
value: 'example.com', | |||
}, | |||
], | |||
headers: [ | |||
{ | |||
key: 'x-another-header', | |||
value: ':authorized', | |||
}, | |||
], | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== الترويسات مع دعم للمسار الأساسي basePath ==== | |||
عند استخدام <code>basePath</code> مع إعادة الترويسات ستُضاف تلقائيًا البادئة إلى المعامل <code>source</code> ما لم تضف الإعداد <code>basePath: false</code> إلى دالة الترويسة:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
basePath: '/docs', | |||
async headers() { | |||
return [ | |||
{ | |||
source: '/with-basePath', // becomes /docs/with-basePath | |||
headers: [ | |||
{ | |||
key: 'x-hello', | |||
value: 'world', | |||
}, | |||
], | |||
}, | |||
{ | |||
source: '/without-basePath', // is not modified since basePath: false is set | |||
headers: [ | |||
{ | |||
key: 'x-hello', | |||
value: 'world', | |||
}, | |||
], | |||
basePath: false, | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== إعادة التوجيه مع دعم التوجه i18n ==== | |||
عند استخدام <code>i18n</code> مع الترويسات ستُضاف تلقائيًا البادئة المهيأة مسبقًا <code>locales</code> إلى المعامل <code>source</code> ما لم تضف الإعداد <code>locale: false</code> إلى الترويسة. وفي حال استخدامه لا بد من إضافة تلك البادئة يدويًا حتى تُطابق بشكل صحيح:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
i18n: { | |||
locales: ['en', 'fr', 'de'], | |||
defaultLocale: 'en', | |||
}, | |||
async headers() { | |||
return [ | |||
{ | |||
source: '/with-locale', // automatically handles all locales | |||
headers: [ | |||
{ | |||
key: 'x-hello', | |||
value: 'world', | |||
}, | |||
], | |||
}, | |||
{ | |||
// does not handle locales automatically since locale: false is set | |||
source: '/nl/with-locale-manual', | |||
locale: false, | |||
headers: [ | |||
{ | |||
key: 'x-hello', | |||
value: 'world', | |||
}, | |||
], | |||
}, | |||
{ | |||
// this matches '/' since `en` is the defaultLocale | |||
source: '/en', | |||
locale: false, | |||
headers: [ | |||
{ | |||
key: 'x-hello', | |||
value: 'world', | |||
}, | |||
], | |||
}, | |||
{ | |||
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level | |||
// `/` or `/fr` routes like /:path* would | |||
source: '/(.*)', | |||
headers: [ | |||
{ | |||
key: 'x-hello', | |||
value: 'world', | |||
}, | |||
], | |||
}, | |||
] | |||
}, | |||
} | |||
</syntaxhighlight> | |||
==== الترويسة <code>Cache-Control</code> ==== | |||
يمكن إعداد الترويسة <code>Cache-Control</code> ضمن وجهات API الخاصة بتطبيقك عن طريق التابع <code>res.setHeader</code>: <syntaxhighlight lang="javascript"> | |||
// pages/api/user.js | |||
export default function handler(req, res) { | |||
res.setHeader('Cache-Control', 's-maxage=86400') | |||
res.status(200).json({ name: 'John Doe' }) | |||
} | |||
</syntaxhighlight>لا يمكن إعداد ترويسات <code>Cache-Control</code> ضمن الملف <code>next.config.js</code> لأنها ستُلغى عند بناء نسخة الإنتاج، وذلك للتأكد من التخزين الفعّال لوجهات API والموجودات الساكنة static assets. | |||
إن أردت إعادة التحقق من الذاكرة المؤقتة لصفحة وُلِّدت بشكل ساكن، عليك ضبط الخاصية <code>revalidate</code> ضمن الدالة <code>getStaticProps</code> في الصفحة. | |||
== الامتدادات المخصصة للصفحات == | |||
وجهت هذه الامتدادات إلى وحدات برمجية مثل التي تضيف دعمًا للصفحات التي تحمل الامتداد. يمكن أن تهيئ الامتدادات التي يجري البحث عنها ضمن المجلد <code>pages</code> عند تحليل الصفحة بفتح الملف <code>next.config.js</code> وإضافة الإعداد <code>pageExtensions</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
pageExtensions: ['mdx', 'md', 'jsx', 'js', 'tsx', 'ts'], | |||
} | |||
</syntaxhighlight>القيم الافتراضية للإعداد <code>pageExtensions</code> هي <code>['tsx', 'ts', 'jsx', 'js']</code>. | |||
يؤثر تهيئة الإعداد <code>pageExtensions</code> على كل الصفحات بما فيها: | |||
* <code>middleware.js</code> | |||
* <code>pages/_document.js</code> | |||
* <code>pages/_app.js</code> | |||
* <code>/pages/api</code> | |||
إذ يعني مثلًا الإعداد <code>['page.tsx', 'page.ts']:pageExtensions</code>، أن جميع الملفات مثل <code>app.tsx_</code> ينبغي أن تُعاد تسميتها إلى <code>app.page.tsx_</code> و <code>middleware.page.ts</code> و <code>pages/users.page.tsx</code> مثلًا. | |||
=== تضمين الملفات من غير الصفحات في المجلد <code>pages</code> === | |||
لكي تشير إلى الموقع المشترك لملفات الاختبار والملفات المولَّدة وغيرها من الملفات التي تستخدمها المكوّنات في المجلد <code>pages</code>، بإمكانك وضع بادئة قبل الامتداد مثل <code>page</code>. افتح الملف <code>next.config.js</code> وأضف الإعداد <code>pageExtensions</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js'], | |||
} | |||
</syntaxhighlight>أعد بعد ذلك تسمية صفحاتك لتضيف <code>page.</code> إلى امتداداتها (غير اسم الملف <code>MyPage.tsx</code> مثلًا إلى <code>MyPage.page.tsx</code>)<blockquote>'''ملاحظة''': تأكد من إعادة تسمية الملفات <code>document.js_</code> و <code>app.js_</code> و <code>middleware.js</code> بالإضافة إلى الملفات الموجودة ضمن <code>pages/api</code>.</blockquote> | |||
== شبكة إيصال المحتوى CDN مع الخيار <code>assetPrefix</code> == | |||
<blockquote>'''تنبيه''': يهيئ النشر على Vercel تلقائيًا شبكة إيصال محتوى CDN لمشروع Next.js. لا حاجة لإعداد الخيار <code>assetPrefix</code> يدويًا.</blockquote><blockquote>'''ملاحظة''': تدعم Next.js ابتداءً من النسخة +9.5 تخصيص مسار أساسي للتطبيق basePath، وهذا يلائم استضافة تطبيقك ضمن مسار فرعي مثل <code>docs/</code>. لا حاجة في هذه الحالة إلى استخدام <code>assetPrefix</code>.</blockquote>لإعداد [https://academy.hsoub.com/devops/cloud-computing/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%AA%D8%B3%D9%84%D9%8A%D9%85-%D8%A7%D9%84%D9%85%D8%AD%D8%AA%D9%88%D9%89-cdn-%D9%84%D8%AA%D8%B3%D8%B1%D9%8A%D8%B9-%D8%AA%D8%B3%D9%84%D9%8A%D9%85-%D8%A7%D9%84%D9%85%D8%AD%D8%AA%D9%88%D9%89-%D8%A7%D9%84%D8%AB%D8%A7%D8%A8%D8%AA-r393/ شبكة إيصال محتوى CDN] يمكنك إعداد بادئة خاصة بالموجودات asset prefix وتهيئة أصل شبكة CDN لتحلل النطاق الذي يستضيف تطبيق Next.js. افتح الملف <code>next.config.js</code> وأضف الإعداد <code>assetPrefix</code>:<syntaxhighlight lang="javascript"> | |||
const isProd = process.env.NODE_ENV === 'production' | |||
module.exports = { | |||
// استخدم شبكة إيصال المحتوى عند الإنتاج و الخادم المحلي عند التطوير | |||
assetPrefix: isProd ? 'https://cdn.mydomain.com' : '', | |||
} | |||
</syntaxhighlight>تستخدم تلقائيًا بادئة الموجودات لملفات JavaScript و CSS والتي تُحمَّل من المسار <code>/_next/</code> (المجلد <code>/next/static.</code>). سيصبح الطلب التالي:<syntaxhighlight lang="bash"> | |||
/_next/static/chunks/4b9b41aaa062cbbfeff4add70f256968c51ece5d.4d708494b3aed70c04f0.js | |||
</syntaxhighlight>لجزء من شيفرة JS مثلًا وفق الإعداد السابق كما يلي:<syntaxhighlight lang="bash"> | |||
https://cdn.mydomain.com/_next/static/chunks/4b9b41aaa062cbbfeff4add70f256968c51ece5d.4d708494b3aed70c04f0.js | |||
</syntaxhighlight> | |||
ستعتمد التهيئة الدقيقة لرفع ملفاتك إلى منظومة إيصال محتوى على المنظومة التي تختارها، وسيكون المجلد الوحيد الذي عليك استضافته على منظومة إيصال المحتوى هو محتوى المجلد <code>/next/static.</code> الذي ينبغي رفعه ليكون على الشكل <code>/next/static_</code> كما يشير طلب URL. لا ترفع بقية ملفات المجلد <code>/next.</code> فمن الخطأ عرض شيفرة الخادم وبقية الإعدادات للعموم. | |||
على الرغم من أنّ الإعداد <code>assetPrefix</code> يغطي الطلبات إلى <code>/next/static_</code> لكنه لا يؤثر بالمسارات التالية: | |||
* الملفات في المجلد [[Next.js/static file serving|public]]، فإن أردت تخديم هذه الموجودات عبر CDN، عليك تقديم البادئة بنفسك. | |||
* طلبات <code>/next/data/_</code> إلى صفحات <code>getServerSideProps</code>. إذ توجّه هذه الطلبات إلى النطاق الأساسي لكونها غير ساكنة. | |||
* طلبات <code>/next/data/_</code> إلى صفحات <code>getStaticProps</code>. إذ توجّه هذه الطلبات إلى النطاق الأساسي لدعم التوليد التدريجي الساكن حتى لو لم تكن تستخدمه (لأغراض الترابط). | |||
== الإعدادات المخصصة لمحزّم Webpack == | |||
<blockquote>'''ملاحظة''': لم تُغطى التغييرات في إعداد webpack بواسطة مخططات الإصدار SemVer لهذا تابع على مسؤوليتك الشخصية.</blockquote>قبل أن تتابع بإضافة إعدادات webpack مخصصة إلى تطبيقك تأكد أولًا من عدم دعم Next.js للحالة التي تواجهك: | |||
* [[Next.js/built in css support|CSS imports]] | |||
* [[Next.js/built in css support|CSS modules]] | |||
* [[Next.js/built in css support|Sass/SCSS imports]] | |||
* [[Next.js/built in css support|Sass/SCSS modules]] | |||
* [https://github.com/vercel/next.js/tree/canary/examples/using-preact preact] | |||
* [[Next.js/customizing babel config|Customizing babel configuration]] | |||
تتاح بعض الميزات التي تُطلب بكثرة على شكل إضافات: | |||
* [https://github.com/vercel/next.js/tree/canary/packages/next-mdx next/mdx@] | |||
* [https://github.com/vercel/next.js/tree/canary/packages/next-bundle-analyzer next/bundle-analyzer@] | |||
لكي توسّع طريقة استخدامنا لمحزّم <code>webpack</code>، بإمكانك تعريف دالة توسّع إعداداته ضمن الملف <code>next.config.js</code> كالتالي:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
webpack: ( | |||
config, | |||
{ buildId, dev, isServer, defaultLoaders, nextRuntime, webpack } | |||
) => { | |||
// Important: return the modified config | |||
return config | |||
}, | |||
} | |||
</syntaxhighlight><blockquote>تُنفَّذ الدالة <code>webpack</code> مرتين، الأولى للخادم والثانية للعميل. يتيح لك ذلك التمييز بين إعدادات الخادم والعميل من خلال الخاصية <code>isServer</code>. </blockquote>إن الوسيط الثاني للدالة <code>webpack</code> هو كائن له الخاصيات التالية: | |||
* <code>buildId</code>: من النوع <code>string</code>، معرّف البناء، ويُستخدم كمعرّف فريد بين نسخ البناء. | |||
* <code>dev</code>: قيمة منطقية تشير إلى أنّ التصريف سيجري في بيئة التطوير أم لا. | |||
* <code>isServer</code>: قيمة منطقية <code>true</code> إن كان التصريف من جانب الخادم و <code>false</code> من جانب العميل. | |||
* <code>nextRuntime</code>: من أحد النوعين <code>String | undefined</code>، وتحدد منصة تنفيذ الشيفرة عندما يجري التصريف من جانب الخادم وتاخذ إحدى القيمتين <code>"edge"</code> أو <code>"nodejs"</code> بينما تأخذ القيمة <code>undefined</code> عند التصريف من جانب العميل. | |||
* <code>defaultLoaders</code>: من النوع <code>object</code>، وتشير إلى المحمّلات الافتراضية في تستخدم داخليًا في Next.js: | |||
**<code>babel</code>: من النوع <code>object</code> وتحمّل تهيئة <code>babel-loader</code> | |||
إليك مثال عن استخدام <code>defaultLoaders.babel</code>:<syntaxhighlight lang="javascript"> | |||
//babel-loader مثال عن إضافة محمّل يعتمد على | |||
// @next/mdx المصدر مأخوذ من الإضافة | |||
// https://github.com/vercel/next.js/tree/canary/packages/next-mdx | |||
module.exports = { | |||
webpack: (config, options) => { | |||
config.module.rules.push({ | |||
test: /\.mdx/, | |||
use: [ | |||
options.defaultLoaders.babel, | |||
{ | |||
loader: '@mdx-js/loader', | |||
options: pluginOptions.options, | |||
}, | |||
], | |||
}) | |||
return config | |||
}, | |||
} | |||
</syntaxhighlight> | |||
=== الخاصية <code>nextRuntime</code>=== | |||
تأخذ <code>isServer</code> القيمة <code>true</code> عندما تكون قيمة <code>nextRuntime</code> هي <code>"edge"</code> أو <code>"nodejs"</code>. وتستخدم الحالة التي تكون فيها قيمة <code>nextRuntime</code> هي <code>edge</code> حاليًا مع البرمجيات الوسطية middleware ومكوّنات الخادم في منصة التشغيل المتقدمة edge فقط. | |||
== ضغط المحتوى == | |||
تستخدم Next.js تقنية '''gzip''' لضغط المحتوى المصيّر والملفات الساكنة. ستحتاج عمومًا لتفعيل الضغط على خوادم HTTP الوكيلة مثل nginx لتفريغ حمولة عملية <code>Node.js</code>. | |||
لإلغاء الضغط، افتح الملف <code>next.config.js</code> وعطّل الخيار <code>compress</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
compress: false, | |||
} | |||
</syntaxhighlight> | |||
== إعداد مرحلة التشغيل == | |||
<blockquote>'''ملاحظة''': تحتاج عمومًا إلى استخدام [[Next.js/environment variables|متغيرات البيئة في زمن التشغيل]] لتطبيق إعداداتك، لأن إعدادات زمن التشغيل تضيف إعدادات التصيير أو التهيئة مسبقًا وهذا لا يتوافق مع التحسين التلقائي الساكن.</blockquote>لإضافة إعدادات زمن التشغيل إلى التطبيق، افتح الملف <code>next.config.js</code> وأضف الإعدادين <code>publicRuntimeConfig</code> و <code>serverRuntimeConfig</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
serverRuntimeConfig: { | |||
// يُتاح فقط من جانب الخادم | |||
mySecret: 'secret', | |||
secondSecret: process.env.SECOND_SECRET, // يُمرر عبر متغيرات البيئة | |||
}, | |||
publicRuntimeConfig: { | |||
// سيكون متاحًا في جانبي الخادم والعميل | |||
staticFolder: '/static', | |||
}, | |||
} | |||
</syntaxhighlight>ضع أية إعدادات تتعلق بزمن التشغيل على الخادم ضمن<code>serverRuntimeConfig</code>، وأية إعدادات يمكن الوصول إليها في جانبي الخادم و العميل ضمن <code>publicRuntimeConfig</code>.<blockquote>إن اعتمدت الصفحة على <code>publicRuntimeConfig</code> فيجب أن تستخدم <code>getInitialProps</code> أو <code>getServerSideProps</code> أو يجب أن يمتلك التطبيق مكوّن [[Next.js/custom app|<code>App</code> مخصص]] مع <code>getInitialProps</code> كي لا تستخدم التحسين التقائي الساكن. لا يمكن استخدام إعدادات زمن التشغيل في أي صفحة أو مكوّن ما لم يُصيّر في جانب الخادم.</blockquote>للوصول إلى إعدادات زمن التشغيل في تطبيقك، استخدم <code>next/config</code> كالتالي:<syntaxhighlight lang="javascript"> | |||
import getConfig from 'next/config' | |||
import Image from 'next/image' | |||
//publicRuntimeConfig و serverRuntimeConfig يضم فقط | |||
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig() | |||
// يتاح فقط في جانب الخادم | |||
console.log(serverRuntimeConfig.mySecret) | |||
// يُتاح في كلا الجانبين | |||
console.log(publicRuntimeConfig.staticFolder) | |||
function MyImage() { | |||
return ( | |||
<div> | |||
<Image | |||
src={`${publicRuntimeConfig.staticFolder}/logo.png`} | |||
alt="logo" | |||
layout="fill" | |||
/> | |||
</div> | |||
) | |||
} | |||
export default MyImage | |||
</syntaxhighlight> | |||
== تعطيل الترويسة <code>x-powered-by</code> == | |||
تضيف Next.js الترويسة <code>x-powered-by</code> افتراضيًا. لإلغاء الأمر، افتح الملف <code>next.config.js</code> وعطّل الإعداد <code>poweredByHeader</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
poweredByHeader: false, | |||
} | |||
</syntaxhighlight> | |||
== تعطيل ترويسة الاستجابة ETag == | |||
تولّد Next.js الترويسة [[wikipedia:HTTP_ETag|etags]] لكل صفحة افتراضيًا، وقد ترغب في تعطيل هذه الميزة في بعض الصفحات وفقًا للاستراتيجية التي تستخدمها في التخزين المؤقت، لهذا، افتح الملف <code>next.config.js</code> وعطّل الإعداد <code>generateEtags</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
generateEtags: false, | |||
} | |||
</syntaxhighlight> | |||
== تعطيل تحديد مدة الإبقاء على اتصال HTTP == | |||
[[Next.js/supported browsers features|توائم Next.js آلية إحضار البيانات في node]] لهذا تمكّن تحديد مدة الإبقاء على اتصال HTTP افتراضيًا HTTP Keep-Alive. إن كنت ترغب في تعطيل هذا الإعداد لاستدعاء معين مفرد للدالة <code>()fetch</code> أضف الخيار <code>Agent</code> كالتالي:<syntaxhighlight lang="javascript"> | |||
import { Agent } from 'https' | |||
const url = 'https://example.com' | |||
const agent = new Agent({ keepAlive: false }) | |||
fetch(url, { agent }) | |||
</syntaxhighlight>ولإلغاء جميع استدعاءات <code>()fetch</code> عمومًا استخدم ملف التهيئة <code>next.config.js</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
httpAgentOptions: { | |||
keepAlive: false, | |||
}, | |||
} | |||
</syntaxhighlight> | |||
== إعداد مجلد بناء مخصص == | |||
يمكن اختيار الاسم الذي تريده لمجلد بناء مخصص بدلًا من استخدام <code>next.</code>. فإن أردت ذلك، افتح الملف <code>next.config.js</code> وأضف الإعداد <code>distDir</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
distDir: 'build', | |||
} | |||
</syntaxhighlight>إن نفّذت الآن الأمر <code>next build</code>، ستستخدم Next.js المجلد <code>build</code> بدلًا من المجلد <code>next.</code> الافتراضي. | |||
'''ملاحظة''': لا يجب أن يقع المجلد خارج مجلد المشروع، فلا يجب أن يكون <code>buid/..</code> مثلًا. | |||
== إعداد معرف فريد للنسخ == | |||
تستخدم Next.js معرّفًا ثابتًا فريدًا ID أثناء بناء التطبيق لتحديد الإصدار الذي يُخدّم من تطبيقك. قد يسبب هذا الأمر المشاكل عند نشر التطبيق على عدة خوادم ثم يُنفَّذ الأمر <code>next build</code> على كل خادم. ولكي تحافظ على معرّف النسخ على جميع الخوادم يمكنك تحديد معرّفًا خاصًا بك للنسخة. | |||
لتنفيذ الأمر، افتح الملف <code>next.config.js</code> وأضف الدالة <code>generateBuildId</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
generateBuildId: async () => { | |||
// You can, for example, get the latest git commit hash here | |||
return 'my-build-id' | |||
}, | |||
} | |||
</syntaxhighlight> | |||
== إعداد الخيار <code>onDemandEntries</code> == | |||
تعرض بعض الخيارات التي تتيح لك التحكم بكيفية تخلص الخادم أو إبقائه لبعض الصفحات المبنية في الذاكرة أثناء التطوير. | |||
لتغيير الإعداد الافتراضي، افتح الملف <code>next.config.js</code> وأضف الإعداد <code>onDemandEntries</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
onDemandEntries: { | |||
//(ميلي ثانية) الفترة التي التي يبقي فيها الخادم الصفحات في الذاكرة | |||
maxInactiveAge: 25 * 1000, | |||
// عد الصفحات التي يجب إبقاؤها معًا دون أن تُلغى | |||
pagesBufferLength: 2, | |||
}, | |||
} | |||
</syntaxhighlight> | |||
== تجاهل المدقق ESLint == | |||
عندما تكتشف Next.js وجود ESLint في تطبيقك فإنها تُحبط عملية البناء <code>next build</code> عند وجود أي خطأ مصدره المدقق ESLint. لكن إن أردت من Next.js أن تبني نسخة إنتاج حتى لو وجودت أخطاء مصدرها ESLint، يمكنك تعطيل خطوة التدقيق المدمجة بالكامل. لا ننصحك بهذا الخيار إلا إن كنت قد هيأت مسبقًا ESLint ليعمل ضمن مرحلة أخرى من مراحل عملك (كمرحلة التكامل المتواصل CI). | |||
لتعطيل ESLint، افتح الملف <code>next.config.js</code> ومكِّن الخيار <code>ignoreDuringBuilds</code> ضمن الإعداد <code>eslint</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
eslint: { | |||
// ESLint يسمح ذلك بنجاح بناء التطبيق حتى لو كانت هناك أخطاء في المدقق | |||
ignoreDuringBuilds: true, | |||
}, | |||
} | |||
</syntaxhighlight> | |||
== تجاهل أخطاء TypeScript == | |||
تُحبط Next.js عملية البناء <code>next build</code> عند وجود أي خطأ مصدره TypeScript. لكن إن أردت من Next.js أن تبني نسخة إنتاج حتى لو وجودت أخطاء مصدرها TypeScript (وهذا أمر خطر)، يمكنك تعطيل خطوة التحقق المدمجة من أخطاء TypeScript بالكامل. | |||
تأكد عند تعطيل تلك الخطوة، أنك ستتحقق من الأنواع خلال عملية البناء أو النشر، وإلا كان عملك محفوفًا بالمخاطر. | |||
افتح الملف <code>next.config.js</code> ومكّن الخيار <code>ignoreBuildErrors</code> ضمن الإعداد <code>typescript</code><syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
typescript: { | |||
// !! تحذير !! | |||
// Typescript يسمح ذلك بنجاح بناء التطبيق حتى لو كانت هناك أخطاء في | |||
ignoreBuildErrors: true, | |||
}, | |||
} | |||
</syntaxhighlight> | |||
== استخدام الإعداد <code>exportPathMap</code> == | |||
<blockquote>هذه الميزة محصورة باستخدام <code>next export</code>. عد إلى الصفحة "[[Next.js/static html export|تصدير التطبيق إلى صفحات HTML ساكنة]]" من هذا التوثيق. </blockquote>يتيح لك هذا الإعداد تحديد علاقة بين مسارات الطلب وصفحات الوجهة، كي تُستخدم أثناء التصدير. تُتاح المسارات المعرّفة داخل الإعداد <code>exportPathMap</code> أيضًا عند تنفيذ الأمر <code>next dev</code>. | |||
لنبدأ بمثال بسيط لإنشاء شبكة علاقات <code>exportPathMap</code> مخصصة لتطبيق يضم الصفحات التالية: | |||
* <code>pages/index.js</code> | |||
* <code>pages/about.js</code> | |||
* <code>pages/post.js</code> | |||
افتح الملف وأضف الشيفرة التالية ضمن الإعداد <code>exportPathMap</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
exportPathMap: async function ( | |||
defaultPathMap, | |||
{ dev, dir, outDir, distDir, buildId } | |||
) { | |||
return { | |||
'/': { page: '/' }, | |||
'/about': { page: '/about' }, | |||
'/p/hello-nextjs': { page: '/post', query: { title: 'hello-nextjs' } }, | |||
'/p/learn-nextjs': { page: '/post', query: { title: 'learn-nextjs' } }, | |||
'/p/deploy-nextjs': { page: '/post', query: { title: 'deploy-nextjs' } }, | |||
} | |||
}, | |||
} | |||
</syntaxhighlight>'''ملاحظة''': لا يمكن أن تستخدم الحقل <code>query</code> من <code>exportPathMap</code> مع الصفحات الساكنة المحسّنة تلقائيًا أو مع صفحات <code>getStaticProps</code> لأنها تُصيَّر إلى ملفات HTML أثناء البناء، ولا يمكن الحصول على معلومات استعلام إضافية خلال التصدير <code>next export</code>. | |||
تُصدّر الصفحات بعد ذلك إلى ملفات HTML، إذ تصبح الصفحة <code>about/</code> مثلًا <code>about.html/</code>. | |||
إن <code>exportPathMap</code> هي دالة غير متزامنة تقبل وسيطين أولهما <code>defaultPathMap</code> ويمثّل مخطط ارتباط Next.js الافتراضي، أما الوسيط الثاني فهو كائن له الخاصيات التالية: | |||
* <code>dev</code>: يأخذ القيمة <code>true</code> عندما تُستدعى <code>exportPathMap</code> في بيئة التطوير و <code>false</code> عند تنفيذ <code>next export</code>. يُستخدم <code>exportPathMap</code> في بيئة التطوير لتعريف الوجهات. | |||
* <code>dir</code>: المسار المطلق إلى مجلد المشروع. | |||
*<code>outDir</code>: المسار المطلق إلى المجلد <code>/out</code> وستكون قيمته <code>null</code> عندما تكون قيمة <code>dev</code> هي <code>true</code>. | |||
*<code>distDir</code>: المسار المطلق إلى المجلد <code>/next.</code> (يُهيّأ من خلال الإعداد <code>distDir</code>). | |||
*<code>buildId</code>: معرّف النسخة الفريد ID. | |||
إن الكائن المعاد هو مخطط ارتباط مع الصفحات مفاتيحه <code>key</code> هي أسماء المسارات <code>pathname</code> وقيمه <code>value</code> كائنات تقبل الحقول التالية: | |||
*<code>page</code>: من النوع <code>String</code>، وهي الصفحة التي تُصيّر ضمن المجلد <code>pages</code>. | |||
*<code>query</code>: من النوع <code>Object</code>، وهو الكائن <code>query</code> الممرر إلى <code>getInitialProps</code> عند التصيير، وقيمته الافتراضية <code>{}</code>. | |||
<blockquote>يمكن أن يكون اسم المسار <code>pathname</code> المعروض اسم ملف (مثل <code>readme.md/</code>)، لكن قد يكون عليك ضبط ترويسة نوع المحتوى <code>Content-Type</code> على القيمة <code>text/html</code> إن كان محتواه مختلفًا عن HTML.</blockquote> | |||
=== تخصيص مجلد للخرج === | |||
يستخدم الأمر <code>next export</code> المجلد <code>out</code> افتراضيًا لوضع ملفات الخرج فيه، بإمكانك تخصيص مجلد آخر لهذه الغاية باستخدام الوسيط <code>o-</code> كالتالي:<syntaxhighlight lang="javascript"> | |||
next export -o outdir | |||
</syntaxhighlight>'''تحذير''': جرى إهمال استخدام <code>exportPathMap</code> لتعريف وجهات routes مع أي صفحة مولدة عبر <code>getStaticPaths</code> ولا ننصح باستعمالهما كلاهما. | |||
انظر المثال [https://github.com/vercel/next.js/tree/canary/examples/with-static-export Static Export]. | |||
== محرف "/" الزائد == | |||
يمكن ضبط Next.js لتصدير الصفحات بالشكل index.html التي تتطلب إضافة محرف "/" الزائد في نهاية العنوان، مثلًا <code>about/</code> تصبح <code>about/index.html/</code>. ويمكن الوصول إليها عبر المسار <code>/about/</code> وقد كان هذا السلوك الافتراضي قبل الإصدار 9. | |||
لاستعادة هذا السلوك، افتح الملف <code>next.config.js</code> وأضف الإعداد <code>trailingSlash</code> كالتالي: <syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
trailingSlash: true, | |||
} | |||
</syntaxhighlight>هكذا سيُعاد توجيه العنوان <code>about/</code> إلى <code>/about/</code>. | |||
== النمط الصارم في React == | |||
<blockquote>'''اقتراح''': نقترح بشدة استخدام هذا الوضع في تطبيقات Next.js لتحضير تطبيقك بشكل أفضل لإصدارت React المستقبلية.</blockquote>إن [[React/strict mode|النمط الصارم في React]] هو وضع تطوير فقط، كي يشير إلى الأخطاء المحتملة في التطبيق. إذ يفيدك في تحديد دورات العمل غير الآمنة واستخدام الواجهات البرمجية القديمة وغيرها من الميزات الأخرى. تدعم Next.js النمط الصارم في مرحلة زمن التشغيل، ولكي تستخدمه، اضبط الخيار التالي في الملف <code>next.config.js</code>:<syntaxhighlight lang="javascript"> | |||
// next.config.js | |||
module.exports = { | |||
reactStrictMode: true, | |||
} | |||
</syntaxhighlight>إن لم تكن مستعدًا مع فريقك للعمل مع هذا النمط، لا بأس بذلك! يمكنك الانتقال إليه تدريجيًا صفحة صفحة باستخدام <code><React.StrictMode></code>. | |||
== إدراج وحدات خارجية من خلال عناوين URL == | |||
إن الإدراج من خلال عناوين URL هي ميزة تجريبية تسمح بإدراج وحدات برمجية مباشرة من خوادم خارجية (بدلًا من القرص المحلي).<blockquote>'''تنبيه''': هذه الميزة تجريبية، لهذا استخدم النطاقات التي تثق بها فقط لتزيل وتنفيذ الشيفرة على جهازك. استخدم الميزة بتروٍ وحذر حتى نشير إلى هذه الميزة على أنها مستقرة stable.</blockquote>لاستخدام الميزة، أضف العناوين المسموحة إلى الإعداد <code>urlImports</code> في الملف <code>next.config.js</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
experimental: { | |||
urlImports: ['https://example.com/assets/', 'https://cdn.skypack.dev'], | |||
}, | |||
} | |||
</syntaxhighlight>بإمكانك حينها إدراج الوحدات من عنوان URL مباشرة في تطبيقك:<syntaxhighlight lang="javascript"> | |||
import { a, b, c } from 'https://example.com/modules/some/module.js' | |||
</syntaxhighlight> | |||
يمكن استخدام هذه الميزة في أي مكان يمكن فيه إدراج حزمة اعتيادية. | |||
=== الأمان === | |||
صُممت هذه الميزة ليكون الأمان أولويتها القصوى. إذ أضفنا بدايةً رايةً تجريبيةً تجبرك على التصريح بسماحك للإدراج من عنوان محدد. نعمل الآن على حصر عمل الوحدات المدرجة من عناوين خارجية ضمن بيئة معزولة sandbox في المتصفح باستخدام بيئة التشغيل المتقدمة [https://nextjs.org/docs/api-reference/edge-runtime Edge Runtime] التي تُستخدم من قبل [[Next.js/middleware|البرمجيات الوسطية]] و [https://vercel.com/live Next.js Live]. | |||
=== إقفال الملفات === | |||
تُنشئ Next.js ملفًا مقفلًا في المجلد <code>next.lock</code> عند الإدراج من عناوين URL. يُفترض أن يُدفع هذا المجلد إلى Git ولا ينبغي تضمينه في الملف <code>gitignore.</code> | |||
* عند تنفيذ الأمر <code>next dev</code>، تنزّل Next.js وتضيف كل الوحدات المدرجة من عناوين URL إلى الملف المقفل. | |||
* عند تنفيذ الأمر <code>next build</code>، تستخدم Next.js الملف المقفل فقط لبناء التطبيق لمرحلة الإنتاج. | |||
لا حاجة عادة إلى أية طلبات شبكة وسيسبب أي ملف مقفل منتهي الصلاحية إحباط البناء. أما الاستثناء الوحيد لهذه الحالة فهي الموارد التي تستجيب بالترويسة <code>Cache-Control: no-cache</code> إذ لا تمتلك هذه الموارد المدخل <code>no-cache</code> في الملف المقفل، وبالتالي لا بد من إحضارها عند كل عملية بناء. | |||
=== أمثلة === | |||
==== إدراج Skypack ==== | |||
<syntaxhighlight lang="javascript"> | |||
import confetti from 'https://cdn.skypack.dev/canvas-confetti' | |||
import { useEffect } from 'react' | |||
export default () => { | |||
useEffect(() => { | |||
confetti() | |||
}) | |||
return <p>Hello</p> | |||
} | |||
</syntaxhighlight> | |||
==== إدراج صور ساكنة ==== | |||
<syntaxhighlight lang="javascript"> | |||
import Image from 'next/image' | |||
import logo from 'https://github.com/vercel/next.js/raw/canary/test/integration/production/public/vercel.png' | |||
export default () => ( | |||
<div> | |||
<Image src={logo} placeholder="blur" /> | |||
</div> | |||
) | |||
</syntaxhighlight> | |||
==== عناوين ضمن CSS ==== | |||
<syntaxhighlight lang="javascript"> | |||
.className { | |||
background: url('https://github.com/vercel/next.js/raw/canary/test/integration/production/public/vercel.png'); | |||
} | |||
</syntaxhighlight> | |||
==== إدراج ملفات ساكنة ==== | |||
<syntaxhighlight lang="javascript"> | |||
const logo = new URL('https://example.com/assets/file.txt', import.meta.url) | |||
console.log(logo.pathname) | |||
// prints "/_next/static/media/file.a9727b5d.txt" | |||
</syntaxhighlight> | |||
== مؤشر بناء التطبيق == | |||
عندما تحرر الشيفرة وتصرّف التطبيق في Next.js، سيظهر مؤشر التصريف في أسفل يمين الصفحة.<blockquote>'''ملاحظة''': يظهر هذا المؤشر في وضع التطوير فقط ولن يظهر أثناء بناء وتشغيل التطبيق في نمط الإنتاج.</blockquote>قد يتوضع هذا المؤشر في مكان خاطئ ضمن الصفحة، فإن أردت تغيير موضعه، افتح الملف <code>next.config.js</code> واضبط قيمة الخيار <code>buildActivityPosition</code> ضمن الكائن <code>devIndicators</code> على <code>bottom-right</code> (افتراضي)، أو <code>bottom-left</code> أو <code>top-right</code> أو <code>top-left</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
devIndicators: { | |||
buildActivityPosition: 'bottom-right', | |||
}, | |||
} | |||
</syntaxhighlight>وقد لا يفيدك هذا المؤشر في بعض الحالات، لذلك بالإمكان إزالته بتعطيل الإعداد <code>buildActivity</code> ضمن الكائن <code>devIndicators</code>:<syntaxhighlight lang="javascript"> | |||
module.exports = { | |||
devIndicators: { | |||
buildActivity: false, | |||
}, | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
سطر 80: | سطر 1٬543: | ||
* الصفحات [https://nextjs.org/docs/api-reference/next.config.js/introduction Next.config.js] من توثيق Next.js الرسمي. | * الصفحات [https://nextjs.org/docs/api-reference/next.config.js/introduction Next.config.js] من توثيق Next.js الرسمي. | ||
[[تصنيف:Next.js|{{SUBPAGENAME}}]] | |||
[[تصنيف:Next.js API|{{SUBPAGENAME}}]] |
المراجعة الحالية بتاريخ 16:55، 3 يناير 2023
بإمكانك إنشاء الملف next.config.js
أو next.config.mjs
في جذر مشروعك وإلى جوار الملف package.json
، إن كنت ترغب في تطبيق إعدادت متقدمة على تطبيق Next.js.
يُعد الملف next.config.js
وحدة Node.js وليس ملف JSON، ويُستخدم من قبل خادم Next.js وخلال مراحل بناء التطبيق ولا يُضمَّن في تجميعة المتصفح.
إليك مثالًا عن ملف التهيئة next.config.js
:
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
/* ضع الإعدادات هنا */
}
module.exports = nextConfig
إن احتجت إلى وحدات ECMAScript بإمكانك استخدام الملف:
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
/* ضع الإعدادات هنا */
}
export default nextConfig
بإمكانك استخدام دالة أيضًا:
module.exports = (phase, { defaultConfig }) => {
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
/* ضع الإعدادات هنا */
}
return nextConfig
}
يمكن ابتداءً بالنسخة 12.1.0 استخدام دالة متزامنة:
module.exports = async (phase, { defaultConfig }) => {
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
/* ضع الإعدادات هنا */
}
return nextConfig
}
يُعد السياق phase
هو السياق الحالي لتحميل الإعدادات وتوجد سياقات أخرى أيضًا. يمكن إدراج المراحل phases من الوحدة next/constants
:
const { PHASE_DEVELOPMENT_SERVER } = require('next/constants')
module.exports = (phase, { defaultConfig }) => {
if (phase === PHASE_DEVELOPMENT_SERVER) {
return {
/* ضع إعدادات مرحلة التطوير هنا */
}
}
return {
/* ضع إعدادات كل المراحل هنا ما عدا مرحلة التطوير */
}
}
تُوضع الإعدادات المسموحة) في next.config.js
مكان أسطر التعليقات في الشيفرات السابقة. مع ذلك، لا حاجة إلى أية إعدادات، وليس من الضرورة فهم عمل كل إعداد. كل ما عليك هو البحث عن الميزات التي تريد تفعيلها أو تعديلها في هذه الصفحة وستريك ما العمل.
تفادى استخدام ميزات JavaScript الجديدة في اصدار Node.js الذي تستهدفه. فلن يُحلل الملف
next.config.js
من قبل Webpack أو Babel أو TypeScript.
متغيرات البيئة
تقدم ابتداءً من الإصدار 9.4 تجربة تعليمية وعملية في إضافة متغيرات البيئة. حاول أن تجربها.
لإضافة متغيرات بيئة إلى تجميعة JavaScript، افتح الملف next.config.js
وأضف الإعداد env
:
module.exports = {
env: {
customKey: 'my-value',
},
}
بإمكانك الآن الوصول إلى process.env.customKey
في شيفرتك. إليك مثالًا:
function Page() {
return <h1>The value of customKey is: {process.env.customKey}</h1>
}
export default Page
تستبدل Next.js أثناء البناء المفاتيح process.env.customKey
بالقيمة 'my-value'
. وانتبه إلى أنك لن تستطيع تفكيك متغيرات process.env
نظرًا لطبيعة الإضافة DefinePlugin في webpack. فلو ألقينا نظرة مثلًا على السطر البرمجي التالي:
return <h1>The value of customKey is: {process.env.customKey}</h1>
سينتهي الأمر على النحو:
return <h1>The value of customKey is: {'my-value'}</h1>
تحذير: متغيرات البيئة المُعرَّفة بهذه الطريقة ستُضاف إلى تجميعة JavaScript المُرسلة إلى العميل خلاف إضافتها في ملف env.
والسلوك الذي تسلكه إلى أضفنا العبارة NEXT_PUBLIC_
أو لا في بداية اسم متغير البيئة.
انظر المثال With env.
المسار الأساسي basePath
أضيف بدءا من الإصدار 9.5.0.
بإمكانك استخدام الإعداد basePath
لنشر تطبيق Next.js ضمن مسار فرعي لنطاق، إذ يسمح لك هذا الإعداد بضبط بادئة للمسار في تطبيقك. ولكي تستخدم مثلًا المسار docs/
بدلًا من المسار الأساسي الافتراضي /
، افتح الملف next.config.js
وأضف الإعداد basePath
كالتالي:
module.exports = {
basePath: '/docs',
}
ملاحظة: لا بد من ضبط هذه القيمة أثناء البناء ولا يمكن تغييرها دون إعادة بناء التطبيق، لأن القيمة ستضاف مباشرة إلى تجميعة الشيفرة الخاصة بجانب العميل.
الروابط
عند ربط الصفحة بغيرها باستخدام next/link
و next/router
سيُطبق الإعداد basePath
تلقائيًا. إذ سيتحول على سبيل المثال المسار about/
إلى docs/about/
تلقائيًا عند ضبط قيمة الإعداد basePath
على docs/
.
export default function HomePage() {
return (
<>
<Link href="/about">
<a>About Page</a>
</Link>
</>
)
}
وسيكون خرج HTML كالتالي:
<a href="/docs/about">About Page</a>
يضمن ذلك أنك لن تُضطر إلى تغيير كل الروابط في تطبيقك عند تغيير قيمة الإعداد basePath
.
الصور
لا بد من إضافة قيمة الإعداد basePath
قبل قيمة الخاصية src
إن كنت تريد استخدام المكوّن next/image
. فالمسار docs/me.png/
سيخدّم صورتك بالشكل الصحيح إن قررت أن تكون قيمة الإعداد basePath
هي docs/
.
import Image from 'next/image'
function Home() {
return (
<>
<h1>My Homepage</h1>
<Image
src="/docs/me.png"
alt="Picture of the author"
width={500}
height={500}
/>
<p>Welcome to my homepage!</p>
</>
)
}
export default Home
إعادة الكتابة Rewrites
الإصدار | التغييرات |
---|---|
13.3.1 | إضافة missing |
10.2.0 | إضافة has |
9.5.0 | إضافة خاصية إعادة الكتابة |
تتيح لك عملية إعادة الكتابة Rewrites ربط مسار طلب وارد إلى مسار وجهة أخرى. تعمل إعادة الكتابة مثل وسيط لعناوين URL وتقنِّع المسار إلى الوجهة ليظهر المستخدم وكأنه لم يغير مكانه في الموقع. بالمقابل تعيد عملية إعادة التوجيه redirects توجيه المستخدم إلى صفحة جديدة وتُظهر التغييرات على العنوان.
ولتستخدم إعادة الكتابة أضف المفتاح rewrites
إلى ملف التهيئة next.config.js
:
module.exports = {
async rewrites() {
return [
{
source: '/about',
destination: '/',
},
]
},
}
تُطبق إعادة الكتابة على التوجيه في جانب العميل، وتطبق إعادة الكتابة في المثال السابق مثلًا على العنصر <"Link href="/about>
.
إن الدالة هي دالة غير متزامنة تتوقع إعادة مصفوفة تضم كائنات تمتلك الخاصيتين source
و destination
:
source
: من النوعString
، وهو نموذج مسار الطلب الوارد.destination
: من النوعString
، وهو المسار الذي تريد التوجه إليه.basePath
: تأخذ أحد القيمتينfalse
أوundefined
، فإن كانت القيمةfalse
، لن يضاف المسار الأساسي إلى العنوان عند المطابقة، ويستخدم في إعادة الكتابة الخارجية.locale
: تأخذ أحد القيمتينfalse
أوundefined
، يحدد إن كان سُضاف الإعداد المحلي إلى المسار عند المطابقة.has
: مصفوفة من الكائناتhas objects
لها الخاصياتtype
وkey
وvalue
.missing
: مصفوفة من كائنات لها الخاصياتtype
وkey
وvalue
.
تجري عملية إعادة الكتابة بعد التحقق من منظومة الملفات (ملفات المجلدين pages
و public
) وقبل التوجه الديناميكي افتراضيًا. يمكن تغيير هذا السلوك بإعادة كائن بدلًا من المصفوفة من الدالة rewrites
ابتداءً من الإصدار 10.1
من Next.js:
module.exports = {
async rewrites() {
return {
beforeFiles: [
//يجري التحقق من عمليات إعادة الكتابة هذه بعد الترويسات
// أو إعادة التوجيه
//_next/public وقبل كل الملفات بما فيها ملفات المجلد
// مما يسمح بتغيير ملفات الصفحة
{
source: '/some-page',
destination: '/somewhere-else',
has: [{ type: 'query', key: 'overrideMe' }],
},
],
afterFiles: [
// pages/public يجري التحقق من عمليات إعادة الكتابة هذه بعد ملفات
// لكن قبل الوجهات الديناميكية
{
source: '/non-existent',
destination: '/somewhere-else',
},
],
fallback: [
// pages/public يجري التحقق من عمليات إعادة الكتابة هذه بعد ملفات
// وقبل الوجهات الديناميكية
{
source: '/:path*',
destination: `https://my-old-site.com/:path*`,
},
],
}
},
}
ملاحظة: إنّ إجراء إعادة كتابة ضمن beforeFiles
لا يتضمن التحقق المباشر من نظام الملفات والوجهات الديناميكية بعد مطابقة المصدر، بل تستمر حتى يجري التحقق من جميع الإجراءات ضمن beforeFiles
. إليك ترتيب التحقق من وجهات Next.js:
- يجري التحقق من الترويسات headers أو تطبيقها.
- يجري التحقق من عمليات إعادة التوجيه redirects أو تطبيقها.
- يجري التحقق من عمليات إعادة الكتابة ضمن
beforeFiles
أو تطبيقها. - يجري التحقق من الملفات الساكنة في المجلد
public
وnext/static_
والصفحات غير الديناميكية أو تخديمها. - يجري التحقق من عمليات إعادة الكتابة ضمن
afterFiles
أو تطبيقها، فإن تطابقت إحدى عمليات إعادة الكتابة، نتحقق من الوجهة الديناميكية أو الملفات الساكنة بعد كل تطابق. - يجري التحقق من إعادة الكتابة ضمن
fallback
أو تطبيقها، ويجري تطبيقها قبل تصيير الصفحة 404، وبعد التحقق من الوجهات الديناميكية وجميع الموجودات الساكنة. إن كنت تستخدم fallback: true/'blocking' فيgetStaticPaths
فلن تعمل عملية إعادة الكتابة ضمنfallback
.
معاملات الدالة rewrites
عند استخدام المعاملات، تُمرر هذه المعاملات إلى الدالة عبر الاستعلام افتراضيًا إن لم يُستخدم أيًا منها في الخاصية destination
:
module.exports = {
async rewrites() {
return [
{
source: '/old-about/:path*',
destination: '/about', //وبالتالي سيُمرر path لم يُستخدم المعامل
// تلقائيًا ضمن الاستعلام
},
]
},
}
أما إن استُخدم معامل في الوجهة destination
، فلن يُمرر أي من المعاملات تلقائيًا ضمن الاستعلام:
module.exports = {
async rewrites() {
return [
{
source: '/docs/:path*',
destination: '/:path*',//وبالتالي لن يُمرر path استُخدم المعامل
// أي معامل تلقائيًا من خلال الاستعلام
},
]
},
}
لكن لا يزال بإمكانك تمرير المعاملات يدويًا ضمن الاستعلام إن استُخدم أحدها في الخاصية destination
:
module.exports = {
async rewrites() {
return [
{
source: '/:first/:second',
destination: '/:first?second=:second',
//قد استُخدم في الوجهة فلن يُضاف first طالما أن المعامل
// تلقائيًا second المعامل الثاني
// إلى الاستعلام على الرغم من إمكانية إضافته يدويًا كما في الأعلى
},
]
},
}
ملاحظة: تُحلَّل معاملات إعادة الكتابة للصفحات الساكنة الناتجة عن التحسين التلقائي الساكن أو التصيير المسبق من جانب العميل بعد الترطيب ويُزوَّد به الاستعلام.
مطابقة المسارات
يُسمح بمطابقة المسارات كأن يُطابق المسار blog/:slug/
المسار blog/hello-world/
(دون تداخل في المسارات).
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug',
destination: '/news/:slug', // يمكن مطابقة المعاملات هنا
},
]
},
}
مطابقة المسارات بوجود محارف بديلة
لمطابقة مسار باستخدام محارف بديلة، بإمكانك استعمال *
بعد المعامل، إذ سيُطابق المسار *blog/:slug/
مثلًا المسار /blog/a/b/c/d/hello-world
:
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug*',
destination: '/news/:slug*', // يمكن مطابقة المعاملات هنا
},
]
},
}
مطابقة المسارات من خلال التعابير النمطية Regex
لمطابقة مسار من خلال التعابير النمطية، غلِّف التعبير النمطي ضمن قوسين بعد المعامل. سيطابق المسار blog/:slug(\\d{1,})/
مثلًا المسار blog/123/
وليس المسار blog/abc/
:
module.exports = {
async rewrites() {
return [
{
source: '/old-blog/:post(\\d{1,})',
destination: '/blog/:post', // يمكن مطابقة المعاملات هنا
},
]
},
}
تُستخدم المحارف التالية (
و )
و {
و }
و :
و *
و +
و ?
في صياغة التعابير النمطية المستخدمة لمطابقة المسارات، فإن استُخدمت في الخاصية source
كقيم غير خاصة non-special لا بد من تجاوزها بإضافة الصيغة \\
قبلها:
module.exports = {
async rewrites() {
return [
{
//`/english(default)/something` سيثطابق ذلك
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
},
]
},
}
مطابقة الترويسات وملفات تعريف الارتباط والاستعلام
بالإمكان مطابقة عملية إعادة كتابة عندما تُطابِق قيم الترويسات أو ملف تعريف الارتباط أو الاستعلام قيمة الحقل has
أو لا تطابق قيمة الحقل missing
. أي يجب أن تتطابق الخاصية source
وجميع عناصر has
حتى تُطبَّق إعادة الكتابة ولا يجب أن تتطابق جميع عناصر missing
. تمتلك العناصر has
و missing
الحقول التالية:
type
: من النوعString
، وسيكون إماheader
أوcookie
أوhost
أوquery
.key
: من النوعString
، مفتاح النوع المختارtype
الذي سيُطابق.value
: من النوعString
أوundefined
، القيمة التي سيجري التحقق منها، وإن كانت غير محددة ستُطابق أي قيمة. يمكن استخدام سلسلة نصية تشابه التعبير النمطي لالتقاط جزء محدد من القيمة. فإن استُخدمت القيمةfirst-(?<paramName>.*)
لمطابقةfirst-second
، ستتمكن حينها من استخدامsecond
في الوجهة مع المعامل :paramName
.
module.exports = {
async rewrites() {
return [
// `x-rewrite-me` إن وجدت الترويسة
// تُطبق إعادة الكتابة
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-rewrite-me',
},
],
destination: '/another-page',
},
// `x-rewrite-me` إن فقدت الترويسة
// تُطبق إعادة الكتابة
{
source: '/:path*',
missing: [
{
type: 'header',
key: 'x-rewrite-me',
},
],
destination: '/another-page',
},
// إن تطابقت الترويسة أو ملف الارتباط أو الاستعلام
// تُطبق إعادة الكتابة
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
//لن تكون قيمة الصفحة متاحة في الوجهة لأن القيمة موجودة
//(?<page>home) ولا تُستخدم مجموعة التقاط مُسماة مثل
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
destination: '/:path*/home',
},
//وتحتوي على قيمة التطابق `x-authorized` إن وجدت الترويسة
//ستُطيّق إعادة الكتابة
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
destination: '/home?authorized=:authorized',
},
//ستُطبّق إعادة الكتابة `example.com` إن كان المضيف
{
source: '/:path*',
has: [
{
type: 'host',
value: 'example.com',
},
],
destination: '/another-page',
},
]
},
}
إعادة الكتابة إلى عنوان URL خارجي
بإمكانك إعادة الكتابة إلى عنوان URL خارجي، وهذا مفيد لتبني Next.js تدريجيًا. إليك مثالًا عن إعادة كتابة لتحويل الوجهة blog/
لتطبيقك الرئيسي إلى موقع خارجي:
module.exports = {
async rewrites() {
return [
{
source: '/blog',
destination: 'https://example.com/blog',
},
{
source: '/blog/:slug',
destination: 'https://example.com/blog/:slug',
},
]
},
}
إن كنت تستخدم الحقل trailingSlash: true
فستحتاج أيضًا إلى حشر محرف /
في نهاية قيمة المعامل source
. وإن كان الخادم الهدف يتوقع وجود المحرف /
في نهاية القيمة، فلا بد من وضعها في المعامل destination
أيضًا.
module.exports = {
trailingSlash: true,
async rewrites() {
return [
{
source: '/blog/',
destination: 'https://example.com/blog/',
},
{
source: '/blog/:path*/',
destination: 'https://example.com/blog/:path*/',
},
]
},
}
راجع هذين المثالين:
تبني Next.js تدريجيًا
يمكنك دفع Next.js للتراجع كي تلعب دور الوسيط لموقع ويب موجود بعد التحقق من كل وجهات Next.js. لا حاجة في هذه الحالة لتغيير إعدادات إعادة الكتابة عند نقل صفحات أكثر إلى Next.js.
module.exports = {
async rewrites() {
return {
fallback: [
{
source: '/:path*',
destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`,
},
],
}
},
}
لمزيد من المعلومات راجع الصفحة "الانتقال إلى Next.js" من هذا التوثيق.
إعادة الكتابة مع دعم للمسار الأساسي
عند استخدام basePath
مع إعادة الكتابة ستُضاف تلقائيًا البادئة إلى المعاملين source
و destination
ما لم تضف الإعداد basePath: false
إلى دالة إعادة الكتابة:
module.exports = {
basePath: '/docs',
async rewrites() {
return [
{
source: '/with-basePath', // /docs/with-basePath يصبج تلقائيًا
destination: '/another', // /docs/another يصبح تلقائيًا
},
{
//basePath: false لأن /without-basePath إلى /docs لا يضيف
// لا يمكن استخدام ذلك في عمليات إعادة الكتابة الداخلية
// destination: '/another' مثال
source: '/without-basePath',
destination: 'https://example.com',
basePath: false,
},
]
},
}
إعادة الكتابة مع دعم التوجه i18n
عند استخدام i18n
مع إعادة الكتابة ستُضاف تلقائيًا البادئة المهيأة مسبقًا locales
إلى المعاملين source
و destination
ما لم تضف الإعداد locale: false
إلى دالة إعادة الكتابة، وفي حال استخدامه لا بد من إضافة تلك البادئة يدويًا حتى تُطابق بشكل صحيح:
module.exports = {
i18n: {
locales: ['en', 'fr', 'de'],
defaultLocale: 'en',
},
async rewrites() {
return [
{
source: '/with-locale', // يتعامل مع الإعداد المحلي تلقائيًا
destination: '/another', // يمرر الإعداد المحلي تلقائيًا
},
{
// لا يُعالج الإعداد المحلي تلقائيًا
source: '/nl/with-locale-manual',
destination: '/nl/another',
locale: false,
},
{
// '/' يطابق
// `en` لأن الإعداد المحلي الافتراضي
source: '/en',
destination: '/en/another',
locale: false,
},
{
// locale: false بإمكانك مطابقة جميع الإعدادات المحلية عندما يكون
source: '/:locale/api-alias/:path*',
destination: '/api/:path*',
locale: false,
},
{
// /(en|fr|de)/(.*) سيحول هذا إلى
// لذا لن يُطابق المستوى الأعلى
// `/` أو `/fr`
source: '/(.*)',
destination: '/another',
},
]
},
}
انظر المثال Rewrites.
إعادة التوجيه
الإصدار | التغييرات |
---|---|
10.2.0 | إضافة has
|
9.5.0 | إضافة خاصية إعادة التوجيه |
يسمح لك إعادة التوجيه أن تحوّل مسار الطلب الوارد إلى وجهة مختلفة. ولاستخدام إعادة التوجيه، لا بد من إضافة المفتاح redirects
إلى ملف التهيئة next.config.js
:
module.exports = {
async redirects() {
return [
{
source: '/about',
destination: '/',
permanent: true,
},
]
},
}
تُعد الدالة redirects
دالة غير متزامنة تتوقع إعادة مصفوفة تضم كائنات تمتلك الخاصيات source
و destination
و permanent
:
source
: من النوعString
، وهو نموذج مسار الطلب الوارد.destination
: من النوعString
، وهو المسار الذي تريد التوجه إليه.permanent
: من النوع المنطقي، فإن كانت قيمتهاtrue
سيُستخدم رمز الحالة 308 الذي يملي على العميل أو محرك البحث تخزين إعادة التوجيه إلى ما لا نهاية. أما في حال كانfalse
سيُستخدم رمز الحالة 307 وهو مؤقت ولا حاجة لتخزينه.قد تلاحظ استخدام رمز الحالة
307
لإعادة التوجه المؤقت و308
لإعادة التوجه الدائم مع()redirect
. وعلى الرغم من استخدام الرمزين302
و301
على الترتيب تقليديًا، إلا أن العديد من المتصفحات قد غيرت نوع طلب إعادة التوجه إلىGET
بغض النظر عن أصول نوع الطلب. فلو أنشأ المتصفح طلبًا إلىPOST /v1/users
وأعاد رمز الحالة302
مع الموقعv2/users/
، فقد تكون الطلبات التالية من النوعGET /v2/users
بدلًا من النوع المتوقعPOST /v2/users
. وبالتالي استخدمت Next.js رمزي الحالة 308 و 307 لحفظ نوع الطلب صراحة.basePath
: تأخذ أحد القيمتينfalse
أوundefined
، فإن كانت القيمةfalse
، لن يضاف المسار الأساسي إلى العنوان عند المطابقة، ويستخد في إعادة الكتابة الخارجية.locale
: تأخذ أحد القيمتينfalse
أوundefined
، يحدد إن كان سُضاف الإعداد المحلي إلى المسار عند المطابقة.has
: مصفوفة من الكائناتhas objects
لها الخاصياتtype
وkey
وvalue
.missing
: مصفوفة من كائنات لها الخاصياتtype
وkey
وvalue
.
يجري التحقق من عمليات إعادة التوجه قبل التحقق من نظام الملفات الذي يضم ملفات المجلدين pages
و public
. ولا تُطبَّق عمليات إعادة التوجيه على التوجيه من طرف العميل (Link
أو router.push
) إلا إن تدخلت البرمجيات الوسيطة Middleware وطابقت المسار.
عندما يُطبق إعادة التوجيه، ستُمرر أي قيم للاستعلام ضمن الطلب إلى الوجهة الجديدة. ألق نظرة على الإعدادات التالية:
{
source: '/old-blog/:path*',
destination: '/blog/:path*',
permanent: false
}
فعندما يكون الطلب من الشكل old-blog/post-1?hello=world/
مثلًا سيُعاد توجيه العميل إلى blog/post-1?hello=world/
.
مطابقة المسارات
يُسمح بمطابقة المسارات كأن يُطابق المسار blog/:slug/
المسار blog/hello-world/
(دون تداخل في المسارات).
module.exports = {
async redirects() {
return [
{
source: '/old-blog/:slug',
destination: '/news/:slug', // Matched parameters can be used in the destination
permanent: true,
},
]
},
}
مطابقة المسارات بوجود محارف بديلة
لمطابقة مسار باستخدام محارف بديلة، بإمكانك استعمال *
بعد المعامل، إذ سيُطابق المسار *blog/:slug/
مثلًا المسار blog/a/b/c/d/hello-world/
:
module.exports = {
async redirects() {
return [
{
source: '/blog/:slug*',
destination: '/news/:slug*', // Matched parameters can be used in the destination
permanent: true,
},
]
},
}
مطابقة المسارات من خلال التعابير النمطية Regex
لمطابقة مسار من خلال التعابير النمطية، غلِّف التعبير النمطي ضمن قوسين بعد المعامل. سيطابق المسار post/:slug(\\d{1,})/
مثلًا المسار post/123/
وليس المسار post/abc/
:
module.exports = {
async redirects() {
return [
{
source: '/post/:slug(\\d{1,})',
destination: '/news/:slug', // Matched parameters can be used in the destination
permanent: false,
},
]
},
}
تُستخدم المحارف التالية (
و )
و {
و }
و :
و *
و +
و ?
في صياغة التعابير النمطية المستخدمة لمطابقة المسارات، فإن استُخدمت في الخاصية source
كقيم غير خاصة non-special لا بد من تجاوزها بإضافة الصيغة \\
قبلها:
module.exports = {
async redirects() {
return [
{
// this will match `/english(default)/something` being requested
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
permanent: false,
},
]
},
}
مطابقة الترويسات وملفات تعريف الارتباط والاستعلام
بالإمكان مطابقة عملية إعادة كتابة عندما تُطابِق قيم الترويسات أو ملف تعريف الارتباط أو الاستعلام قيمة الحقل has
فقط. أي يجب أن تتطابق الخاصية source
وجميع عناصر has
حتى تُطبَّق إعادة الكتابة. تمتلك العناصر has
و missing
الحقول التالية:
type
: من النوعString
، وسيكون إماheader
أوcookie
أوhost
أوquery
.key
: من النوعString
، مفتاح النوع المختارtype
الذي سيُطابق.value
: من النوعString
أوundefined
، القيمة التي سيجري التحقق منها، وإن كانت غير محددة ستُطابق أي قيمة. يمكن استخدام سلسلة نصية تشابه التعبير النمطي لالتقاط جزء محدد من القيمة. فإن استُخدمت القيمةfirst-(?<paramName>.*)
لمطابقةfirst-second
، ستتمكن حينها من استخدامsecond
في الوجهة مع المعامل:paramName
.
module.exports = {
async redirects() {
return [
// if the header `x-redirect-me` is present,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
has: [
{
type: 'header',
key: 'x-redirect-me',
},
],
permanent: false,
destination: '/another-page',
},
// if the header `x-dont-redirect` is present,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
missing: [
{
type: 'header',
key: 'x-do-not-redirect',
},
],
permanent: false,
destination: '/another-page',
},
// if the source, query, and cookie are matched,
// this redirect will be applied
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// the page value will not be available in the
// destination since value is provided and doesn't
// use a named capture group e.g. (?<page>home)
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
permanent: false,
destination: '/another/:path*',
},
// if the header `x-authorized` is present and
// contains a matching value, this redirect will be applied
{
source: '/',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
permanent: false,
destination: '/home?authorized=:authorized',
},
// if the host is `example.com`,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
has: [
{
type: 'host',
value: 'example.com',
},
],
permanent: false,
destination: '/another-page',
},
]
},
}
إعادة التوجيه مع دعم للمسار الأساسي basePath
عند استخدام basePath
مع إعادة التوجيه ستُضاف تلقائيًا البادئة إلى المعاملين source
و destination
ما لم تضف الإعداد basePath: false
إلى دالة إعادة التوجيه:
module.exports = {
basePath: '/docs',
async redirects() {
return [
{
source: '/with-basePath', // automatically becomes /docs/with-basePath
destination: '/another', // automatically becomes /docs/another
permanent: false,
},
{
// does not add /docs since basePath: false is set
source: '/without-basePath',
destination: '/another',
basePath: false,
permanent: false,
},
]
},
}
إعادة التوجيه مع دعم التوجه i18n
عند استخدام i18n
مع إعادة الكتابة ستُضاف تلقائيًا البادئة المهيأة مسبقًا locales
إلى المعاملين source
و destination
ما لم تضف الإعداد locale: false
إلى دالة إعادة التوجيه، وفي حال استخدامه لا بد من إضافة تلك البادئة يدويًا حتى تُطابق بشكل صحيح:
module.exports = {
i18n: {
locales: ['en', 'fr', 'de'],
defaultLocale: 'en',
},
async redirects() {
return [
{
source: '/with-locale', // automatically handles all locales
destination: '/another', // automatically passes the locale on
permanent: false,
},
{
// does not handle locales automatically since locale: false is set
source: '/nl/with-locale-manual',
destination: '/nl/another',
locale: false,
permanent: false,
},
{
// this matches '/' since `en` is the defaultLocale
source: '/en',
destination: '/en/another',
locale: false,
permanent: false,
},
// it's possible to match all locales even when locale: false is set
{
source: '/:locale/page',
destination: '/en/newpage',
permanent: false,
locale: false,
}
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
destination: '/another',
permanent: false,
},
]
},
}
قد تحتاج في حالات نادرة تعيين رموز حالة مخصصة لعملاء HTTP الأقدم كي يُعاد توجيههم بالشكل الصحيح. في حالات كهذه، استخدم الخاصية statusCode
بدلًا من permanent
لكن لا تستخدمهما معًا. تجدر الإشارة إلى إضافة الترويسة Refresh
تلقائيًا إلى رمز الحالة 308 لضمان التوافق مع المتصفح IE11.
أنواع أخرى لإعادة التوجيه
- بإمكانك استخدام
()res.redirect
ضمن وجهات API. - يمكنك إعاة توجيه صفحات محددة عند الطلب ضمن
getStaticProps
وgetServerSideProps
.
انظر مثال Redirects.
الترويسات
الإصدار | التغييرات |
---|---|
10.2.0 | إضافة has
|
9.5.0 | إضافة خاصية الترويسات |
تتيح لك إعداد ترويسات HTTP مخصصة عند الاستجابة إلى طلب وارد عبر مسار معين. ولإعداد ترويسة مخصصة، استخدم المفتاح headers
ضمن الملف next.config.js
:
module.exports = {
async headers() {
return [
{
source: '/about',
headers: [
{
key: 'x-custom-header',
value: 'my custom header value',
},
{
key: 'x-another-custom-header',
value: 'my other custom header value',
},
],
},
]
},
}
تُعد الدالة headers
دالة غير متزامنة تتوقع إعادة مصفوفة تضم كائنات تمتلك الخاصيات source
و headers
:
source
: من النوعString
، وهو نموذج مسار الطلب الوارد.headers
: مصفوفة من كائنات ترويسة الاستجابة، ولها الخاصيتانkey
وvalue
.basePath
: تأخذ أحد القيمتينfalse
أوundefined
، فإن كانت القيمةfalse
، لن يضاف المسار الأساسي إلى العنوان عند المطابقة، ويستخدم في إعادة الكتابة الخارجية.locale
: تأخذ أحد القيمتينfalse
أوundefined
، يحدد إن كان سُضاف الإعداد المحلي إلى المسار عند المطابقة.has
: مصفوفة من الكائناتhas objects
لها الخاصياتtype
وkey
وvalue
.missing
: مصفوفة من كائنات لها الخاصياتtype
وkey
وvalue
.
يجري التحقق من الترويسات قبل التحقق من منظومة الملفات التي تضم ملفات المجلدين pages
و public
.
سلوك الإلغاء في الترويسات
إن تطابقت ترويستان مع المسار ذاته واستهدفتا نفس المفتاح، سيُلغي مفتاح الترويسة الأخيرة مفتاح الأولى ويحل محله. في المثال التالي، سينتج المسار hello/
عن الترويسة x-hello
التي قيمتها world
لأنها الترويسة الأخيرة من ترويستين لهما نفس المفتاح x-hello
:
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'x-hello',
value: 'there',
},
],
},
{
source: '/hello',
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
]
},
}
مطابقة المسارات
يُسمح بمطابقة المسارات كأن يُطابق المسار blog/:slug/
المسار blog/hello-world/
(دون تداخل في المسارات).
module.exports = {
async headers() {
return [
{
source: '/blog/:slug',
headers: [
{
key: 'x-slug',
value: ':slug', // Matched parameters can be used in the value
},
{
key: 'x-slug-:slug', // Matched parameters can be used in the key
value: 'my other custom header value',
},
],
},
]
},
}
مطابقة المسارات بوجود محارف بديلة
لمطابقة مسار باستخدام محارف بديلة، بإمكانك استعمال *
بعد المعامل، إذ سيُطابق المسار *blog/:slug/
مثلًا المسار blog/a/b/c/d/hello-world/
:
module.exports = {
async headers() {
return [
{
source: '/blog/:slug*',
headers: [
{
key: 'x-slug',
value: ':slug*', // Matched parameters can be used in the value
},
{
key: 'x-slug-:slug*', // Matched parameters can be used in the key
value: 'my other custom header value',
},
],
},
]
},
}
مطابقة المسارات من خلال التعابير النمطية Regex
لمطابقة مسار من خلال التعابير النمطية، غلِّف التعبير النمطي ضمن قوسين بعد المعامل. سيطابق المسار blog/:slug(\\d{1,})/
مثلًا المسار blog/123/
وليس المسار blog/abc/
:
module.exports = {
async headers() {
return [
{
source: '/blog/:post(\\d{1,})',
headers: [
{
key: 'x-post',
value: ':post',
},
],
},
]
},
}
تُستخدم المحارف التالية (
و )
و {
و }
و :
و *
و +
و ?
في صياغة التعابير النمطية المستخدمة لمطابقة المسارات، فإن استُخدمت في الخاصية source
كقيم غير خاصة non-special لا بد من تجاوزها بإضافة الصيغة \\
قبلها:
module.exports = {
async headers() {
return [
{
// this will match `/english(default)/something` being requested
source: '/english\\(default\\)/:slug',
headers: [
{
key: 'x-header',
value: 'value',
},
],
},
]
},
}
مطابقة الترويسات وملفات تعريف الارتباط والاستعلام
بالإمكان مطابقة ترويسة عندما تُطابِق قيم ترويسة أو ملف تعريف الارتباط أو الاستعلام قيمة الحقل has
فقط. أي يجب أن تتطابق الخاصية source
وجميع عناصر has
حتى تُطبَّق إعادة الكتابة. تمتلك العناصر has
و missing
الحقول التالية:
type
: من النوعString
، وسيكون إماheader
أوcookie
أوhost
أوquery
.key
: من النوعString
، مفتاح النوع المختارtype
الذي سيُطابق.value
: من النوعString
أوundefined
، القيمة التي سيجري التحقق منها، وإن كانت غير محددة ستُطابق أي قيمة. يمكن استخدام سلسلة نصية تشابه التعبير النمطي لالتقاط جزء محدد من القيمة. فإن استُخدمت القيمةfirst-(?<paramName>.*)
لمطابقةfirst-second
، ستتمكن حينها من استخدامsecond
في الوجهة مع المعامل:paramName
.
module.exports = {
async headers() {
return [
// if the header `x-add-header` is present,
// the `x-another-header` header will be applied
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-add-header',
},
],
headers: [
{
key: 'x-another-header',
value: 'hello',
},
],
},
// if the header `x-no-header` is not present,
// the `x-another-header` header will be applied
{
source: '/:path*',
missing: [
{
type: 'header',
key: 'x-no-header',
},
],
headers: [
{
key: 'x-another-header',
value: 'hello',
},
],
},
// if the source, query, and cookie are matched,
// the `x-authorized` header will be applied
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// the page value will not be available in the
// header key/values since value is provided and
// doesn't use a named capture group e.g. (?<page>home)
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
headers: [
{
key: 'x-authorized',
value: ':authorized',
},
],
},
// if the header `x-authorized` is present and
// contains a matching value, the `x-another-header` will be applied
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
headers: [
{
key: 'x-another-header',
value: ':authorized',
},
],
},
// if the host is `example.com`,
// this header will be applied
{
source: '/:path*',
has: [
{
type: 'host',
value: 'example.com',
},
],
headers: [
{
key: 'x-another-header',
value: ':authorized',
},
],
},
]
},
}
الترويسات مع دعم للمسار الأساسي basePath
عند استخدام basePath
مع إعادة الترويسات ستُضاف تلقائيًا البادئة إلى المعامل source
ما لم تضف الإعداد basePath: false
إلى دالة الترويسة:
module.exports = {
basePath: '/docs',
async headers() {
return [
{
source: '/with-basePath', // becomes /docs/with-basePath
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
{
source: '/without-basePath', // is not modified since basePath: false is set
headers: [
{
key: 'x-hello',
value: 'world',
},
],
basePath: false,
},
]
},
}
إعادة التوجيه مع دعم التوجه i18n
عند استخدام i18n
مع الترويسات ستُضاف تلقائيًا البادئة المهيأة مسبقًا locales
إلى المعامل source
ما لم تضف الإعداد locale: false
إلى الترويسة. وفي حال استخدامه لا بد من إضافة تلك البادئة يدويًا حتى تُطابق بشكل صحيح:
module.exports = {
i18n: {
locales: ['en', 'fr', 'de'],
defaultLocale: 'en',
},
async headers() {
return [
{
source: '/with-locale', // automatically handles all locales
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
{
// does not handle locales automatically since locale: false is set
source: '/nl/with-locale-manual',
locale: false,
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
{
// this matches '/' since `en` is the defaultLocale
source: '/en',
locale: false,
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
]
},
}
الترويسة Cache-Control
يمكن إعداد الترويسة Cache-Control
ضمن وجهات API الخاصة بتطبيقك عن طريق التابع res.setHeader
:
// pages/api/user.js
export default function handler(req, res) {
res.setHeader('Cache-Control', 's-maxage=86400')
res.status(200).json({ name: 'John Doe' })
}
لا يمكن إعداد ترويسات Cache-Control
ضمن الملف next.config.js
لأنها ستُلغى عند بناء نسخة الإنتاج، وذلك للتأكد من التخزين الفعّال لوجهات API والموجودات الساكنة static assets.
إن أردت إعادة التحقق من الذاكرة المؤقتة لصفحة وُلِّدت بشكل ساكن، عليك ضبط الخاصية revalidate
ضمن الدالة getStaticProps
في الصفحة.
الامتدادات المخصصة للصفحات
وجهت هذه الامتدادات إلى وحدات برمجية مثل التي تضيف دعمًا للصفحات التي تحمل الامتداد. يمكن أن تهيئ الامتدادات التي يجري البحث عنها ضمن المجلد pages
عند تحليل الصفحة بفتح الملف next.config.js
وإضافة الإعداد pageExtensions
:
module.exports = {
pageExtensions: ['mdx', 'md', 'jsx', 'js', 'tsx', 'ts'],
}
القيم الافتراضية للإعداد pageExtensions
هي ['tsx', 'ts', 'jsx', 'js']
.
يؤثر تهيئة الإعداد pageExtensions
على كل الصفحات بما فيها:
middleware.js
pages/_document.js
pages/_app.js
/pages/api
إذ يعني مثلًا الإعداد ['page.tsx', 'page.ts']:pageExtensions
، أن جميع الملفات مثل app.tsx_
ينبغي أن تُعاد تسميتها إلى app.page.tsx_
و middleware.page.ts
و pages/users.page.tsx
مثلًا.
تضمين الملفات من غير الصفحات في المجلد pages
لكي تشير إلى الموقع المشترك لملفات الاختبار والملفات المولَّدة وغيرها من الملفات التي تستخدمها المكوّنات في المجلد pages
، بإمكانك وضع بادئة قبل الامتداد مثل page
. افتح الملف next.config.js
وأضف الإعداد pageExtensions
:
module.exports = {
pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js'],
}
أعد بعد ذلك تسمية صفحاتك لتضيف page.
إلى امتداداتها (غير اسم الملف MyPage.tsx
مثلًا إلى MyPage.page.tsx
)
ملاحظة: تأكد من إعادة تسمية الملفات
document.js_
وapp.js_
وmiddleware.js
بالإضافة إلى الملفات الموجودة ضمنpages/api
.
شبكة إيصال المحتوى CDN مع الخيار assetPrefix
تنبيه: يهيئ النشر على Vercel تلقائيًا شبكة إيصال محتوى CDN لمشروع Next.js. لا حاجة لإعداد الخيار
assetPrefix
يدويًا.
ملاحظة: تدعم Next.js ابتداءً من النسخة +9.5 تخصيص مسار أساسي للتطبيق basePath، وهذا يلائم استضافة تطبيقك ضمن مسار فرعي مثل
docs/
. لا حاجة في هذه الحالة إلى استخدامassetPrefix
.
لإعداد شبكة إيصال محتوى CDN يمكنك إعداد بادئة خاصة بالموجودات asset prefix وتهيئة أصل شبكة CDN لتحلل النطاق الذي يستضيف تطبيق Next.js. افتح الملف next.config.js
وأضف الإعداد assetPrefix
:
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
// استخدم شبكة إيصال المحتوى عند الإنتاج و الخادم المحلي عند التطوير
assetPrefix: isProd ? 'https://cdn.mydomain.com' : '',
}
تستخدم تلقائيًا بادئة الموجودات لملفات JavaScript و CSS والتي تُحمَّل من المسار /_next/
(المجلد /next/static.
). سيصبح الطلب التالي:
/_next/static/chunks/4b9b41aaa062cbbfeff4add70f256968c51ece5d.4d708494b3aed70c04f0.js
لجزء من شيفرة JS مثلًا وفق الإعداد السابق كما يلي:
https://cdn.mydomain.com/_next/static/chunks/4b9b41aaa062cbbfeff4add70f256968c51ece5d.4d708494b3aed70c04f0.js
ستعتمد التهيئة الدقيقة لرفع ملفاتك إلى منظومة إيصال محتوى على المنظومة التي تختارها، وسيكون المجلد الوحيد الذي عليك استضافته على منظومة إيصال المحتوى هو محتوى المجلد /next/static.
الذي ينبغي رفعه ليكون على الشكل /next/static_
كما يشير طلب URL. لا ترفع بقية ملفات المجلد /next.
فمن الخطأ عرض شيفرة الخادم وبقية الإعدادات للعموم.
على الرغم من أنّ الإعداد assetPrefix
يغطي الطلبات إلى /next/static_
لكنه لا يؤثر بالمسارات التالية:
- الملفات في المجلد public، فإن أردت تخديم هذه الموجودات عبر CDN، عليك تقديم البادئة بنفسك.
- طلبات
/next/data/_
إلى صفحاتgetServerSideProps
. إذ توجّه هذه الطلبات إلى النطاق الأساسي لكونها غير ساكنة.
- طلبات
/next/data/_
إلى صفحاتgetStaticProps
. إذ توجّه هذه الطلبات إلى النطاق الأساسي لدعم التوليد التدريجي الساكن حتى لو لم تكن تستخدمه (لأغراض الترابط).
الإعدادات المخصصة لمحزّم Webpack
ملاحظة: لم تُغطى التغييرات في إعداد webpack بواسطة مخططات الإصدار SemVer لهذا تابع على مسؤوليتك الشخصية.
قبل أن تتابع بإضافة إعدادات webpack مخصصة إلى تطبيقك تأكد أولًا من عدم دعم Next.js للحالة التي تواجهك:
تتاح بعض الميزات التي تُطلب بكثرة على شكل إضافات:
لكي توسّع طريقة استخدامنا لمحزّم webpack
، بإمكانك تعريف دالة توسّع إعداداته ضمن الملف next.config.js
كالتالي:
module.exports = {
webpack: (
config,
{ buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }
) => {
// Important: return the modified config
return config
},
}
تُنفَّذ الدالة
webpack
مرتين، الأولى للخادم والثانية للعميل. يتيح لك ذلك التمييز بين إعدادات الخادم والعميل من خلال الخاصيةisServer
.
إن الوسيط الثاني للدالة webpack
هو كائن له الخاصيات التالية:
buildId
: من النوعstring
، معرّف البناء، ويُستخدم كمعرّف فريد بين نسخ البناء.dev
: قيمة منطقية تشير إلى أنّ التصريف سيجري في بيئة التطوير أم لا.isServer
: قيمة منطقيةtrue
إن كان التصريف من جانب الخادم وfalse
من جانب العميل.nextRuntime
: من أحد النوعينString | undefined
، وتحدد منصة تنفيذ الشيفرة عندما يجري التصريف من جانب الخادم وتاخذ إحدى القيمتين"edge"
أو"nodejs"
بينما تأخذ القيمةundefined
عند التصريف من جانب العميل.defaultLoaders
: من النوعobject
، وتشير إلى المحمّلات الافتراضية في تستخدم داخليًا في Next.js:babel
: من النوعobject
وتحمّل تهيئةbabel-loader
إليك مثال عن استخدام defaultLoaders.babel
:
//babel-loader مثال عن إضافة محمّل يعتمد على
// @next/mdx المصدر مأخوذ من الإضافة
// https://github.com/vercel/next.js/tree/canary/packages/next-mdx
module.exports = {
webpack: (config, options) => {
config.module.rules.push({
test: /\.mdx/,
use: [
options.defaultLoaders.babel,
{
loader: '@mdx-js/loader',
options: pluginOptions.options,
},
],
})
return config
},
}
الخاصية nextRuntime
تأخذ isServer
القيمة true
عندما تكون قيمة nextRuntime
هي "edge"
أو "nodejs"
. وتستخدم الحالة التي تكون فيها قيمة nextRuntime
هي edge
حاليًا مع البرمجيات الوسطية middleware ومكوّنات الخادم في منصة التشغيل المتقدمة edge فقط.
ضغط المحتوى
تستخدم Next.js تقنية gzip لضغط المحتوى المصيّر والملفات الساكنة. ستحتاج عمومًا لتفعيل الضغط على خوادم HTTP الوكيلة مثل nginx لتفريغ حمولة عملية Node.js
.
لإلغاء الضغط، افتح الملف next.config.js
وعطّل الخيار compress
:
module.exports = {
compress: false,
}
إعداد مرحلة التشغيل
ملاحظة: تحتاج عمومًا إلى استخدام متغيرات البيئة في زمن التشغيل لتطبيق إعداداتك، لأن إعدادات زمن التشغيل تضيف إعدادات التصيير أو التهيئة مسبقًا وهذا لا يتوافق مع التحسين التلقائي الساكن.
لإضافة إعدادات زمن التشغيل إلى التطبيق، افتح الملف next.config.js
وأضف الإعدادين publicRuntimeConfig
و serverRuntimeConfig
:
module.exports = {
serverRuntimeConfig: {
// يُتاح فقط من جانب الخادم
mySecret: 'secret',
secondSecret: process.env.SECOND_SECRET, // يُمرر عبر متغيرات البيئة
},
publicRuntimeConfig: {
// سيكون متاحًا في جانبي الخادم والعميل
staticFolder: '/static',
},
}
ضع أية إعدادات تتعلق بزمن التشغيل على الخادم ضمنserverRuntimeConfig
، وأية إعدادات يمكن الوصول إليها في جانبي الخادم و العميل ضمن publicRuntimeConfig
.
إن اعتمدت الصفحة على
publicRuntimeConfig
فيجب أن تستخدمgetInitialProps
أوgetServerSideProps
أو يجب أن يمتلك التطبيق مكوّنApp
مخصص معgetInitialProps
كي لا تستخدم التحسين التقائي الساكن. لا يمكن استخدام إعدادات زمن التشغيل في أي صفحة أو مكوّن ما لم يُصيّر في جانب الخادم.
للوصول إلى إعدادات زمن التشغيل في تطبيقك، استخدم next/config
كالتالي:
import getConfig from 'next/config'
import Image from 'next/image'
//publicRuntimeConfig و serverRuntimeConfig يضم فقط
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig()
// يتاح فقط في جانب الخادم
console.log(serverRuntimeConfig.mySecret)
// يُتاح في كلا الجانبين
console.log(publicRuntimeConfig.staticFolder)
function MyImage() {
return (
<div>
<Image
src={`${publicRuntimeConfig.staticFolder}/logo.png`}
alt="logo"
layout="fill"
/>
</div>
)
}
export default MyImage
تعطيل الترويسة x-powered-by
تضيف Next.js الترويسة x-powered-by
افتراضيًا. لإلغاء الأمر، افتح الملف next.config.js
وعطّل الإعداد poweredByHeader
:
module.exports = {
poweredByHeader: false,
}
تعطيل ترويسة الاستجابة ETag
تولّد Next.js الترويسة etags لكل صفحة افتراضيًا، وقد ترغب في تعطيل هذه الميزة في بعض الصفحات وفقًا للاستراتيجية التي تستخدمها في التخزين المؤقت، لهذا، افتح الملف next.config.js
وعطّل الإعداد generateEtags
:
module.exports = {
generateEtags: false,
}
تعطيل تحديد مدة الإبقاء على اتصال HTTP
توائم Next.js آلية إحضار البيانات في node لهذا تمكّن تحديد مدة الإبقاء على اتصال HTTP افتراضيًا HTTP Keep-Alive. إن كنت ترغب في تعطيل هذا الإعداد لاستدعاء معين مفرد للدالة ()fetch
أضف الخيار Agent
كالتالي:
import { Agent } from 'https'
const url = 'https://example.com'
const agent = new Agent({ keepAlive: false })
fetch(url, { agent })
ولإلغاء جميع استدعاءات ()fetch
عمومًا استخدم ملف التهيئة next.config.js
:
module.exports = {
httpAgentOptions: {
keepAlive: false,
},
}
إعداد مجلد بناء مخصص
يمكن اختيار الاسم الذي تريده لمجلد بناء مخصص بدلًا من استخدام next.
. فإن أردت ذلك، افتح الملف next.config.js
وأضف الإعداد distDir
:
module.exports = {
distDir: 'build',
}
إن نفّذت الآن الأمر next build
، ستستخدم Next.js المجلد build
بدلًا من المجلد next.
الافتراضي.
ملاحظة: لا يجب أن يقع المجلد خارج مجلد المشروع، فلا يجب أن يكون buid/..
مثلًا.
إعداد معرف فريد للنسخ
تستخدم Next.js معرّفًا ثابتًا فريدًا ID أثناء بناء التطبيق لتحديد الإصدار الذي يُخدّم من تطبيقك. قد يسبب هذا الأمر المشاكل عند نشر التطبيق على عدة خوادم ثم يُنفَّذ الأمر next build
على كل خادم. ولكي تحافظ على معرّف النسخ على جميع الخوادم يمكنك تحديد معرّفًا خاصًا بك للنسخة.
لتنفيذ الأمر، افتح الملف next.config.js
وأضف الدالة generateBuildId
:
module.exports = {
generateBuildId: async () => {
// You can, for example, get the latest git commit hash here
return 'my-build-id'
},
}
إعداد الخيار onDemandEntries
تعرض بعض الخيارات التي تتيح لك التحكم بكيفية تخلص الخادم أو إبقائه لبعض الصفحات المبنية في الذاكرة أثناء التطوير.
لتغيير الإعداد الافتراضي، افتح الملف next.config.js
وأضف الإعداد onDemandEntries
:
module.exports = {
onDemandEntries: {
//(ميلي ثانية) الفترة التي التي يبقي فيها الخادم الصفحات في الذاكرة
maxInactiveAge: 25 * 1000,
// عد الصفحات التي يجب إبقاؤها معًا دون أن تُلغى
pagesBufferLength: 2,
},
}
تجاهل المدقق ESLint
عندما تكتشف Next.js وجود ESLint في تطبيقك فإنها تُحبط عملية البناء next build
عند وجود أي خطأ مصدره المدقق ESLint. لكن إن أردت من Next.js أن تبني نسخة إنتاج حتى لو وجودت أخطاء مصدرها ESLint، يمكنك تعطيل خطوة التدقيق المدمجة بالكامل. لا ننصحك بهذا الخيار إلا إن كنت قد هيأت مسبقًا ESLint ليعمل ضمن مرحلة أخرى من مراحل عملك (كمرحلة التكامل المتواصل CI).
لتعطيل ESLint، افتح الملف next.config.js
ومكِّن الخيار ignoreDuringBuilds
ضمن الإعداد eslint
:
module.exports = {
eslint: {
// ESLint يسمح ذلك بنجاح بناء التطبيق حتى لو كانت هناك أخطاء في المدقق
ignoreDuringBuilds: true,
},
}
تجاهل أخطاء TypeScript
تُحبط Next.js عملية البناء next build
عند وجود أي خطأ مصدره TypeScript. لكن إن أردت من Next.js أن تبني نسخة إنتاج حتى لو وجودت أخطاء مصدرها TypeScript (وهذا أمر خطر)، يمكنك تعطيل خطوة التحقق المدمجة من أخطاء TypeScript بالكامل.
تأكد عند تعطيل تلك الخطوة، أنك ستتحقق من الأنواع خلال عملية البناء أو النشر، وإلا كان عملك محفوفًا بالمخاطر.
افتح الملف next.config.js
ومكّن الخيار ignoreBuildErrors
ضمن الإعداد typescript
module.exports = {
typescript: {
// !! تحذير !!
// Typescript يسمح ذلك بنجاح بناء التطبيق حتى لو كانت هناك أخطاء في
ignoreBuildErrors: true,
},
}
استخدام الإعداد exportPathMap
هذه الميزة محصورة باستخدام
next export
. عد إلى الصفحة "تصدير التطبيق إلى صفحات HTML ساكنة" من هذا التوثيق.
يتيح لك هذا الإعداد تحديد علاقة بين مسارات الطلب وصفحات الوجهة، كي تُستخدم أثناء التصدير. تُتاح المسارات المعرّفة داخل الإعداد exportPathMap
أيضًا عند تنفيذ الأمر next dev
.
لنبدأ بمثال بسيط لإنشاء شبكة علاقات exportPathMap
مخصصة لتطبيق يضم الصفحات التالية:
pages/index.js
pages/about.js
pages/post.js
افتح الملف وأضف الشيفرة التالية ضمن الإعداد exportPathMap
:
module.exports = {
exportPathMap: async function (
defaultPathMap,
{ dev, dir, outDir, distDir, buildId }
) {
return {
'/': { page: '/' },
'/about': { page: '/about' },
'/p/hello-nextjs': { page: '/post', query: { title: 'hello-nextjs' } },
'/p/learn-nextjs': { page: '/post', query: { title: 'learn-nextjs' } },
'/p/deploy-nextjs': { page: '/post', query: { title: 'deploy-nextjs' } },
}
},
}
ملاحظة: لا يمكن أن تستخدم الحقل query
من exportPathMap
مع الصفحات الساكنة المحسّنة تلقائيًا أو مع صفحات getStaticProps
لأنها تُصيَّر إلى ملفات HTML أثناء البناء، ولا يمكن الحصول على معلومات استعلام إضافية خلال التصدير next export
.
تُصدّر الصفحات بعد ذلك إلى ملفات HTML، إذ تصبح الصفحة about/
مثلًا about.html/
.
إن exportPathMap
هي دالة غير متزامنة تقبل وسيطين أولهما defaultPathMap
ويمثّل مخطط ارتباط Next.js الافتراضي، أما الوسيط الثاني فهو كائن له الخاصيات التالية:
dev
: يأخذ القيمةtrue
عندما تُستدعىexportPathMap
في بيئة التطوير وfalse
عند تنفيذnext export
. يُستخدمexportPathMap
في بيئة التطوير لتعريف الوجهات.dir
: المسار المطلق إلى مجلد المشروع.outDir
: المسار المطلق إلى المجلد/out
وستكون قيمتهnull
عندما تكون قيمةdev
هيtrue
.distDir
: المسار المطلق إلى المجلد/next.
(يُهيّأ من خلال الإعدادdistDir
).buildId
: معرّف النسخة الفريد ID.
إن الكائن المعاد هو مخطط ارتباط مع الصفحات مفاتيحه key
هي أسماء المسارات pathname
وقيمه value
كائنات تقبل الحقول التالية:
page
: من النوعString
، وهي الصفحة التي تُصيّر ضمن المجلدpages
.query
: من النوعObject
، وهو الكائنquery
الممرر إلىgetInitialProps
عند التصيير، وقيمته الافتراضية{}
.
يمكن أن يكون اسم المسار
pathname
المعروض اسم ملف (مثلreadme.md/
)، لكن قد يكون عليك ضبط ترويسة نوع المحتوىContent-Type
على القيمةtext/html
إن كان محتواه مختلفًا عن HTML.
تخصيص مجلد للخرج
يستخدم الأمر next export
المجلد out
افتراضيًا لوضع ملفات الخرج فيه، بإمكانك تخصيص مجلد آخر لهذه الغاية باستخدام الوسيط o-
كالتالي:
next export -o outdir
تحذير: جرى إهمال استخدام exportPathMap
لتعريف وجهات routes مع أي صفحة مولدة عبر getStaticPaths
ولا ننصح باستعمالهما كلاهما.
انظر المثال Static Export.
محرف "/" الزائد
يمكن ضبط Next.js لتصدير الصفحات بالشكل index.html التي تتطلب إضافة محرف "/" الزائد في نهاية العنوان، مثلًا about/
تصبح about/index.html/
. ويمكن الوصول إليها عبر المسار /about/
وقد كان هذا السلوك الافتراضي قبل الإصدار 9.
لاستعادة هذا السلوك، افتح الملف next.config.js
وأضف الإعداد trailingSlash
كالتالي:
module.exports = {
trailingSlash: true,
}
هكذا سيُعاد توجيه العنوان about/
إلى /about/
.
النمط الصارم في React
اقتراح: نقترح بشدة استخدام هذا الوضع في تطبيقات Next.js لتحضير تطبيقك بشكل أفضل لإصدارت React المستقبلية.
إن النمط الصارم في React هو وضع تطوير فقط، كي يشير إلى الأخطاء المحتملة في التطبيق. إذ يفيدك في تحديد دورات العمل غير الآمنة واستخدام الواجهات البرمجية القديمة وغيرها من الميزات الأخرى. تدعم Next.js النمط الصارم في مرحلة زمن التشغيل، ولكي تستخدمه، اضبط الخيار التالي في الملف next.config.js
:
// next.config.js
module.exports = {
reactStrictMode: true,
}
إن لم تكن مستعدًا مع فريقك للعمل مع هذا النمط، لا بأس بذلك! يمكنك الانتقال إليه تدريجيًا صفحة صفحة باستخدام <React.StrictMode>
.
إدراج وحدات خارجية من خلال عناوين URL
إن الإدراج من خلال عناوين URL هي ميزة تجريبية تسمح بإدراج وحدات برمجية مباشرة من خوادم خارجية (بدلًا من القرص المحلي).
تنبيه: هذه الميزة تجريبية، لهذا استخدم النطاقات التي تثق بها فقط لتزيل وتنفيذ الشيفرة على جهازك. استخدم الميزة بتروٍ وحذر حتى نشير إلى هذه الميزة على أنها مستقرة stable.
لاستخدام الميزة، أضف العناوين المسموحة إلى الإعداد urlImports
في الملف next.config.js
:
module.exports = {
experimental: {
urlImports: ['https://example.com/assets/', 'https://cdn.skypack.dev'],
},
}
بإمكانك حينها إدراج الوحدات من عنوان URL مباشرة في تطبيقك:
import { a, b, c } from 'https://example.com/modules/some/module.js'
يمكن استخدام هذه الميزة في أي مكان يمكن فيه إدراج حزمة اعتيادية.
الأمان
صُممت هذه الميزة ليكون الأمان أولويتها القصوى. إذ أضفنا بدايةً رايةً تجريبيةً تجبرك على التصريح بسماحك للإدراج من عنوان محدد. نعمل الآن على حصر عمل الوحدات المدرجة من عناوين خارجية ضمن بيئة معزولة sandbox في المتصفح باستخدام بيئة التشغيل المتقدمة Edge Runtime التي تُستخدم من قبل البرمجيات الوسطية و Next.js Live.
إقفال الملفات
تُنشئ Next.js ملفًا مقفلًا في المجلد next.lock
عند الإدراج من عناوين URL. يُفترض أن يُدفع هذا المجلد إلى Git ولا ينبغي تضمينه في الملف gitignore.
- عند تنفيذ الأمر
next dev
، تنزّل Next.js وتضيف كل الوحدات المدرجة من عناوين URL إلى الملف المقفل. - عند تنفيذ الأمر
next build
، تستخدم Next.js الملف المقفل فقط لبناء التطبيق لمرحلة الإنتاج.
لا حاجة عادة إلى أية طلبات شبكة وسيسبب أي ملف مقفل منتهي الصلاحية إحباط البناء. أما الاستثناء الوحيد لهذه الحالة فهي الموارد التي تستجيب بالترويسة Cache-Control: no-cache
إذ لا تمتلك هذه الموارد المدخل no-cache
في الملف المقفل، وبالتالي لا بد من إحضارها عند كل عملية بناء.
أمثلة
إدراج Skypack
import confetti from 'https://cdn.skypack.dev/canvas-confetti'
import { useEffect } from 'react'
export default () => {
useEffect(() => {
confetti()
})
return <p>Hello</p>
}
إدراج صور ساكنة
import Image from 'next/image'
import logo from 'https://github.com/vercel/next.js/raw/canary/test/integration/production/public/vercel.png'
export default () => (
<div>
<Image src={logo} placeholder="blur" />
</div>
)
عناوين ضمن CSS
.className {
background: url('https://github.com/vercel/next.js/raw/canary/test/integration/production/public/vercel.png');
}
إدراج ملفات ساكنة
const logo = new URL('https://example.com/assets/file.txt', import.meta.url)
console.log(logo.pathname)
// prints "/_next/static/media/file.a9727b5d.txt"
مؤشر بناء التطبيق
عندما تحرر الشيفرة وتصرّف التطبيق في Next.js، سيظهر مؤشر التصريف في أسفل يمين الصفحة.
ملاحظة: يظهر هذا المؤشر في وضع التطوير فقط ولن يظهر أثناء بناء وتشغيل التطبيق في نمط الإنتاج.
قد يتوضع هذا المؤشر في مكان خاطئ ضمن الصفحة، فإن أردت تغيير موضعه، افتح الملف next.config.js
واضبط قيمة الخيار buildActivityPosition
ضمن الكائن devIndicators
على bottom-right
(افتراضي)، أو bottom-left
أو top-right
أو top-left
:
module.exports = {
devIndicators: {
buildActivityPosition: 'bottom-right',
},
}
وقد لا يفيدك هذا المؤشر في بعض الحالات، لذلك بالإمكان إزالته بتعطيل الإعداد buildActivity
ضمن الكائن devIndicators
:
module.exports = {
devIndicators: {
buildActivity: false,
},
}
المصادر
- الصفحات Next.config.js من توثيق Next.js الرسمي.