Next.js/migrating
الانتقال إلى Next.js
صُمِّمت Next.js لكي يجري تبنيها تدريجيًا، إذ ستكون قادرًا على متابعة العمل على شيفرة جاهزة وإضافة المقدار الذي تريده من شيفرة React. فإن بدأت بكمية صغيرة من الشيفرة ووسعتها تدريجيًا بإضافة صفحات جديدة، سيمنع ذلك خروج الميزات عن الطريق الذي رسم لها فيما لو أعدت كتابة كل شيء بالكامل.
استراتيجيات العمل
المسارات الفرعية
تقتضي الاستراتيجية الأولى بتهيئة الخادم أو الخادم الوكيل لوضع كل ما يتعلق بتطبيق Next.js في نفس المسار الفرعي (ضمن مجلد فرعي). فقد يكون موقعك الإلكتروني مثلًا example.com
ومن ثم تهيئ المسار الفرعي example.com/store
على الخادم ليضم تطبيق لمتجر إلكتروني.
بإمكانك تهيئة موجودات وروابط تطبيق Next.js لتعمل تلقائيًا عند طلب الوجهة store/
،وذلك باستخدام basePath
. وبما أن كل صفحة من صفحات Next.js هي وجهة قائمة بنفسها، يمكنك الوصول إلى الصفحة pages/products.js
مثلًا عبر المسار example.com/store/products
.
// next.config.js
module.exports = {
basePath: '/store',
}
تتوفر هذه الميزة ابتداءً من الإصدار 9.5. فإن كنت تستخدم إصدارًا أقدم، يستحسن ترقية إصدارك ثم التجريب.
الدالة rewrites
تقتضي الاستراتيجية الثانية إنشاء تطبيق Next.js جديد يشير إلى عنوان URL الجذري للنطاق domain الذي تستخدمه. استخدم بعد ذلك الدالة rewrites
ضمن ملف التهيئة لكي تُحوَّل بعض المسارات إلى التطبيق الموجود.
لنفرض مثلًا أنك أنشأت تطبيق Next.js كي يُخدّم عبر النطاق example.com
وله ملف التهيئة next.config.js
. عندها ستتعامل Next.js مع الصفحات التي أضفتها إلى تطبيقك (مثل about/
إن أضفت pages/about.js
)، بينما ستحوّل أية طلبات أخرى (مثل dashboard/
) إلى proxy.example.com
.
// 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*`,
},
]
},
}
تتوفر هذه الميزة ابتداءً من الإصدار 9.5. فإن كنت تستخدم إصدارًا أقدم، يستحسن ترقية إصدارك ثم التجريب.
واجهات أمامية مُصغّرة مع مستودعات مفردة ونطاقات فرعية
تجعل و بناء الواجهات الأمامية المصغّرة أو المجزّأة micro-frontends ونشرها إلى مستودع مفرد Monorepo أمرًا مباشرًا وبسيطًا. يسمح لك ذلك باستخدام النطاقات الفرعية لتبنّي تطبيقات جديدة تدريجيًا. ومن مزايا استخدام الواجهة الأمامية المصغّرة:
- صغر حجمها وتماسكها وسهولة إدارة شيفرتها.
- يشترك في إنتاجها عدة منظمات قادرة على التوسع عبر فرق مستقلة ومنفصلة.
- القدرة على الترقية و التحديث وحتى إعادة كتابة أجزاء منها بأسلوب تدريجي.
حالما تنهي تهيئة مستودعك المفرد، ادفع بالتغييرات إلى مستودع Git كالعادة وسترى أن حمولتك قد نُشرت ضمن مشاريع Vercel المرتبطة بها.
الانتقال من Gatesby
يساعدك هذا الدليل في نقل تطبيقك Gatsby إلى تطبيق Next.js؛ إذ يسمح لك الانتقال إلى أن:
- تختار استراتيجية إحضار البيانات التي تريد لكل صفحة بشكل مستقل.
- تستخدم التجديد الساكن التلقائي لتحديث الصفحات الموجودة بتصييرها مسبقًا في الخلفية عند وصول البيانات.
- تستخدم وجهات API.
سنحاول الآن إنجاز عملية الإنتقال خطوة خطوة
تحديث الملف package.json
والاعتماديات
وهي الخطوة الأولى في عملية الانتقال وعليك تنفيذ ما يلي:
- إزالة كل الحزم المتعلقة بلغة (ابق فقط
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 هذا المجلد لوضع الموجودات الساكنة. إليك خطوات الانتقال في هذه المرحلة:
- أزل الإشارة إلى المجلدين
/cache.
وpublic
من الملفgitignore.
واحذف المجلدين. - غيّر اسم المجلد
static
إلىpublic
. - أضف
next.
إلىgitignore.
.
إنشاء الوجهات
تدعم كلا اللغتين 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-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 هذا المجلد لوضع الموجودات الساكنة فقط. إليك خطوات الانتقال في هذه المرحلة:
- انقل أية صور أو خطوط أو أية موجودات ساكنة أخرى إلى المجلد
- حوّل الملف (نقطة الدخول إلى التطبيق) إلى ، وينبغي نقل أية شيفرات ضمن العنصر إلى مستند مخصص
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 مُدار ذاتيًا (أو مفصول عن إطار العمل ejeected)، إليك بعض النقاط التي ينبغي أخذها بعين الاعتبار:
- إن كان لديك ملف مخصص مهيأ ليضم محمِّلات CSS أو Sass أو غيرها من الموجودات فهذه المحملات مدمجة في Next.js.
- إن أضفت بنفسك ميزات JavaScript جديدة (كالسَلسَلة الاختيارية) أو شيفرات مواءمة، فتحقق مما هو مدمج بالفعل في 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:]
ضمن اسم الملف للتوجه الديناميكي بدلًا من استخدامها ضمن المكوّن 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
هو تمرير المحتوى حتى أعلى الصفحة، لكن بإمكانك أيضًا تعطيل هذا السلوك إن أردت.
اقرأ أيضًا
- ألق نظرة على هذا المثال المخصص على Github لتتعرف على تفاصيل أكثر عن نقل تطبيق Gatsby إلى Next.js.
- تعلم التوّجه في Next.js.
- الوجهات الديناميكية في Next.js.
- التنقل عبر الواجهة الأمامية في Next.js.
المصادر
- صفحات Migrating to Next.js من توثيق Next.js الرسمي