دليل ترقية إصدارات Next.js

من موسوعة حسوب

إليك قائمة بالتغييرات التي تحدث عند ترقية إصدارات Next.js والمتطلبات اللازمة لكل منها.

ترقية Next.js من النسخة 12 إلى 13

إن أردت ترقية إصدار Next.js إلى النسخة 13، فنفذ أحد الأوامر التالي وفقًا لمدير الحزم الذي تستخدمه:

npm i next@latest react@latest react-dom@latest eslint-config-next@latest
# أو
yarn add next@latest react@latest react-dom@latest eslint-config-next@latest
# أو
pnpm up next react react-dom eslint-config-next --latest

تغييرات الإصدار 13 باختصار

  • تغيرت قائمة المتصفحات المدعومة وأزيل منها المتصفح إنترنت إكسبلورر Internet Explorer لتركز القائمة على استهداف المتصفحات الحديثة.
  • تغيرت إصدار Node.js الأدنى المطلوب من 12.22.0 إلى 14.0.0 إذ وصل الإصدار 12 إلى نهايته وتوقف دعمه.
  • تغير إصدار مكتبة React الأدنى المطلوب من 17.0.2 إلى 18.2.0.
  • تغيرت قيمة الضبط swcMinify من false إلى true، وارجع إلى توثيق مصرِّف Next.js لمزيد من التفاصيل.
  • أعيد تسمية الإدراج next/image إلى next/legacy/image وأعيد تسمية الإدراج next/future/image إلى next/image وتساعدك تحويلات Codemods على تبديل التسميات بدقة وأمان.
  • لا حاجة إلى إضافة عنصر <a> ابن للعنصر next/link، لذا أضف الخاصية legacyBehavior إن كنت تريد إبقاء العنصر <a> والحفاظ على السلوك القديم أو أزل العنصر، وتساعدك تحويلات Codemods على الانتقال إلى السلوك الجديد.
  • أزيلت خاصية الضبط target وحل محلها تتبع ملفات الخرج.

الانتقال إلى ميزات الإصدار

قدم الإصدار 13 هيكلية جديدة للمجلد app مع ميزات جديدة وعُرف تنظيمي جديد ولكن لا يتطلب الانتقال إلى الإصدار 13 اتباع هذه الهيكلية، ولا تعتمد الهيكلية الجديدة على استعمال المجلد pages ولكن بإمكانك استعماله مع الميزات الجديدة التي قدمها الإصدار مثل مكون الصورة Image ومكون الرابط Link ومكون السكربت Script والخط المُحسن وسنشرحها تباعًا.

مكون الصورة <Image /‎>

قدم الإصدار 12 الكثير من التحسينات لمكون الصورة الذي يستورد عبر الإدراج next/future/image المؤفت آنذاك منها شيفرة جافاسكربت أصغر من طرف العميل وطريقة أسهل لعرض وتنسيق الصورة وعناية أكبر بسهولة الوصول accessibility ودعم التحميل المُرجأ lazy loading الذي يوفره المتصفح نفسه، وبدءًا من 13 أصبحت كل تلك الميزات هي الميزات الافتراضية لمكون الصورة next/image.

هنالك تحويلين من تحويلات codemods يساعدانك على الانتقال إلى مكون الصورة الجديد هما:

  • التحويل next-image-to-legacy-image: سيبدِّل هذا التحويل بدقة وأمان الإدراج next/image إلى الإدراج next/legacy/image أينما وجد للحفاظ على السلوك القديم للصور من الإصدار 12 وننصح بتطبيق هذا التحويل بأقرب وقت والانتقال إلى مكون الصورة الجديد.
  • التحويل next-image-experimental (تجريبي): بعد تنفيذ التحويل السابق، يمكنك اختياريًا تنفيذ هذا التحويل التجريبي لترقية مكون الصورة القديم المدرج عبر next/legacy/image إلى مكون الصورة الجديد next/image والذي سيحذف الخاصيات التي لم تعد مستخدمة ويضيف مكانها تنسيقات سطرية، وانتبه إلى أن هذا التحويل قيد التجريب ولا يشمل عن أنواع الصور ويقتصر حاليًا على الصور الثابتة مثل <Image src={img} layout="responsive" /‎> ولا يشمل صور مثل <Image {...props} /‎>.

بدلًا من تطبيق تحويلات آلية، يمكنك تطبيق التحويلات يدويًا باتباع دليل التحويل وارجع أيضًا إلى توثيق عنصر الصورة القديم.

مكون الرابط <Link>

لا يطلب مكون الرابط <Link> من Next.js إضافة عنصر المربط <a> يدويًا كعنصر ابن له بعد الآن وقد أضيف هذا السلوك تجريبيًا في بدءًا من الإصدار 12.2 وقد أصبح السلوك الافتراضي بدءًا من الإصدار 13 وأصبح فيه يضاف العنصر <a> آليًا ويُسمح لك بتحويل خاصيات props إليه.

انظر مثلًا:

import Link from 'next/link'

// Next.js 12: `<a>` has to be nested otherwise it's excluded
<Link href="/about">
  <a>About</a>
</Link>

// Next.js 13: `<Link>` always renders `<a>` under the hood
<Link href="/about">
  About
</Link>

لترقية روابط لتعمتد على السلوك الجديد، يمكنك تنفيذ التحويل new-link.

مكون السكربت <Script>

جرى ترقية سلوك مكون السكربت next/script وأصبح يدعم كلا مجلد الصفحات pages ومجلد التطبيق app.

تحسين الخطوط

كانت Next.js تساعد في تحسين الخطوط عبر خاصيات CSS أما بدءًا من الإصدار 13 فقد قدمت الوحدة next/font التي تتيح لك إمكانية تخصيص عملية تحميل الخط مع الحفاظ على الأداء ودعم السلوك القديم في المتصفحات.

ارجع إلى صفحة تحسين الخطوط لمزيد من التفاصيل حول استخدام next/font.

ترقية Next.js إلى 12.2

إن كنت تستعمل البرمجيات الوسيطة Middleware قبل الإصدار 12.2، فارجع إلى دليل الترقية لمزيد من التفاصيل.

ترقية 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.

ستُنقل العديد من آليات التكامل مع المكتبات الخارجية التي تتطلب حاليًا تحويلات Babel مخصصة إلى تحويلات SWC قائمة على لغة رست في المستقبل القريب، ومن بين هذه التحويلات:

  • 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 div. فقد لا تجده القاعدة بعد الآن. بإمكانك في هذه الحالة تحديث المحدد ليصبح container span. أو يُفضّل إضافة العنصر <"div className="wrapper> ليغلّف المكوّن <Image> ومن ثم استهدف هذا الغلاف بقاعدة مثل container .wrapper..

لن تتغير الخاصية className وستبقى قادرًا على تمريرها إلى العنصر الداخلي <img>. لمزيد من المعلومات راجع صفحة تحسين الصور في توثيق Next.js.

استخدام WebSocket في تأسيس اتصالات HMR في Next.js

استخدمت سابقًا تقنية دفع التحديثات server-sent events من الخادم إلى العميل عبر اتصال 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. يمكن الانتقال إلى هذا الإعداد تلقائيًا بتنفيذ الشيفرة التالية في جذر مشروعك:

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

المصادر