الفرق بين المراجعتين لصفحة: «Next.js/migrating»
لا ملخص تعديل |
جميل-بيلوني (نقاش | مساهمات) ط مراجعة |
||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:الانتقال إلى Next.js}}</noinclude> | <noinclude>{{DISPLAYTITLE:الانتقال إلى Next.js}}</noinclude> | ||
صُمِّمت Next.js لكي يجري تبنيها تدريجيًا، إذ ستكون قادرًا على متابعة العمل على شيفرة جاهزة وإضافة المقدار الذي تريده من شيفرة React. فإن بدأت بكمية صغيرة من الشيفرة ووسعتها تدريجيًا بإضافة صفحات جديدة، | صُمِّمت Next.js لكي يجري تبنيها تدريجيًا، إذ ستكون قادرًا على متابعة العمل على شيفرة جاهزة حالية وإضافة المقدار الذي تريده من شيفرة React. فإن بدأت بكمية صغيرة من الشيفرة ووسعتها تدريجيًا بإضافة صفحات جديدة، سيسهل ذلك عليك تبني Next.js في مشاريعك وتجنب إعادة كتابة كل شيء بالكامل. | ||
== استراتيجيات العمل == | == استراتيجيات العمل == | ||
=== المسارات الفرعية === | === المسارات الفرعية Subpath === | ||
تقتضي الاستراتيجية الأولى بتهيئة الخادم أو الخادم الوكيل لوضع كل ما يتعلق بتطبيق Next.js في نفس المسار الفرعي (ضمن مجلد فرعي). فقد يكون موقعك الإلكتروني مثلًا <code>example.com</code> ومن ثم تهيئ المسار الفرعي <code>example.com/store</code> على الخادم ليضم تطبيق لمتجر إلكتروني. | تقتضي الاستراتيجية الأولى بتهيئة الخادم أو الخادم الوكيل لوضع كل ما يتعلق بتطبيق Next.js في نفس المسار الفرعي (ضمن مجلد فرعي). فقد يكون موقعك الإلكتروني مثلًا <code>example.com</code> ومن ثم تهيئ المسار الفرعي <code>example.com/store</code> على الخادم ليضم تطبيق لمتجر إلكتروني. | ||
بإمكانك تهيئة | بإمكانك تهيئة أصول assets وروابط تطبيق Next.js لتعمل تلقائيًا عند طلب الوجهة <code>store/</code>، وذلك باستخدام [[Next.js/next.config.js|<code>basePath</code>]]. وبما أن كل صفحة من صفحات Next.js هي وجهة قائمة بنفسها، يمكنك الوصول إلى الصفحة <code>pages/products.js</code> مثلًا عبر المسار <code>example.com/store/products</code>. <syntaxhighlight lang="javascript"> | ||
// next.config.js | // next.config.js | ||
سطر 13: | سطر 13: | ||
basePath: '/store', | basePath: '/store', | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== الدالة rewrites == | == الدالة rewrites == | ||
تقتضي الاستراتيجية الثانية إنشاء تطبيق Next.js جديد يشير إلى عنوان URL الجذري للنطاق domain الذي تستخدمه. استخدم بعد ذلك الدالة [[Next.js/next.config.js|<code>rewrites</code>]] ضمن ملف التهيئة لكي تُحوَّل بعض المسارات إلى التطبيق الموجود. | تقتضي الاستراتيجية الثانية إنشاء تطبيق Next.js جديد يشير إلى عنوان URL الجذري للنطاق domain الذي تستخدمه. استخدم بعد ذلك الدالة [[Next.js/next.config.js|<code>rewrites</code>]] ضمن ملف التهيئة لكي تُحوَّل بعض المسارات إلى التطبيق الموجود. | ||
لنفرض مثلًا أنك أنشأت تطبيق Next.js كي يُخدّم عبر النطاق <code>example.com</code> وله ملف التهيئة <code>next.config.js</code>. عندها ستتعامل Next.js مع الصفحات التي أضفتها إلى تطبيقك (مثل <code>about/</code> إن أضفت <code>pages/about.js</code>)، بينما ستحوّل أية طلبات أخرى (مثل <code>dashboard/</code>) إلى <code>proxy.example.com</code>.<syntaxhighlight lang="javascript"> | |||
لنفرض مثلًا أنك أنشأت تطبيق Next.js كي يُخدّم عبر النطاق <code>example.com</code> وله ملف التهيئة <code>next.config.js</code>. عندها ستتعامل Next.js مع الصفحات التي أضفتها إلى تطبيقك (مثل <code>about/</code> إن أضفت <code>pages/about.js</code>)، بينما ستحوّل أية طلبات أخرى (مثل <code>dashboard/</code>) إلى <code>proxy.example.com</code>. | |||
'''ملاحظة''': إن كنت تستعمل <code>fallback: true/'blocking'</code> في <code>getStaticPaths</code>، فلن يعمل الالتقاط الكامل catch-all ضمن <code>rewrites</code> المُعرف في الملف <code>next.config.js</code> إذ ستلتقطها <code>getStaticPaths</code>.<syntaxhighlight lang="javascript"> | |||
// next.config.js | // next.config.js | ||
سطر 36: | سطر 39: | ||
//في الإصدارات مادون 10.1 rewrite يمكنك استخدام الدالة غير الفعالة | //في الإصدارات مادون 10.1 rewrite يمكنك استخدام الدالة غير الفعالة | ||
return [ | return [ | ||
// | // لابد من تعريف دالة غير فعالة لتحرض عملية التحقق | ||
// من كل الصفحات الساكنة قبل أن نحاول تحويل المسار | // من كل الصفحات الساكنة قبل أن نحاول تحويل المسار | ||
{ | { | ||
سطر 49: | سطر 52: | ||
}, | }, | ||
} | } | ||
</syntaxhighlight>< | </syntaxhighlight>'''ملاحظة''': إن كنت تنتقل تدريجيا إلى الوجهات الديناميكية مثل <code>[slug]</code> وكنت تستعمل <code>fallback: true</code> أو <code>fallback: 'blocking'</code> مع <code>rewrite</code>، فتأكد من أن تشمل حالة عدم العثور على صفحة page not found، إذ عندما تلتقط Next.js الوجهات الديناميكية فإنها تتوقف عن التحقق من أي وجهات أخرى. استعمال <code>notFound: true</code> في <code>getStaticProps</code> سيعيد صفحة 404 دون تطبيق <code>rewrite</code>، فإن لم تكن ترغب بذلك، يمكنك استعمال <code>getServerSideProps</code> مع ترويسة التحكم بالتخزين المؤقت <code>stale-while-revalidate</code> عند إعادة الخاصيات props وبعدها يمكنك إعادة التوجيه proxy يدويًا إلى الواجهة الخلفية الحالية باستعمال أدوات مثل [https://github.com/vercel/next.js/discussions/38839#discussioncomment-3744442 http-proxy] بدلًا من إعادة <code>notFound: true</code>. | ||
=== واجهات أمامية مُصغرة مع مستودعات مفردة ونطاقات فرعية === | |||
=== واجهات أمامية | تجعل Next.js و Vercel عملية بناء الواجهات الأمامية المصغّرة أو المجزّأة [https://martinfowler.com/articles/micro-frontends.html micro-frontends] ونشرها إلى مستودع مفرد [https://vercel.com/blog/monorepos Monorepo] أمرًا مباشرًا وبسيطًا. يسمح لك ذلك باستخدام النطاقات الفرعية لتبنّي تطبيقات جديدة تدريجيًا. ومن مزايا استخدام الواجهة الأمامية المصغّرة: | ||
* صغر حجمها وتماسكها وسهولة إدارة شيفرتها. | * صغر حجمها وتماسكها وسهولة إدارة شيفرتها. | ||
سطر 61: | سطر 63: | ||
== الانتقال من Gatesby == | == الانتقال من Gatesby == | ||
يساعدك هذا الدليل في نقل تطبيقك Gatsby إلى تطبيق | يساعدك هذا الدليل في نقل تطبيقك Gatsby إلى تطبيق Next.js؛ إذ يسمح لك الانتقال إلى Next.js أن: | ||
* تختار استراتيجية [[Next.js/data fetching|إحضار البيانات]] التي تريد لكل صفحة بشكل مستقل. | * تختار استراتيجية [[Next.js/data fetching|إحضار البيانات]] التي تريد لكل صفحة بشكل مستقل. | ||
سطر 72: | سطر 74: | ||
وهي الخطوة الأولى في عملية الانتقال وعليك تنفيذ ما يلي: | وهي الخطوة الأولى في عملية الانتقال وعليك تنفيذ ما يلي: | ||
* إزالة كل الحزم | * إزالة كل الحزم المتعلقة ب Gatsby (ابق فقط <code>react</code> و <code>react-dom</code>) | ||
* ثبِّت <code>next</code>. | * ثبِّت <code>next</code>. | ||
* أضف الأوامر | * أضف الأوامر Next.js إلى <code>scripts</code> وأولها <code>next dev</code> الذي يشغّل خادم التطوير على العنوان <code>localhost:3000</code>. أما ثانيها فهو <code>next build</code> و <code>next start</code> لإنشاء وتشغيل نسخة الإنتاج. | ||
إليك مثالًا عن <code>package.json</code>:<syntaxhighlight lang="json"> | إليك مثالًا عن <code>package.json</code>:<syntaxhighlight lang="json"> | ||
سطر 91: | سطر 93: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== | === الأصولو الساكنة والخرج المُصرَّف === | ||
تستخدم Gatsby المجلد <code>public</code> لوضع ملفات الخرج المصرَّفة بينما تستخدم Next.js هذا المجلد لوضع | تستخدم Gatsby المجلد <code>public</code> لوضع ملفات الخرج المصرَّفة بينما تستخدم Next.js هذا المجلد لوضع الأصول الساكنة static assets. إليك خطوات الانتقال في هذه المرحلة: | ||
* أزل الإشارة إلى المجلدين <code>/cache.</code> و <code>public</code> من الملف <code>gitignore.</code> واحذف المجلدين. | * أزل الإشارة إلى المجلدين <code>/cache.</code> و <code>public</code> من الملف <code>gitignore.</code> واحذف المجلدين. | ||
سطر 98: | سطر 100: | ||
* أضف <code>next.</code> إلى <code>gitignore.</code>. | * أضف <code>next.</code> إلى <code>gitignore.</code>. | ||
=== إنشاء الوجهات === | === إنشاء الوجهات Routes === | ||
تدعم كلا | تدعم كلا Gatsby و Next المجلد <code>pages</code> الذي يستخدم [[Next.js/Routing|أسلوب توجيه يعتمد على نظام الملفات]]. تستخدم المجلد <code>src/pages</code> الذي [[Next.js/src directory|تدعمه أيضًا Next.js]]. تُنشئ Gatsby الوجهات الديناميكية باستخدام الواجهة البرمجية <code>createPages</code> ضمن الملف <code>gatsby-node.js</code>. ويمكنك في Next استخدام [[Next.js/Routing#.D8.A7.D9.84.D9.88.D8.AC.D9.87.D8.A7.D8.AA%20.D8.A7.D9.84.D8.AF.D9.8A.D9.86.D8.A7.D9.85.D9.8A.D9.83.D9.8A.D8.A9%20.D9.81.D9.8A%20Next.js|الوجهات الديناميكية]] ضمن المجلد <code>pages</code> للحصول على نفس التأثير. وبدلًا من وجود مجلد بالاسم <code>template</code>، يمكنك استخدام مكوّنات React ضمن ملف الوجهة الديناميكية: | ||
* '''في Gatsby''': أنشئ مسارات ديناميكية لكل منشور مثلًا باستخدام الواجهة <code>createPages</code> ومن ثم أنشئ ملفًا يمثل قالبًا لهذه المنشورات ضمن <code>src/templates/blog-post.js</code>. | * '''في Gatsby''': أنشئ مسارات ديناميكية لكل منشور مثلًا باستخدام الواجهة <code>createPages</code> ومن ثم أنشئ ملفًا يمثل قالبًا لهذه المنشورات ضمن <code>src/templates/blog-post.js</code>. | ||
سطر 131: | سطر 133: | ||
=== إحضار البيانات === | === إحضار البيانات === | ||
يظهر الاختلاف الجذري بين Gatsby و Next.js في طريقة إحضار البيانات. إذ يرتكز خيار Gatsby على "GraphQL" في إحضار البيانات إلى التطبيق، بينما عليك أن تختار في Next.js الاستراتيجية التي تريد ومن ضمنها "GraphQL". | يظهر الاختلاف الجذري بين Gatsby و Next.js في طريقة إحضار البيانات. إذ يرتكز خيار Gatsby على "GraphQL" في إحضار البيانات إلى التطبيق، بينما عليك أن تختار في Next.js الاستراتيجية التي تريد ومن ضمنها "GraphQL". | ||
تستخدم Gatsby الدالة <code>graphql</code> لاستعلام البيانات في صفحات الموقع بما فيها البيانات المحلية والبعيدة ومعلومات التهيئة الخاصة بالموقع، كما تسمح بإنشاء صفحات ساكنة فقط. أما في Next.js، بإمكانك اختيار استراتيجية [[Next.js/data fetching|إحضار البيانات]] الخاصة بكل [[Next.js/pages|صفحة]]. إذ تسمح لك الدالة <code>getServerSideProps</code> مثلًا بتنفيذ التصيير من جانب الخادم، بينما بإمكانك تصدير الدالتين <code>getStaticProps</code> / <code>getStaticPaths</code> ضمن الصفحة لتوليد صفحات ساكنة بدلًا من تنفيذ <code>pageQuery</code>. إليك مثالًا:<syntaxhighlight lang="javascript"> | تستخدم Gatsby الدالة <code>graphql</code> لاستعلام البيانات في صفحات الموقع بما فيها البيانات المحلية والبعيدة ومعلومات التهيئة الخاصة بالموقع، كما تسمح بإنشاء صفحات ساكنة فقط. أما في Next.js، بإمكانك اختيار استراتيجية [[Next.js/data fetching|إحضار البيانات]] الخاصة بكل [[Next.js/pages|صفحة]]. إذ تسمح لك الدالة <code>getServerSideProps</code> مثلًا بتنفيذ التصيير من جانب الخادم، بينما بإمكانك تصدير الدالتين <code>getStaticProps</code> / <code>getStaticPaths</code> ضمن الصفحة لتوليد صفحات ساكنة بدلًا من تنفيذ <code>pageQuery</code>. إليك مثالًا:<syntaxhighlight lang="javascript"> | ||
سطر 170: | سطر 170: | ||
} | } | ||
} | } | ||
</syntaxhighlight>سترى عادة ملحقات plugins في Gatsby لقراءة منظومة الملفات | </syntaxhighlight>سترى عادة ملحقات plugins في Gatsby لقراءة منظومة الملفات <code>gatsby-source-filesystem</code> أو التعامل مع تنسيق Markdown من خلال <code>gatsby-transformer-remark</code> وغيرها. فالمثال النموذجي الأكثر شعبية لمبتدئي تطبيقات المنشورات، قد استخدم [https://github.com/gatsbyjs/gatsby-starter-blog/blob/master/package.json 15 حزمة Gatsby] خاصة. تأخذ Next في المقابل نهجًا آخر، إذ تُضمِّن الميزات كثيرة الاستعمال مباشرة ضمن إطار العمل، وتمنح المستخدم تحكمًا كاملًا في دعم التطبيق بحزم خارجية. فبدلًا من فصل شيفرة القراءة من منظومة الملفات ضمن ملحق، بإمكانك استخدام حزمة Node.js الأصلية <code>fs</code> ضمن الدالتين <code>getStaticProps</code> / <code>getStaticPaths</code> لقراءة منظومة الملفات:<syntaxhighlight lang="javascript"> | ||
// src/lib/blog.js | // src/lib/blog.js | ||
//date-fns و gray-matter ثبِّت | //date-fns و gray-matter ثبِّت | ||
سطر 198: | سطر 198: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== | === مكون الصور وتحسين الصور === | ||
تمتلك Next.js [[Next.js/image optimization|مكوِّن صور مدمج وطريقة تحسين مدمجة للصور]]. إذ يُعد المكوِّن [[Next.js/next image|<code>next/image</code>]] امتدادًا لعنصر الصورة <code><img></code> في HTML، وقد طوّر ليلائم مواقع الويب الحديثة. | تمتلك Next.js [[Next.js/image optimization|مكوِّن صور مدمج وطريقة تحسين مدمجة للصور]]. إذ يُعد المكوِّن [[Next.js/next image|<code>next/image</code>]] امتدادًا لعنصر الصورة <code><img></code> في HTML، وقد طوّر ليلائم مواقع الويب الحديثة. | ||
يتيح لك التحسين التقائي للصور إعادة تحجيم الصورة وتحسينها وتقديمها بامتدادات حديثة مثل [https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types WebP] عندما يدعمها المتصفح. يقلل ذلك من الدفع بصورة كبيرة إلى أجهزة لها نافذة عرض صغيرة، كما يسمح | يتيح لك التحسين التقائي للصور إعادة تحجيم الصورة وتحسينها وتقديمها بامتدادات حديثة مثل [https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types WebP] عندما يدعمها المتصفح. يقلل ذلك من الدفع بصورة كبيرة إلى أجهزة لها نافذة عرض صغيرة، كما يسمح لـ Next.js بالتبني التلقائي لتنسيقات الصور المستقبلية، وتقديمها للمتصفح الذي يدعمها. | ||
==== الإنتقال بالصور من Gatsby ==== | ==== الإنتقال بالصور من Gatsby ==== | ||
سطر 241: | سطر 241: | ||
ستجد البيانات الوصفية (الاسم والوصف وغيرها) للموقع المبني باستخدام Gatsby ضمن الملف <code>gatsby-config.js</code> وتُستعرض بعد ذلك من قبل واجهة GraphQL البرمجية التي تتعامل معها من خلال <code>pageQuery</code> أو من خلال استعلام ساكن ضمن المكوّن. | ستجد البيانات الوصفية (الاسم والوصف وغيرها) للموقع المبني باستخدام Gatsby ضمن الملف <code>gatsby-config.js</code> وتُستعرض بعد ذلك من قبل واجهة GraphQL البرمجية التي تتعامل معها من خلال <code>pageQuery</code> أو من خلال استعلام ساكن ضمن المكوّن. | ||
لكن يُفضَّل في Next.js إنشاء ملف تهيئة يُشابه في محتواه الشيفرة | لكن يُفضَّل في Next.js إنشاء ملف تهيئة يُشابه في محتواه الشيفرة التالية؛ ومن ثم تستطيع إدراج هذه الملف في أي مكان دون الحاجة لاستخدام GraphQL للولوج إلى البيانات الوصفية للموقع:<syntaxhighlight lang="javascript"> | ||
// src/config.js | // src/config.js | ||
سطر 258: | سطر 258: | ||
=== تحسين نتائج البحث في محركات البحث === | === تحسين نتائج البحث في محركات البحث === | ||
تستخدم معظم أمثلة Gatsby العنصر <code>react-helmet</code> للمساعدة في إضافة بيانات وصفية <code>meta</code> لأغراض تحسين نتيجة ظهور الموقع في محركات البحث SEO. تستخدم Next.js في المقابل المكوّن [[Next.js/next head|<code>next/head</code>]] لإضافة هذه البيانات إلى العنصر <code></ head></code>. إليك مثالًا عن مكوّن SEO | تستخدم معظم أمثلة Gatsby العنصر <code>react-helmet</code> للمساعدة في إضافة بيانات وصفية <code>meta</code> لأغراض تحسين نتيجة ظهور الموقع في محركات البحث SEO. تستخدم Next.js في المقابل المكوّن [[Next.js/next head|<code>next/head</code>]] لإضافة هذه البيانات إلى العنصر <code></ head></code>. إليك مثالًا عن مكوّن SEO في Gatsby:<syntaxhighlight lang="javascript"> | ||
// src/components/seo.js | // src/components/seo.js | ||
سطر 343: | سطر 343: | ||
وهي الخطوة الأولى في عملية الانتقال وعليك تنفيذ ما يلي: | وهي الخطوة الأولى في عملية الانتقال وعليك تنفيذ ما يلي: | ||
* إزالة | * إزالة حزم <code>react</code> (ابق فقط <code>react</code> و <code>react-dom</code>). إن كنت تستخدم React Router يمكنك إزالة <code>react-router-dom</code> أيضًا. | ||
* ثبِّت <code>next</code>. | * ثبِّت <code>next</code>. | ||
* أضف | * أضف أوامر Next.js إلى <code>scripts</code> وأولها <code>next dev</code> الذي يشغّل خادم التطوير على العنوان <code>localhost:3000</code>. أما ثانيها فهو <code>next build</code> و <code>next start</code> لإنشاء وتشغيل نسخة الإنتاج. | ||
إليك مثالًا عن <code>package.json</code>:<syntaxhighlight lang="json"> | إليك مثالًا عن <code>package.json</code>:<syntaxhighlight lang="json"> | ||
سطر 362: | سطر 362: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== | === الأصول الساكنة والخرج المُصرَّف === | ||
تستخدم Create React App المجلد <code>public</code> لوضع ملفات HTML التي تُمثِّل نقاط دخول إلى التطبيق والموجودات الساكنة بينما تستخدم Next.js هذا المجلد لوضع | تستخدم Create React App المجلد <code>public</code> لوضع ملفات HTML التي تُمثِّل نقاط دخول إلى التطبيق والموجودات الساكنة بينما تستخدم Next.js هذا المجلد لوضع الأصول الساكنة static assests فقط. إليك خطوات الانتقال في هذه المرحلة: | ||
* انقل أية صور أو خطوط أو أية موجودات ساكنة أخرى إلى المجلد | * انقل أية صور أو خطوط أو أية الأصول أو موجودات ساكنة أخرى إلى المجلد <code>public</code>. | ||
* حوّل الملف <code>index.html</code> (نقطة الدخول إلى التطبيق) إلى Next.js، وينبغي نقل أية شيفرات | * حوّل الملف <code>index.html</code> (نقطة الدخول إلى التطبيق) إلى Next.js، وينبغي نقل أية شيفرات <code><head></code> ضمنه إلى [[Next.js/custom document|مستند مخصص <code>document.js_</code>]]، وكذلك أية تخطيطات layouts مشتركة بين الصفحات إلى [[Next.js/custom app|تطبيق APP مخصص]]. | ||
* أضف <code>next.</code> إلى <code>gitignore.</code>. | * أضف <code>next.</code> إلى <code>gitignore.</code>. | ||
سطر 379: | سطر 379: | ||
* أما الوجهات التي تتطلب مساراتها محتوى ديناميكي (مثل <code>blog/:slug/</code>)، بإمكانك استخدام الوجهات الديناميكية في Next.js (مثل <code>pages/blog/[slug].js</code>). يمكن الوصول إلى قيمة <code>slug</code> من خلال معامل استعلام. إذ يمكن مثلًا الوصول إلى المنشور <code>blog/first-post/</code> انطلاقًا من القالب <code>pages/blog/[slug].js</code> من خلال كائن الاستعلام <code>{ 'slug': 'first-post' }</code>. | * أما الوجهات التي تتطلب مساراتها محتوى ديناميكي (مثل <code>blog/:slug/</code>)، بإمكانك استخدام الوجهات الديناميكية في Next.js (مثل <code>pages/blog/[slug].js</code>). يمكن الوصول إلى قيمة <code>slug</code> من خلال معامل استعلام. إذ يمكن مثلًا الوصول إلى المنشور <code>blog/first-post/</code> انطلاقًا من القالب <code>pages/blog/[slug].js</code> من خلال كائن الاستعلام <code>{ 'slug': 'first-post' }</code>. | ||
=== التنسيق === | |||
تقدم Next.js [[Next.js/built in css support|دعمًا مدمجًا لتنسيق CSS و SaSS و CSS-in-JS]]. كما يسمح Create React App بإدراج ملفات <code>css.</code> مباشرة ضمن المكوّنات. تسمح Next.js بنفس هذا الأسلوب أيضًا، لكن لا بد أن تكون هذه الملفات [[Next.js/built in css support|وحدات تنسيق CSS]]. أما بالنسبة للتنسيقات العامة، ستحتاج إلى [[Next.js/custom app|تطبيق App مخصص]] لإضافتها. | تقدم Next.js [[Next.js/built in css support|دعمًا مدمجًا لتنسيق CSS و SaSS و CSS-in-JS]]. كما يسمح Create React App بإدراج ملفات <code>css.</code> مباشرة ضمن المكوّنات. تسمح Next.js بنفس هذا الأسلوب أيضًا، لكن لا بد أن تكون هذه الملفات [[Next.js/built in css support|وحدات تنسيق CSS]]. أما بالنسبة للتنسيقات العامة، ستحتاج إلى [[Next.js/custom app|تطبيق App مخصص]] لإضافتها. | ||
=== الولوج الآمن إلى واجهة | === الولوج الآمن إلى واجهة الويب البرمجية === | ||
يمكن الوصول إلى الواجهة <code>window</code> أو<code>localStorage</code> أو <code>navigator</code> وغيرها من واجهات ويب البرمجية مباشرة عبر التطبيقات التي تُصيَّر من جانب العميل. لكن طالما أن Next.js تستخدم التصيير المسبق، لا بد من الوصول إلى تلك الواجهات بطريقة آمنة عندما يكون المستخدم في الواجهة الأمامية. تسمح الشيفرة التالية مثلًا بالوصول إلى الواجهة <code>window</code> من جهة العميل فقط (من الواجهة الأمامية):<syntaxhighlight lang="javascript"> | يمكن الوصول إلى الواجهة <code>window</code> أو <code>localStorage</code> أو <code>navigator</code> وغيرها من واجهات ويب البرمجية مباشرة عبر التطبيقات التي تُصيَّر من جانب العميل. لكن طالما أن Next.js تستخدم التصيير المسبق، لا بد من الوصول إلى تلك الواجهات بطريقة آمنة عندما يكون المستخدم في الواجهة الأمامية. تسمح الشيفرة التالية مثلًا بالوصول إلى الواجهة <code>window</code> من جهة العميل فقط (من الواجهة الأمامية):<syntaxhighlight lang="javascript"> | ||
if (typeof window !== 'undefined') { | if (typeof window !== 'undefined') { | ||
//الآن window يمكنك الوصول إلى ` | //الآن window يمكنك الوصول إلى ` | ||
سطر 418: | سطر 419: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== | === متغيرات البيئة === | ||
تدعم [[Next.js/environment variables|متغيرات البيئة]] <code>env.</code> كما يفعل Create React App، ويكمن الفرق الأساسي بينهما هو البادئة التي تكشف متغير البيئة لجانب العميل. | تدعم [[Next.js/environment variables|متغيرات البيئة]] <code>env.</code> كما يفعل Create React App، ويكمن الفرق الأساسي بينهما هو البادئة التي تكشف متغير البيئة لجانب العميل. | ||
* حوّل بادئات متغيرات البيئة من <code>_REACT_APP</code> إلى <code>_NEXT_PUBLIC</code>. | * حوّل بادئات متغيرات البيئة من <code>_REACT_APP</code> إلى <code>_NEXT_PUBLIC</code>. | ||
* تتاح متغيرات البيئة للاستخدام أثناء بناء التطبيق وعند طلب وجهات API | * تتاح متغيرات البيئة للاستخدام أثناء بناء التطبيق وعند طلب وجهات API. | ||
=== تحسين نتائج البحث في محركات البحث === | === تحسين نتائج البحث في محركات البحث === | ||
تستخدم معظم أمثلة Create React App العنصر <code>react-helmet</code> للمساعدة في إضافة بيانات وصفية <code>meta</code> لأغراض تحسين نتيجة ظهور الموقع في محركات البحث SEO. تستخدم Next.js في المقابل المكوّن [[Next.js/next head|<code>next/head</code>]] لإضافة هذه البيانات إلى العنصر <code></ head></code>. إليك مثالًا عن مكوّن SEO | تستخدم معظم أمثلة Create React App العنصر <code>react-helmet</code> للمساعدة في إضافة بيانات وصفية <code>meta</code> لأغراض تحسين نتيجة ظهور الموقع في محركات البحث SEO. تستخدم Next.js في المقابل المكوّن [[Next.js/next head|<code>next/head</code>]] لإضافة هذه البيانات إلى العنصر <code></ head></code>. إليك مثالًا عن مكوّن SEO في تطبيق Create React App:<syntaxhighlight lang="javascript"> | ||
// src/components/seo.js | // src/components/seo.js | ||
سطر 520: | سطر 521: | ||
=== التطبيقات المدارة ذاتيًا === | === التطبيقات المدارة ذاتيًا === | ||
إن كنت تمتلك تطبيق Create React App مُدار ذاتيًا (أو مفصول | إن كنت تمتلك تطبيق Create React App مُدار ذاتيًا (أو مفصول ejected باستعمال الأمر <code>npm run eject</code> وتديره أنت ذاتيًا بكامل ضبطه وخياراته)، إليك بعض النقاط التي ينبغي أخذها بعين الاعتبار: | ||
* إن كان لديك ملف مخصص مهيأ ليضم محمِّلات CSS أو Sass أو غيرها من الموجودات فهذه المحملات مدمجة في Next.js. | * إن كان لديك ملف مخصص مهيأ ليضم محمِّلات CSS أو Sass أو غيرها من الموجودات فهذه المحملات مدمجة في Next.js. | ||
* إن أضفت بنفسك [[Next.js/supported browsers features|ميزات JavaScript جديدة]] (كالسَلسَلة الاختيارية) أو شيفرات | * إن أضفت بنفسك [[Next.js/supported browsers features|ميزات JavaScript جديدة]] (كالسَلسَلة الاختيارية) أو [[Next.js/supported browsers features|شيفرات مواءمة]] Polyfills، فتحقق مما هو مدمج بالفعل في Next.js. | ||
* إن كان لديك إعدادات مخصصة لفصل الشيفرات Next.js، يمكنك إزالتها لأن Next.js تمتلك آلية فصل شيفرات تلقائية مبنية على أساس الصفحات. | * إن كان لديك إعدادات مخصصة لفصل الشيفرات Next.js، يمكنك إزالتها لأن Next.js تمتلك آلية فصل شيفرات تلقائية مبنية على أساس الصفحات. | ||
* يمكنك [[Next.js/customizing postcss config|تخصيص إعدادات PostCSS]] في Next.js دون الحاجة إلى فصل التطبيق عن منصة العمل. | * يمكنك [[Next.js/customizing postcss config|تخصيص إعدادات PostCSS]] في Next.js دون الحاجة إلى فصل التطبيق عن منصة العمل. | ||
سطر 556: | سطر 557: | ||
) | ) | ||
} | } | ||
</syntaxhighlight>تمتلك معظم تطبيقات React التي تستخدم React Router | </syntaxhighlight>تمتلك معظم تطبيقات React التي تستخدم React Router ملفًا عال المستوى يحتوي على قائمة بكل الوجهات. إليك مثالًا:<syntaxhighlight lang="javascript"> | ||
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom' | import { BrowserRouter as Router, Switch, Route } from 'react-router-dom' | ||
سطر 582: | سطر 583: | ||
* <code>pages/index.js</code> → <code>/</code> | * <code>pages/index.js</code> → <code>/</code> | ||
== الوجهات المتداخلة == | === الوجهات المتداخلة === | ||
تُصيّر الوجهات مثل <code>blog/my-post/</code> في الشيفرة التالية إلى مكوِّن <code>Post</code>. فإن لم تكن هناك كتلة ديناميكية <code>slug</code> تحدد هوية المنشور، سيصيّر قائمة المنشورات بأكملها:<syntaxhighlight lang="javascript"> | تُصيّر الوجهات مثل <code>blog/my-post/</code> في الشيفرة التالية إلى مكوِّن <code>Post</code>. فإن لم تكن هناك كتلة ديناميكية <code>slug</code> تحدد هوية المنشور، سيصيّر قائمة المنشورات بأكملها:<syntaxhighlight lang="javascript"> | ||
import { | import { | ||
سطر 614: | سطر 616: | ||
return <h1>Post Slug: {slug}</h1> | return <h1>Post Slug: {slug}</h1> | ||
} | } | ||
</syntaxhighlight>تستخدم Next.js الصيغة <code>[slug:]</code> ضمن اسم الملف للتوجه الديناميكي بدلًا من | </syntaxhighlight>تستخدم Next.js الصيغة <code>[slug:]</code> ضمن اسم الملف للتوجه الديناميكي بدلًا من استخدام <code>slug:</code> ضمن المكوّن <code>Route</code>. وبالإمكان الانتقال إلى Next.js بإنشاء ملفين جديدين الأول <code>pages/blog/[slug].js</code> (ليعرض كل الصفحات) والآخر <code>pages/blog/[slug].js</code> (لعرض منشورات مفردة):<syntaxhighlight lang="javascript"> | ||
// pages/blog/index.js | // pages/blog/index.js | ||
سطر 646: | سطر 648: | ||
راجع صفحة [[Next.js/dynamic import|الإدراج الديناميكي]] لمعلومات أوفى. | راجع صفحة [[Next.js/dynamic import|الإدراج الديناميكي]] لمعلومات أوفى. | ||
=== استعادة | === استعادة موضع التمرير === | ||
تقدم Next.js دعمًا مدمجًا لاستعادة | تقدم Next.js دعمًا مدمجًا لاستعادة موضع التمرير scroll restoration، وبالتالي يمكنك إزالة أية مكوّنات <code>ScrollToTop</code> خاصة قد عرّفتها. | ||
إن السلوك الافتراضي للمكونين <code>next/link</code> و <code>next/router</code> هو تمرير المحتوى حتى أعلى الصفحة، لكن بإمكانك أيضًا تعطيل هذا السلوك إن أردت. | إن السلوك الافتراضي للمكونين <code>next/link</code> و <code>next/router</code> هو تمرير المحتوى حتى أعلى الصفحة، لكن بإمكانك أيضًا تعطيل هذا السلوك إن أردت. | ||
== أمثلة == | |||
* [https://github.com/vercel/next.js/tree/canary/examples/rewrites\ Rewrites] | |||
* [https://github.com/vercel/next.js/tree/canary/examples/redirects Redirects] | |||
* [https://github.com/vercel/next.js/tree/canary/examples/with-zones Multi-Zones] | |||
== اقرأ أيضًا == | == اقرأ أيضًا == | ||
*[[Next.js/Routing|تعلم التوّجه في Next.js]] | |||
* [[Next.js/Routing|تعلم التوّجه في Next.js]] | *[[Next.js/Routing|الوجهات الديناميكية في Next.js]] | ||
* [[Next.js/Routing|الوجهات الديناميكية في Next.js]] | *[[Next.js/next link|التنقل عبر الواجهة الأمامية في Next.js]] | ||
* [[Next.js/next link|التنقل عبر الواجهة الأمامية في Next.js]] | |||
== المصادر == | == المصادر == | ||
* صفحات [https://nextjs.org/docs/migrating/ Migrating to Next.js] من توثيق Next.js الرسمي | * صفحات [https://nextjs.org/docs/migrating/ Migrating to Next.js] من توثيق Next.js الرسمي |
مراجعة 09:04، 31 ديسمبر 2022
صُمِّمت Next.js لكي يجري تبنيها تدريجيًا، إذ ستكون قادرًا على متابعة العمل على شيفرة جاهزة حالية وإضافة المقدار الذي تريده من شيفرة React. فإن بدأت بكمية صغيرة من الشيفرة ووسعتها تدريجيًا بإضافة صفحات جديدة، سيسهل ذلك عليك تبني Next.js في مشاريعك وتجنب إعادة كتابة كل شيء بالكامل.
استراتيجيات العمل
المسارات الفرعية Subpath
تقتضي الاستراتيجية الأولى بتهيئة الخادم أو الخادم الوكيل لوضع كل ما يتعلق بتطبيق Next.js في نفس المسار الفرعي (ضمن مجلد فرعي). فقد يكون موقعك الإلكتروني مثلًا example.com
ومن ثم تهيئ المسار الفرعي example.com/store
على الخادم ليضم تطبيق لمتجر إلكتروني.
بإمكانك تهيئة أصول assets وروابط تطبيق Next.js لتعمل تلقائيًا عند طلب الوجهة store/
، وذلك باستخدام basePath
. وبما أن كل صفحة من صفحات Next.js هي وجهة قائمة بنفسها، يمكنك الوصول إلى الصفحة pages/products.js
مثلًا عبر المسار example.com/store/products
.
// next.config.js
module.exports = {
basePath: '/store',
}
الدالة rewrites
تقتضي الاستراتيجية الثانية إنشاء تطبيق Next.js جديد يشير إلى عنوان URL الجذري للنطاق domain الذي تستخدمه. استخدم بعد ذلك الدالة rewrites
ضمن ملف التهيئة لكي تُحوَّل بعض المسارات إلى التطبيق الموجود.
لنفرض مثلًا أنك أنشأت تطبيق Next.js كي يُخدّم عبر النطاق example.com
وله ملف التهيئة next.config.js
. عندها ستتعامل Next.js مع الصفحات التي أضفتها إلى تطبيقك (مثل about/
إن أضفت pages/about.js
)، بينما ستحوّل أية طلبات أخرى (مثل dashboard/
) إلى proxy.example.com
.
ملاحظة: إن كنت تستعمل fallback: true/'blocking'
في getStaticPaths
، فلن يعمل الالتقاط الكامل catch-all ضمن rewrites
المُعرف في الملف next.config.js
إذ ستلتقطها getStaticPaths
.
// next.config.js
module.exports = {
async rewrites() {
return {
//(بما في ذلك المسارت الديناميكة) Next.js بعد التحقق من كل صفحات
// والملفات الساكنة سنحوّل أي طلبات أخرى
fallback: [
{
source: '/:path*',
destination: `https://proxy.example.com/:path*`,
},
],
}
//في الإصدارات مادون 10.1 rewrite يمكنك استخدام الدالة غير الفعالة
return [
// لابد من تعريف دالة غير فعالة لتحرض عملية التحقق
// من كل الصفحات الساكنة قبل أن نحاول تحويل المسار
{
source: '/:path*',
destination: '/:path*',
},
{
source: '/:path*',
destination: `https://proxy.example.com/:path*`,
},
]
},
}
ملاحظة: إن كنت تنتقل تدريجيا إلى الوجهات الديناميكية مثل [slug]
وكنت تستعمل fallback: true
أو fallback: 'blocking'
مع rewrite
، فتأكد من أن تشمل حالة عدم العثور على صفحة page not found، إذ عندما تلتقط Next.js الوجهات الديناميكية فإنها تتوقف عن التحقق من أي وجهات أخرى. استعمال notFound: true
في getStaticProps
سيعيد صفحة 404 دون تطبيق rewrite
، فإن لم تكن ترغب بذلك، يمكنك استعمال getServerSideProps
مع ترويسة التحكم بالتخزين المؤقت stale-while-revalidate
عند إعادة الخاصيات props وبعدها يمكنك إعادة التوجيه proxy يدويًا إلى الواجهة الخلفية الحالية باستعمال أدوات مثل http-proxy بدلًا من إعادة notFound: true
.
واجهات أمامية مُصغرة مع مستودعات مفردة ونطاقات فرعية
تجعل Next.js و Vercel عملية بناء الواجهات الأمامية المصغّرة أو المجزّأة micro-frontends ونشرها إلى مستودع مفرد Monorepo أمرًا مباشرًا وبسيطًا. يسمح لك ذلك باستخدام النطاقات الفرعية لتبنّي تطبيقات جديدة تدريجيًا. ومن مزايا استخدام الواجهة الأمامية المصغّرة:
- صغر حجمها وتماسكها وسهولة إدارة شيفرتها.
- يشترك في إنتاجها عدة منظمات قادرة على التوسع عبر فرق مستقلة ومنفصلة.
- القدرة على الترقية والتحديث وحتى إعادة كتابة أجزاء منها بأسلوب تدريجي.
حالما تنهي تهيئة مستودعك المفرد، ادفع بالتغييرات إلى مستودع Git كالعادة وسترى أن حمولتك قد نُشرت ضمن مشاريع Vercel المرتبطة بها.
الانتقال من Gatesby
يساعدك هذا الدليل في نقل تطبيقك Gatsby إلى تطبيق Next.js؛ إذ يسمح لك الانتقال إلى Next.js أن:
- تختار استراتيجية إحضار البيانات التي تريد لكل صفحة بشكل مستقل.
- تستخدم التجديد الساكن التلقائي لتحديث الصفحات الموجودة بتصييرها مسبقًا في الخلفية عند وصول البيانات.
- تستخدم وجهات API.
سنحاول الآن إنجاز عملية الإنتقال خطوة خطوة
تحديث الملف package.json
والاعتماديات
وهي الخطوة الأولى في عملية الانتقال وعليك تنفيذ ما يلي:
- إزالة كل الحزم المتعلقة ب Gatsby (ابق فقط
react
وreact-dom
) - ثبِّت
next
. - أضف الأوامر Next.js إلى
scripts
وأولهاnext dev
الذي يشغّل خادم التطوير على العنوانlocalhost:3000
. أما ثانيها فهوnext build
وnext start
لإنشاء وتشغيل نسخة الإنتاج.
إليك مثالًا عن package.json
:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "latest",
"react-dom": "latest"
}
}
الأصولو الساكنة والخرج المُصرَّف
تستخدم Gatsby المجلد public
لوضع ملفات الخرج المصرَّفة بينما تستخدم Next.js هذا المجلد لوضع الأصول الساكنة static assets. إليك خطوات الانتقال في هذه المرحلة:
- أزل الإشارة إلى المجلدين
/cache.
وpublic
من الملفgitignore.
واحذف المجلدين. - غيّر اسم المجلد
static
إلىpublic
. - أضف
next.
إلىgitignore.
.
إنشاء الوجهات Routes
تدعم كلا Gatsby و Next المجلد pages
الذي يستخدم أسلوب توجيه يعتمد على نظام الملفات. تستخدم المجلد src/pages
الذي تدعمه أيضًا Next.js. تُنشئ Gatsby الوجهات الديناميكية باستخدام الواجهة البرمجية createPages
ضمن الملف gatsby-node.js
. ويمكنك في Next استخدام الوجهات الديناميكية ضمن المجلد pages
للحصول على نفس التأثير. وبدلًا من وجود مجلد بالاسم template
، يمكنك استخدام مكوّنات React ضمن ملف الوجهة الديناميكية:
- في Gatsby: أنشئ مسارات ديناميكية لكل منشور مثلًا باستخدام الواجهة
createPages
ومن ثم أنشئ ملفًا يمثل قالبًا لهذه المنشورات ضمنsrc/templates/blog-post.js
. - في Next: أنشئ المسارات الديناميكية على الشكل
pages/blog/[slug].js
لتمثل قالبًا للمنشورات. يمكن الوصول إلى قيمةslug
من خلال معامل استعلام. إذ يمكن مثلًا الوصول إلى المنشورblog/first-post/
انطلاقًا من القالبpages/blog/[slug].js
من خلال كائن الاستعلام{ 'slug': 'first-post' }
.
تنسيق الصفحات
تُدرج Gatsby تنسيقات CSS العامة في الملف gatsby-browser.js
، لكن لا بد من إنشاء تطبيق app.js_
مخصص للتنسيقات العامة في Next.js. عند الانتقال إلى Next.js بإمكانك نسخ التنسيقات المُدرجة مباشرة وتحديث المسارات النسبية إن اقتضى الأمر. وتذكر أن Next.js تقدم دعمًا مدمجًا لتنسيق CSS.
الروابط
للمكوّن Link
في Gatsby ونظيره Link
في Next.js واجهتان برمجيتان تختلفان اختلافًا طفيفًا:
// Gatsby
import { Link } from 'gatsby'
export default function Home() {
return <Link to="/blog">blog</Link>
}
// Next.js
import Link from 'next/link'
export default function Home() {
return (
<Link href="/blog">
<a>blog</a>
</Link>
)
}
حدِّث أية عبارت إدراج مختلفة، ثم بدّل to
إلى href
وأضف العنصر <a>
ضمن العنصر <link>
.
إحضار البيانات
يظهر الاختلاف الجذري بين Gatsby و Next.js في طريقة إحضار البيانات. إذ يرتكز خيار Gatsby على "GraphQL" في إحضار البيانات إلى التطبيق، بينما عليك أن تختار في Next.js الاستراتيجية التي تريد ومن ضمنها "GraphQL".
تستخدم Gatsby الدالة graphql
لاستعلام البيانات في صفحات الموقع بما فيها البيانات المحلية والبعيدة ومعلومات التهيئة الخاصة بالموقع، كما تسمح بإنشاء صفحات ساكنة فقط. أما في Next.js، بإمكانك اختيار استراتيجية إحضار البيانات الخاصة بكل صفحة. إذ تسمح لك الدالة getServerSideProps
مثلًا بتنفيذ التصيير من جانب الخادم، بينما بإمكانك تصدير الدالتين getStaticProps
/ getStaticPaths
ضمن الصفحة لتوليد صفحات ساكنة بدلًا من تنفيذ pageQuery
. إليك مثالًا:
// src/pages/[slug].js
// remark-html و remark ثبِّت
import { remark } from 'remark'
import html from 'remark-html'
import { getPostBySlug, getAllPosts } from '../lib/blog'
export async function getStaticProps({ params }) {
const post = getPostBySlug(params.slug)
const markdown = await remark()
.use(html)
.process(post.content || '')
const content = markdown.toString()
return {
props: {
...post,
content,
},
}
}
export async function getStaticPaths() {
const posts = getAllPosts()
return {
paths: posts.map((post) => {
return {
params: {
slug: post.slug,
},
}
}),
fallback: false,
}
}
سترى عادة ملحقات plugins في Gatsby لقراءة منظومة الملفات gatsby-source-filesystem
أو التعامل مع تنسيق Markdown من خلال gatsby-transformer-remark
وغيرها. فالمثال النموذجي الأكثر شعبية لمبتدئي تطبيقات المنشورات، قد استخدم 15 حزمة Gatsby خاصة. تأخذ Next في المقابل نهجًا آخر، إذ تُضمِّن الميزات كثيرة الاستعمال مباشرة ضمن إطار العمل، وتمنح المستخدم تحكمًا كاملًا في دعم التطبيق بحزم خارجية. فبدلًا من فصل شيفرة القراءة من منظومة الملفات ضمن ملحق، بإمكانك استخدام حزمة Node.js الأصلية fs
ضمن الدالتين getStaticProps
/ getStaticPaths
لقراءة منظومة الملفات:
// src/lib/blog.js
//date-fns و gray-matter ثبِّت
import matter from 'gray-matter'
import { parseISO, format } from 'date-fns'
import fs from 'fs'
import { join } from 'path'
//`src/content/blog` إلى markdown أضف ملفات
const postsDirectory = join(process.cwd(), 'src', 'content', 'blog')
export function getPostBySlug(slug) {
const realSlug = slug.replace(/\.md$/, '')
const fullPath = join(postsDirectory, `${realSlug}.md`)
const fileContents = fs.readFileSync(fullPath, 'utf8')
const { data, content } = matter(fileContents)
const date = format(parseISO(data.date), 'MMMM dd, yyyy')
return { slug: realSlug, frontmatter: { ...data, date }, content }
}
export function getAllPosts() {
const slugs = fs.readdirSync(postsDirectory)
const posts = slugs.map((slug) => getPostBySlug(slug))
return posts
}
مكون الصور وتحسين الصور
تمتلك Next.js مكوِّن صور مدمج وطريقة تحسين مدمجة للصور. إذ يُعد المكوِّن next/image
امتدادًا لعنصر الصورة <img>
في HTML، وقد طوّر ليلائم مواقع الويب الحديثة.
يتيح لك التحسين التقائي للصور إعادة تحجيم الصورة وتحسينها وتقديمها بامتدادات حديثة مثل WebP عندما يدعمها المتصفح. يقلل ذلك من الدفع بصورة كبيرة إلى أجهزة لها نافذة عرض صغيرة، كما يسمح لـ Next.js بالتبني التلقائي لتنسيقات الصور المستقبلية، وتقديمها للمتصفح الذي يدعمها.
الإنتقال بالصور من Gatsby
تعمل Next.js على تحسين الصورة عند الطلب بدلًا من تحسينها أثناء بناء التطبيق. وعلى خلاف مولِّدات المواقع الساكنة والحلول الساكنة فقط، لن يزيد ذلك زمن بناء التطبيق سواءً حمّلت 10 صور أو 10 ملايين صورة. ويعني أنه بإمكانك إزالة ملحقات Gatsby الشائعة مثل:
gatsby-image
gatsby-transformer-sharp
gatsby-plugin-sharp
استخدم بدلًا من ذلك المكوّن next/image
والتحسين التلقائي للصورة.
لا يُدعم المُحمّل الافتراضي للمكون
next/image
عند استخدامnext export
، لكن ستعمل خيارات أخرى.
import Image from 'next/image'
import profilePic from '../public/me.png'
export default function Home() {
return (
<>
<h1>My Homepage</h1>
<Image
src={profilePic}
alt="Picture of the author"
//Gatsby في "fluid" الخيار "responsive" يُشابه
//Gatsby بأعظم عرض في"fluid" الخيار "intrinsic" يُشابه
//Gatsby في ""fixed" الخيار "fixed" يُشابه
layout="responsive"
//Gatsby في "blur-up" اختياري، ويشابه
placeholder="blur"
//Gatsby GraphQL في "width" اختياري، ويشابه
width={500}
//Gatsby GraphQL في "height" اختياري، ويشابه
height={500}
/>
<p>Welcome to my homepage!</p>
</>
)
}
تهيئة الموقع
ستجد البيانات الوصفية (الاسم والوصف وغيرها) للموقع المبني باستخدام Gatsby ضمن الملف gatsby-config.js
وتُستعرض بعد ذلك من قبل واجهة GraphQL البرمجية التي تتعامل معها من خلال pageQuery
أو من خلال استعلام ساكن ضمن المكوّن.
لكن يُفضَّل في Next.js إنشاء ملف تهيئة يُشابه في محتواه الشيفرة التالية؛ ومن ثم تستطيع إدراج هذه الملف في أي مكان دون الحاجة لاستخدام GraphQL للولوج إلى البيانات الوصفية للموقع:
// src/config.js
export default {
title: 'Starter Blog',
author: {
name: 'Lee Robinson',
summary: 'who loves Next.js.',
},
description: 'A starter blog converting Gatsby -> Next.',
social: {
twitter: 'leeerob',
},
}
تحسين نتائج البحث في محركات البحث
تستخدم معظم أمثلة Gatsby العنصر react-helmet
للمساعدة في إضافة بيانات وصفية meta
لأغراض تحسين نتيجة ظهور الموقع في محركات البحث SEO. تستخدم Next.js في المقابل المكوّن next/head
لإضافة هذه البيانات إلى العنصر </ head>
. إليك مثالًا عن مكوّن SEO في Gatsby:
// src/components/seo.js
import { Helmet } from 'react-helmet'
export default function SEO({ description, title, siteTitle }) {
return (
<Helmet
title={title}
titleTemplate={siteTitle ? `%s | ${siteTitle}` : null}
meta={[
{
name: `description`,
content: description,
},
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: description,
},
{
property: `og:type`,
content: `website`,
},
{
name: `twitter:card`,
content: `summary`,
},
{
name: `twitter:creator`,
content: twitter,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: description,
},
]}
/>
)
}
وهذا هو المثال ذاته باستخدام Next.js بما في ذلك القراءة من ملف إعدادات الموقع:
// src/components/seo.js
import Head from 'next/head'
import config from '../config'
export default function SEO({ description, title }) {
const siteTitle = config.title
return (
<Head>
<title>{`${title} | ${siteTitle}`}</title>
<meta name="description" content={description} />
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:site_name" content={siteTitle} />
<meta property="twitter:card" content="summary" />
<meta property="twitter:creator" content={config.social.twitter} />
<meta property="twitter:title" content={title} />
<meta property="twitter:description" content={description} />
</Head>
)
}
الانتقال من Create React App
يساعدك هذا الدليل في نقل تطبيقك من Create React App إلى تطبيق Next.js؛ إذ يسمح لك ذلك أن:
- تختار استراتيجية إحضار البيانات التي تريد لكل صفحة بشكل مستقل.
- تستخدم التجديد الساكن التلقائي لتحديث الصفحات الموجودة بتصييرها مسبقًا في الخلفية عند وصول البيانات.
- تستخدم وجهات API.
سنحاول الآن إنجاز عملية الإنتقال خطوة خطوة.
تحديث الملف package.json
والاعتماديات
وهي الخطوة الأولى في عملية الانتقال وعليك تنفيذ ما يلي:
- إزالة حزم
react
(ابق فقطreact
وreact-dom
). إن كنت تستخدم React Router يمكنك إزالةreact-router-dom
أيضًا. - ثبِّت
next
. - أضف أوامر Next.js إلى
scripts
وأولهاnext dev
الذي يشغّل خادم التطوير على العنوانlocalhost:3000
. أما ثانيها فهوnext build
وnext start
لإنشاء وتشغيل نسخة الإنتاج.
إليك مثالًا عن package.json
:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "latest",
"react-dom": "latest"
}
}
الأصول الساكنة والخرج المُصرَّف
تستخدم Create React App المجلد public
لوضع ملفات HTML التي تُمثِّل نقاط دخول إلى التطبيق والموجودات الساكنة بينما تستخدم Next.js هذا المجلد لوضع الأصول الساكنة static assests فقط. إليك خطوات الانتقال في هذه المرحلة:
- انقل أية صور أو خطوط أو أية الأصول أو موجودات ساكنة أخرى إلى المجلد
public
. - حوّل الملف
index.html
(نقطة الدخول إلى التطبيق) إلى Next.js، وينبغي نقل أية شيفرات<head>
ضمنه إلى مستند مخصصdocument.js_
، وكذلك أية تخطيطات layouts مشتركة بين الصفحات إلى تطبيق APP مخصص. - أضف
next.
إلىgitignore.
.
وسنناقش لاحقًا موضوع التنسيق.
إنشاء الوجهات والروابط
قد تستخدم المكتبة React Router في تطبيقات Create React App، لكن بدلًا من استخدام مكتبة من طرف آخر، تقدم طريقة Next.js آلية توجه مدمجة مبنية على نظام الملفات.
- أنشئ المجلد
pages
في جذر المشروع. - انقل الملف
src/App.js
ليصبحpages/index.js
. يمثل هذا الملف الصفحة الرئيسية لتطبيقك. ادمج هذا الملف مع الشيفرة التي تُستخدم لعرض وجهة الصفحة الرئيسية في تطبيق Create React App. - حوّل كل المكوّنات
Route
إلى ملفات جديدة في المجلدpages
. - أما الوجهات التي تتطلب مساراتها محتوى ديناميكي (مثل
blog/:slug/
)، بإمكانك استخدام الوجهات الديناميكية في Next.js (مثلpages/blog/[slug].js
). يمكن الوصول إلى قيمةslug
من خلال معامل استعلام. إذ يمكن مثلًا الوصول إلى المنشورblog/first-post/
انطلاقًا من القالبpages/blog/[slug].js
من خلال كائن الاستعلام{ 'slug': 'first-post' }
.
التنسيق
تقدم Next.js دعمًا مدمجًا لتنسيق CSS و SaSS و CSS-in-JS. كما يسمح Create React App بإدراج ملفات css.
مباشرة ضمن المكوّنات. تسمح Next.js بنفس هذا الأسلوب أيضًا، لكن لا بد أن تكون هذه الملفات وحدات تنسيق CSS. أما بالنسبة للتنسيقات العامة، ستحتاج إلى تطبيق App مخصص لإضافتها.
الولوج الآمن إلى واجهة الويب البرمجية
يمكن الوصول إلى الواجهة window
أو localStorage
أو navigator
وغيرها من واجهات ويب البرمجية مباشرة عبر التطبيقات التي تُصيَّر من جانب العميل. لكن طالما أن Next.js تستخدم التصيير المسبق، لا بد من الوصول إلى تلك الواجهات بطريقة آمنة عندما يكون المستخدم في الواجهة الأمامية. تسمح الشيفرة التالية مثلًا بالوصول إلى الواجهة window
من جهة العميل فقط (من الواجهة الأمامية):
if (typeof window !== 'undefined') {
//الآن window يمكنك الوصول إلى `
}
ومن الطرق المستحسنة للوصول الآمن إلى الواجهات هو استخدام الخطاف useEffect
والذي يُنفَّذ فقط في جانب العميل:
import { useEffect } from 'react'
useEffect(() => {
//الآن window يمكنك الوصول إلى `
}, [])
مكوّن الصور وتحسين الصور
تمتلك Next.js ابتداءً من الإصدار 10.0.0 مكوِّن صور مدمج وطريقة تحسين مدمجة للصور. إذ يُعد المكوَّن next/image
امتدادًا لعنصر الصورة <img>
في HTML، وقد طوّر ليلائم مواقع الويب الحديثة.
يتيح لك التحسين التقائي للصور إعادة تحجيم الصورة وتحسينها وتقديمها بامتدادات حديثة مثل WebP عندما يدعمها المتصفح. يقلل ذلك من الدفع بصورة كبيرة إلى أجهزة لها نافذة عرض صغيرة، كما يسمح للغة Next.js بالتبني التلقائي لتنسيقات الصور المستقبلية، وتقديمها للمتصفح الذي يدعمها.
تعمل Next.js على تحسين الصورة عند الطلب بدلًا من تحسينها أثناء بناء التطبيق. وعلى خلاف مولِّدات المواقع الساكنة والحلول الساكنة فقط، لن يزيد ذلك زمن بناء التطبيق سواءً حمّلت 10 صور أو 10 ملايين صورة.
import Image from 'next/image'
export default function Home() {
return (
<>
<h1>My Homepage</h1>
<Image
src="/me.png"
alt="Picture of the author"
width={500}
height={500}
/>
<p>Welcome to my homepage!</p>
</>
)
}
متغيرات البيئة
تدعم متغيرات البيئة env.
كما يفعل Create React App، ويكمن الفرق الأساسي بينهما هو البادئة التي تكشف متغير البيئة لجانب العميل.
- حوّل بادئات متغيرات البيئة من
_REACT_APP
إلى_NEXT_PUBLIC
. - تتاح متغيرات البيئة للاستخدام أثناء بناء التطبيق وعند طلب وجهات API.
تحسين نتائج البحث في محركات البحث
تستخدم معظم أمثلة Create React App العنصر react-helmet
للمساعدة في إضافة بيانات وصفية meta
لأغراض تحسين نتيجة ظهور الموقع في محركات البحث SEO. تستخدم Next.js في المقابل المكوّن next/head
لإضافة هذه البيانات إلى العنصر </ head>
. إليك مثالًا عن مكوّن SEO في تطبيق Create React App:
// src/components/seo.js
import { Helmet } from 'react-helmet'
export default function SEO({ description, title, siteTitle }) {
return (
<Helmet
title={title}
titleTemplate={siteTitle ? `%s | ${siteTitle}` : null}
meta={[
{
name: `description`,
content: description,
},
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: description,
},
{
property: `og:type`,
content: `website`,
},
{
name: `twitter:card`,
content: `summary`,
},
{
name: `twitter:creator`,
content: twitter,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: description,
},
]}
/>
)
}
وهذا هو المثال ذاته باستخدام Next.js:
// src/components/seo.js
import Head from 'next/head'
export default function SEO({ description, title, siteTitle }) {
return (
<Head>
<title>{`${title} | ${siteTitle}`}</title>
<meta name="description" content={description} />
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:site_name" content={siteTitle} />
<meta property="twitter:card" content="summary" />
<meta property="twitter:creator" content={config.social.twitter} />
<meta property="twitter:title" content={title} />
<meta property="twitter:description" content={description} />
</Head>
)
}
تطبيقات الصفحة الواحدة
إن أردت نقل تطبيق Create React App إلى Next.js والإبقاء على تطبيق الصفحة الواحدة، انقل جميع نقاط الدخول إلى التطبيق إلى مسار التقاط اختياري لأي وجهة يُدعى pages/[[...app]].js
.
// pages/[[...app]].js
import { useState, useEffect } from 'react'
import CreateReactAppEntryPoint from '../components/app'
function App() {
const [isMounted, setIsMounted] = useState(false)
useEffect(() => {
setIsMounted(true)
}, [])
if (!isMounted) {
return null
}
return <CreateReactAppEntryPoint />
}
export default App
التطبيقات المدارة ذاتيًا
إن كنت تمتلك تطبيق Create React App مُدار ذاتيًا (أو مفصول ejected باستعمال الأمر npm run eject
وتديره أنت ذاتيًا بكامل ضبطه وخياراته)، إليك بعض النقاط التي ينبغي أخذها بعين الاعتبار:
- إن كان لديك ملف مخصص مهيأ ليضم محمِّلات CSS أو Sass أو غيرها من الموجودات فهذه المحملات مدمجة في Next.js.
- إن أضفت بنفسك ميزات JavaScript جديدة (كالسَلسَلة الاختيارية) أو شيفرات مواءمة Polyfills، فتحقق مما هو مدمج بالفعل في Next.js.
- إن كان لديك إعدادات مخصصة لفصل الشيفرات Next.js، يمكنك إزالتها لأن Next.js تمتلك آلية فصل شيفرات تلقائية مبنية على أساس الصفحات.
- يمكنك تخصيص إعدادات PostCSS في Next.js دون الحاجة إلى فصل التطبيق عن منصة العمل.
- عليك العودة إلى الإعدادات الافتراضية لمفسّر Babel ومحزّم Webpack في Next.js لتقف على ما هو موجود افتراضيًا.
الانتقال من React Router
يساعدك هذا الدليل في فهم آلية الانتقال من استخدام المكتبة React Router في تحديد الوجهات إلى الاعتماد على منظومة الملفات. تستطيع أن تستخدم في Next.js المكونين next/link
و next/router
لكي :
- تقلل حجم تجميعة الشيفرة بإزالة الاعتمادية React Router.
- تحديد الوجهات في تطبيقك من خلال منظومة الملفات.
- الاستفادة من آخر التحسينات في إطار عمل Next.js.
الأساسيات
ألغ تثبيت React Router أولًا إذ سننتقل إلى استخدام طريقة التوجيه المدمجة مع Next.js:
npm uninstall react-router-dom
يختلف المكوّن Link
الذي ينفّذ عمليات التنقل في جانب العميل قليلًا عن React Router:
// قبل (React Router)
import { Link } from 'react-router-dom'
export default function App() {
return <Link to="/about">About</Link>
}
// يعد (Next.js)
import Link from 'next/link'
export default function App() {
return (
<Link href="/about">
<a>About</a>
</Link>
)
}
تمتلك معظم تطبيقات React التي تستخدم React Router ملفًا عال المستوى يحتوي على قائمة بكل الوجهات. إليك مثالًا:
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
export default function App() {
return (
<Router>
<Switch>
<Route path="/about">
<h1>About</h1>
</Route>
<Route path="/blog">
<h1>Blog</h1>
</Route>
<Route path="/">
<h1>Home</h1>
</Route>
</Switch>
</Router>
)
}
يمكنك التعبير عن نفس هيكيلية التطبيق في Next.js باستخدام منظومة الملفات. فعندما يُضاف ملف إلى المجلد pages
سيكون متاحًا كوجهة:
pages/about.js
→/about
pages/blog.js
→/blog
pages/index.js
→/
الوجهات المتداخلة
تُصيّر الوجهات مثل blog/my-post/
في الشيفرة التالية إلى مكوِّن Post
. فإن لم تكن هناك كتلة ديناميكية slug
تحدد هوية المنشور، سيصيّر قائمة المنشورات بأكملها:
import {
BrowserRouter as Router,
Switch,
Route,
useRouteMatch,
useParams,
} from 'react-router-dom'
export default function Blog() {
// Nested route under /blog
const match = useRouteMatch()
return (
<Router>
<Switch>
<Route path={`${match.path}/:slug`}>
<Post />
</Route>
<Route path={match.path}>
<h1>All Blog Posts</h1>
</Route>
</Switch>
</Router>
)
}
function Post() {
const { slug } = useParams()
return <h1>Post Slug: {slug}</h1>
}
تستخدم Next.js الصيغة [slug:]
ضمن اسم الملف للتوجه الديناميكي بدلًا من استخدام slug:
ضمن المكوّن Route
. وبالإمكان الانتقال إلى Next.js بإنشاء ملفين جديدين الأول pages/blog/[slug].js
(ليعرض كل الصفحات) والآخر pages/blog/[slug].js
(لعرض منشورات مفردة):
// pages/blog/index.js
export default function Blog() {
return <h1>All Blog Posts</h1>
}
// pages/blog/[slug].js
import { useRouter } from 'next/router'
export default function Post() {
const router = useRouter()
const { slug } = router.query
return <h1>Post Slug: {slug}</h1>
}
التصيير من جانب الخادم
تقدم Next.js دعمًا مدمجًا للتصيير من جانب الخادم. أي بالإمكان إزالة أي نسخ عن StaticRouter
في الشيفرة.
فصل الشيفرة
تقدم Next.js دعمًا مدمجًا لفصل الشيفرات، أي بالإمكان إزالة أية نسخ عن:
loadable/server@
وloadable/babel-plugin@
وloadable/webpack-plugin@
- أية تعديلات على الملف
babelrc.
لأجلloadable/babel-plugin@
ستُفصل شيفرة كل ملف موجود في المجلد pages
إلى تجميعة JavaScript خاصة خلال عملية البناء. كما تدعم Next.js الإدراج الديناميكي ()import
وفق مواصفات JavaScript إصدار ES2020. وهكذا يمكنك إدراج وحدات JavaScript ديناميكيًا والعمل عليها. كما تعمل أيضًا مع التصيير من جانب الخادم.
راجع صفحة الإدراج الديناميكي لمعلومات أوفى.
استعادة موضع التمرير
تقدم Next.js دعمًا مدمجًا لاستعادة موضع التمرير scroll restoration، وبالتالي يمكنك إزالة أية مكوّنات ScrollToTop
خاصة قد عرّفتها.
إن السلوك الافتراضي للمكونين next/link
و next/router
هو تمرير المحتوى حتى أعلى الصفحة، لكن بإمكانك أيضًا تعطيل هذا السلوك إن أردت.
أمثلة
اقرأ أيضًا
المصادر
- صفحات Migrating to Next.js من توثيق Next.js الرسمي