دليل ترقية إصدارات Next.js
إليك قائمة بالتغييرات التي تحدث عند ترقية إصدارات Next.js والمتطلبات اللازمة لكل منها.
ترقية Next.js من النسخة 11 إلى 12
النسخة الأدنى من Node.js
رُفع متطلب الحد الأدنى لنسخة Node.js من 12.0.0 إلى 12.22.0، وهي أولى نسخ Node.js التي تدعم وحدات ES الأساسية.
ترقية React إلى أحدث نسخة
إن أدنى نسخة مدعومة من React هي 17.0.2
. نفِّذ الأمر التالي لترقية الإصدار الذي لديك:
npm install react@latest react-dom@latest
أو باستخدام yarn
:
yarn add react@latest react-dom@latest
ترقية Next.js إلى الإصدار 12
نفِّذ الأمر التالي:
npm install next@12
أو:
yarn add next@12
استبدال المفسّر Babel بالمصرِّف SWR
تستخدم Next.js حاليًا المصرِّف SWC المكتوب بلغة Rust لتصريف شيفرة JavaScript وTypeScript. وهذا المصرِّف أسرع بسبع عشرة مرة من Babel عند تصريف الملفات المفردة وأسرع بخمس مرات عندما يتعلق الأمر بميزة التحديث السريع.
تدعم Next.js بشكل كامل التوافقية الرجعية للتطبيقات التي تستخدم تهيئة خاصة بمفسِّر Babel، ونُقلت جميع التحويلات التي تتعامل معها افتراضيًا مثل "styled-jsx" و"tree-shaking" الخاصة بالدوال getStaticProps
/ getStaticPaths
/ getServerSideProps
إلى Rust.
تتوقف Next.js عن استخدام SWC عندما يكون للتطبيق تهيئة Babel مخصصة، ويتراجع ليستخدم Babel عند تصريف شيفرة JavaScript/Typescript بنفس الطريقة التي استُخدمت في النسخة 11 من Next.js.
ستُنقل العديد من آليات التكامل مع المكتبات الخارجية التي تتطلب حاليًا تحويلات مخصصة إلى تحويلات في المستقبل القريب، ومن بين هذه التحويلات:
- Styled Components
- Emotion
- Relay
استبدال المجمّع Terser بالمصرِّف SWR
يزيد استخدام SWC بدلًا من Terser من سرعة تصغير شيفرة JavaScript، وذلك بتفعيل الراية swcMinify
في الملف next.config.js
:
module.exports = {
swcMinify: true,
}
لا بد حاليًا من التأكيد على استخدام SWC لتصغير الشيفرة لاختباره في تطبيقات Next.js الحقيقية قبل أن يُعتمد كمصرّف افتراضي في النسخة 12.1.
التحسينات على تفسير تنسيقات styled-jsx
أنجزنا مفسّر CSS جديد مبني على المفسّر الذي استُخدم في تحويل Babel الخاص يتنسيقات styled-jsx. طوّرت آلية التعامل مع تنسيقات CSS في المفسّر الجديد، وستظهر أخطاء CSS الآن أثناء التطوير وعند تنفيذ الأمر next build
بدلًا من تجاهلها وظهور مشاكل غير متوقعة. لكن هذه التغييرات ستُطبق فقط عند استخدام styled-jsx.
تغير عنصر تغليف next/image
تصير next/image
الآن العنصر <img>
داخل عنصر <span>
وليس <div>
. فإن استخدم تطبيقك قاعدة CSS محددة تستهدف العنصر <span>
مثل container span.
، سيؤدي تحديث التطبيق إلى مطابقة عناصر التغليف ضمن المكوّن <Image>
، لهذا لا بد من تحاشي ذلك بتقييد محدد التنسيق إلى قاعدة محددة مثل container span.item.
، وتحديث المكوّن بإضافة الخاصية className
ليصبح بالشكل </ "span className="item">
.
إن كان لتطبيقك قاعدة تنسيق محددة تستهدف العنصر <div>
الخاص بالمكوّن next/image
مثل container span.
، فقد لا تجده القاعدة بعد الآن. بإمكانك في هذه الحالة تحديث المحدد ليصبح container span.
، أو يُفضّل إضافة العنصر <"div className="wrapper>
ليغلّف المكوّن <Image>
ومن ثم استهدف هذا الغلاف بقاعدة مثل container .wrapper.
.
لن تتغير الخاصية className
وستبقى قادرًا على تمريرها إلى العنصر الداخلي <img>
. لمزيد من المعلومات راجع صفحة تحسين الصور في توثيق Next.js.
استخدام WebSocket في تأسيس اتصالات HMR في Next.js
استخدمت سابقًا تقنية دفع التحديثات من الخادم إلى العميل عبر اتصال HTTP أو ما يُعرف بالأحداث المرسلة من قبل الخادم SSE، وذلك لاستقبال تحديثات HMR (الاستبدال السريع للوحدات Hot Modules Replacement). تُستخدم الآن اتصالات مقبس ويب WebSocket.
في بعض الحالات التي تُستخدم فيها خوادم وسيطة لإرسال الطلبات إلى خادم تطوير Next.js، لا بد من التأكد من صحة تخديم الطلب عند ترقيته. إذ قد تحتاج أن تضيف مثلًا الإعدادات التالية عند استخدام الخادم الوسيط nginx:
location /_next/webpack-hmr {
proxy_pass http://localhost:3000/_next/webpack-hmr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
أما في خوادم أخرى مثل express
، فقد تحتاج إلى استخدام الدالة app.all
للتاكد من صحة تمرير الطلب. إليك مثالًا:
app.all('/_next/webpack-hmr', (req, res) => {
nextjsRequestHandler(req, res)
})
إلغاء دعم الإصدار الرابع من Webpack
إن كنت تستخدم الإصدار الخامس من webpack فتجاوز هذه الفقرة.
تستخدم Next.js النسخة 11 برنامج التحزيم webpack 5 افتراضيًا أثناء تصريف التطبيقات. وتوقف دعم النسخة 4.
إن كنت لا تزال تستخدم webpack 4 في تطبيقاتك بوضع راية التحييد في ملف الإعدادات، سترى الآن رسالة خطأ تشير إلى موضوع رفع الدعم عن هذه النسخة.
إلغاء الخيار target
إن لم تستخدم الخيار target
في ملف الإعدادات next.config.js
يمكنك تجاوز هذه الفقرة.
ألغي الخيار لمصلحة الدعم المدمج لتعقب الاعتماديات اللازمة لتشغيل الصفحة. فخلال عملية البناء next build
، تتعقب Next.js تلقائيًا كل صفحة واعتمادياتها لتحديد كل الملفات التي يحتاجها التطبيق لنشر نسخة إنتاج منه.
راجع صفحة تعقب ملفات الخرج من توثيق Next.js لمعلومات أكثر، إن كنت تستخدم الخيار target
مضبوطًا على القيمة serverless
.
الترقية من النسخة 10 إلى 11
ترقية React إلى أحدث نسخة
إنّ أدنى نسخة مدعومة من React هي 17.0.2
. نفِّذ الأمر التالي لترقية الإصدار الذي لديك:
npm install react@latest react-dom@latest
أو باستخدام yarn
:
yarn add react@latest react-dom@latest
ترقية Next.js إلى الإصدار 11
نفِّذ الأمر التالي:
npm install next@11
أو:
yarn add next@11
برنامج Webpack 5
يُعد Webpack 5 المحزّم الافتراضي لنسخ Next.js الآن. إن لم تستخدم تهيئة خاصة لهذا المحزّم في تطبيقك ستستخدم Next.js المحزّم Webpack 5. أما إن كنت تستخدم إعدادات خاصة، راجع توثيق استخدام مع Next.js.
مسح distDir
سيكون الخيار الافتراضي الآن
ستُمسح محتويات المجلد الذي يضم خرج عملية البناء افتراضيًا (وهو next.
افتراضيًا) ما عدا ذاكرة Next.js المؤقتة. فإن كان يتعلق تطبيقك بهذه الناحية، تستطيع تعطيل هذه الميزة الافتراضية الجديدة بإضافة الراية cleanDistDir: false
ضمن الملف next.config.js
.
دعم استخدام PORT
عند تنفيذ الأمرين next dev
و next start
تدعم استخدام متغير البيئة لضبط المنفذ الذي سيعمل عليه التطبيق. ينصح باستخدام p-
و port--
حتى الآن، لكن حين تُمنع من استخدام p-
يمكنك الآن استخدام PORT
. إليك مثالًا:
PORT=4000 next start
تخصيص إعدادات next.config.js
لإدراج الصور
تدعم النسخة الإدراج الساكن للصور من خلال المكوّن next/image
. وتعتمد على معالجة الصورة المُدرجة. إن أضفت سابقًا الحزمتين next-images
أو next-optimized-images
، فبإمكانك الانتقال إلى الدعم المدمج الجديد باستخدام next/image
أو إلغاء الميزة:
module.exports = {
images: {
disableStaticImages: true,
},
}
إزالة التابع ()super.componentDidCatch
من pages/_app.js
ألغي التابع العائد ()super.componentDidCatch
منذ الإصدار 9 ولم يعد هنالك أي حاجة لاستخدامه، وقد أزيل في النسخة 11. إن احتوت الصفحة pages/_app.js
تابع مخصص componentDidCatch
، يمكنك إزالة super.componentDidCatch
لأنك لن تحتاجه بعد الآن.
إزالة Container
من الصفحة pages/_app.js
ألغي هذا التصدير منذ الإصدار 9 ولم يعد هنالك حاجة إلى استخدامه، وقد أزيل في النسخة 11. إن أدرجت الصفحة pages/_app.js
العنصر Container
من المكوّن next/app
يمكن إزالته.
إزالة استخدام الخاصية props.url
من مكوّنات الصفحة.
ألغي استخدام هذه الخاصية في الإصدار 4، ومنذ ذلك الوقت بدأت تظهر تنبيهات إلى هذا الموضوع أثناء تطوير التطبيق. لكن مع ظهور الدالتين getStaticProps
و getServerSideProps
لم يعد يُسمح باستخدام props.url
. وقد ألغي تمامًا في الإصدار 11.
إزالة الخاصية unsized
من المكوّن next/image
ألغيت الخاصية unsized
في المكوّن next/image
ابتداءً من النسخة 10.0.1، ويمكنك استخدام layout="fill"
بدلًا منها. أزيلت هذه الخاصية تمامًا في النسخة 11.
إزالة الخاصية modules
من المكوّن next/dynamic
ألغيت الخاصيتان modules
و render
العائدتان للمكوّن next/dynamic
ابتداءً من النسخة 9.5، وتعرض Next.js تنبيهًا أنهما ملغيّتان. والسبب في ذلك جعل المكوّن next/dynamic
قريبًا من React.lazy
في الواجهة البرمجية API. أُزيلت الخاصيتان تمامًا في النسخة 11.
لم يُشر إلى هذا الخيار في توثيق Next.js منذ النسخة 8 لهذا من غير المحتمل أن تراه مستخدمًا في أي تطبيق.
إزالة Head.rewind
لم يعد للتابع Head.rewind
استخدام منذ النسخة 9.5 وأزيل في النسخة 11. بإمكانك إزالة هذا التابع بأمان إن كنت قد استخدمته.
استثناء الإعدادات المحلية Moment.js افتراضيًا
يتضمن الملف "Moment.js" ترجمة للكثير من الإعدادات المحلية افتراضيًا. وتستثني Next.js الآن افتراضيًا هذه الملفات لتحسين حجم تجميعة التطبيقات التي تستخدمها. ولهذا عليك أن تستخدم الشيفرة التالية لتضمين أي إعداد محلي:
import moment from 'moment'
import 'moment/locale/ja'
moment.locale('ja')
تستطيع تعطيل هذا الخيار الافتراضي بإضافة excludeDefaultMomentLocales: false
إلى ملف التهيئة next.config.js
. لكن عليك الانتباه بأن تعطيله غير محبّذ إطلاقًا لأنه يؤثر على إجراءات التحسين التي تساهم كثيرًا في تقليل حجم الملف "Moment.js".
تحديث استخدام router.events
إن كنت تصل إلى router.events
خلال التصيير فلن تتمكن من ذلك بعد الآن في Next.js 11 خلال التصيير المسبق. تأكد من استخدام useEffect
للوصول إلى router.events
:
useEffect(() => {
const handleRouteChange = (url, { shallow }) => {
console.log(
`App is changing to ${url} ${
shallow ? 'with' : 'without'
} shallow routing`
)
}
router.events.on('routeChangeStart', handleRouteChange)
// إن لم يكن المكوّن مثبتًا، فألغ الوصول إلى
// `off` الحدث باستخدام التابع
return () => {
router.events.off('routeChangeStart', handleRouteChange)
}
}, [router])
إن كنت تستخدم router.router.events
في تطبيقك وهي خاصية داخلية لم تكن عامة، تأكد من استخدام router.events
أيضًا.
استخدام React 16 وReact 17
أضافت React 17 تحويلات JSX Transform جديدة أتاحت إمكانية استخدام الإدراج import React from 'react'
في Next.js عند استخدام بيئة React. تستخدم Next.js التحويل الجديد تلقائيًا مع النسخة 17 من React، والذي لا يجعل المتغير React
متغيرًا عامًا لأن ذلك أدى إلى آثار جانبية غير مقصودة سابقًا. بالإمكان الآن استخدام تحويلات Codemode لإصلاح الحالات التي تستخدم فيها React
دون إدراج.
الترقية من الإصدار 9 إلى 10 في Next.js
لا توجد تغييرات كبيرة بين الإصدارين 9 و 10، وكل ما عليك للترقية هو تنفيذ الأمر التالي:
npm install next@10
أو:
yarn add next@10
الترقية من الإصدار 8 إلى 9 في Next.js
تمهيد
نشر نسخة الإنتاج على Vercel
إن كنت قد هيأت routes
في ملف vercel.json
لتكون ديناميكية، بالإمكان إزالة هذه القواعد عند الانتقال إلى الإصدار 9 لوجود ميزة التوجيه الديناميكي. لا تتطلب الوجهات الديناميكية في الإصدار 9 أية تهيئة مخصصة عند النشر على Vercel بل تُهيأ تلقائيًا.
التحقق من التطبيقات المخصصة pages/_app.js
إن اطلعت سابقًا على المثال الذي أوردناه في صفحة التطبيقات المخصصة باستخدام App
"، سترى أنه من الممكن إزالة الدالة getInitialProps
.
من المهم جدًا إزالة getInitialProps
من التطبيقات المخصصة pages/_app.js
عندما يكون ذلك ممكنًا لاستخدام ميزات Next.js الجديدة. فليس للدالة getInitialProps
مثلًا عمل في هذه الشيفرة وبالإمكان إزالتها:
class MyApp extends App {
// أزل هذه الشيفرة،فليس لهاوظيفة
static async getInitialProps({ Component, ctx }) {
let pageProps = {}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx)
}
return { pageProps }
}
render() {
// الخ
}
}
تغييرات مفصلية
لا ضرورة لاستخدام التوجيه zeit/next-typescript@
تتجاهل في هذا الإصدار التوجيه zeit/next-typescript@
وتنبهك إلى ضرورة إزالته.
- أزل الإضافة
zeit/next-typescript@
من الملفnext.config.js
. - أزل الإشارات المرجعية إلى
zeit/next-typescript@
في الملفbabelrc.
إن وجد. - أزل الملحق
fork-ts-checker-webpack-plugin
من الملفnext.config.js
. - تُنشر تعريفات TypeScript ضمن حزمة
next
، لهذا عليك إزالةtypes/next@
لمنع حدوث تعارض. - تختلف الأنواع التالية من:
import { NextContext } from 'next'
import { NextAppContext, DefaultAppIProps } from 'next/app'
import { NextDocumentContext, DefaultDocumentIProps } from 'next/document'
إلى:
import { NextPageContext } from 'next'
import { AppContext, AppInitialProps } from 'next/app'
import { DocumentContext, DocumentInitialProps } from 'next/document'
ملاحظة: أعدَّ هذه القائمة مجتمع Next لمساعدتك على الترقية، فإن وجدت اختلافات أخرى يمكن إرسال طلب سحب pull-request على هذه القائمة (في GitHub) لمساعدة بقية المستخدمين.
تصدير المفتاح config
لم يعد بالإمكان تصدير متغير اسمه config
من الصفحة كالتالي:
export { config }
// أو
export const config ...
يُستخدم هذا المتغيّر المُصدّر الآن لتخصيص إعداد Next.js على مستوى الصفحة مثل حالة استخدام AMP أو موجهات API.
عليك إعادة تسمية أي متغير config
عند تصديره إن كان لا يتعلق بإعدادات Next.js
لا يصيّر next/dynamic
أي شيء افتراضيًا أثناء التحميل
على الرغم من ذلك، يمكنك تخصيص هذا السلوك بضبط قيمة الخاصية loading
:
import dynamic from 'next/dynamic'
const DynamicComponentWithCustomLoading = dynamic(
() => import('../components/hello2'),
{
loading: () => <p>Loading</p>,
}
)
إزالة withAmp
لصالح كائن تهيئة مُصدّر
تعتمد Next.js في هذا الإصدار مفهوم التهيئة على مستوى الصفحات، لهذا أزيل مكوّن المستوى الأعلى withAmp
. يمكن تهجير migrate هذا الإعداد تلقائيًا بتنفيذ الشيفرة التالية في جذر مشروعك:
curl -L https://github.com/vercel/next-codemod/archive/master.tar.gz | tar -xz --strip=2 next-codemod-master/transforms/withamp-to-config.js npx jscodeshift -t ./withamp-to-config.js pages/**/*.js
لتنفيذ هذا التهجير يدويًا أو متابعة ما يولّده تحويل codemode، ألق نظرة على التالي: قبل:
import { withAmp } from 'next/amp'
function Home() {
return <h1>My AMP Page</h1>
}
export default withAmp(Home)
// or
export default withAmp(Home, { hybrid: true })
بعد:
export default function Home() {
return <h1>My AMP Page</h1>
}
export const config = {
amp: true,
// or
amp: 'hybrid',
}
لن تصدر next export
الصفحات إلى index.html
صُدِّر الملف pages/about.js
سابقًا إلى out/about/index.html
. لكنه يُصدَّر الآن إلى out/about.html
.
يمكنك العودة إلى السلوك السابق بإضافة الإعداد التالي إلى next.config.js
:
// next.config.js
module.exports = {
trailingSlash: true,
}
معاملة مختلف لمكونات المجلد /pages/api
تُعد جميع الملفات في هذا المجلد وجهات API، ولن يتضمن تجميعات خاصة بواجهة العميل.
الميزات الملغاة في Next.js
إلغاء تحميل عدة وحدات برمجية معًا من خلال next/dynamic
وذلك كي يشابه المكوّن next/dynamic
الكائنات (React.lazy
و Suspense
) في React.
لن تصادفك أية عقبات تقريبًا في تحديث الشيفرة المتعلقة بهذا الموضوع، وقد أوردنا مثالًا لمساعدتك على تهجير التطبيق.
قبل:
import dynamic from 'next/dynamic'
const HelloBundle = dynamic({
modules: () => {
const components = {
Hello1: () => import('../components/hello1').then((m) => m.default),
Hello2: () => import('../components/hello2').then((m) => m.default),
}
return components
},
render: (props, { Hello1, Hello2 }) => (
<div>
<h1>{props.title}</h1>
<Hello1 />
<Hello2 />
</div>
),
})
function DynamicBundle() {
return <HelloBundle title="Dynamic Bundle" />
}
export default DynamicBundle
بعد:
import dynamic from 'next/dynamic'
const Hello1 = dynamic(() => import('../components/hello1'))
const Hello2 = dynamic(() => import('../components/hello2'))
function HelloBundle({ title }) {
return (
<div>
<h1>{title}</h1>
<Hello1 />
<Hello2 />
</div>
)
}
function DynamicBundle() {
return <HelloBundle title="Dynamic Bundle" />
}
export default DynamicBundle
المصادر
- الصفحة Upgrade Guide من توثيق Next.js الرسمي.