تقسيم الرمز باستخدام عمليات الاستيراد الديناميكية في Next.js

كيفية تسريع تطبيق Next.js باستخدام ميزة "تقسيم الرموز البرمجية" واستراتيجيات التحميل الذكية

ما الذي ستتعلمه؟

توضّح هذه المشاركة الأنواع المختلفة من تقسيم الرمز البرمجي وكيفية استخدام عمليات الاستيراد الديناميكية لتسريع تطبيقات Next.js.

تقسيم الرموز البرمجية استنادًا إلى المسار والمكوّنات

يقسّم Next.js تلقائيًا JavaScript إلى أجزاء منفصلة لكل مسار. عندما يحمّل المستخدمون تطبيقك، لا ترسل Next.js سوى الرمز المطلوب للمسار الأولي. عندما ينتقل المستخدمون في التطبيق، يجلبون الأجزاء المرتبطة بالمسارات الأخرى. يعمل تقسيم الرموز البرمجية المستند إلى المسار على تقليل مقدار النص البرمجي الذي يجب تحليله وتجميعه في آنٍ واحد، ما يؤدي إلى تقليل أوقات تحميل الصفحة.

على الرغم من أنّ تقسيم الرموز البرمجية المستنِد إلى المسار هو خيار تلقائي جيد، يمكنك تحسين عملية التحميل بشكلٍ أكبر من خلال تقسيم الرموز البرمجية على مستوى المكوّن. إذا كانت لديك مكونات كبيرة في تطبيقك، ننصحك بتقسيمها إلى أجزاء منفصلة. بهذه الطريقة، يمكن تحميل أي مكوّنات كبيرة ليست ضرورية أو لا يتم عرضها إلا عند تفاعلات معيّنة للمستخدم (مثل النقر على زر) بشكل بطيء.

تتوافق Next.js مع import() الديناميكي، ما يتيح لك استيراد وحدات JavaScript (بما في ذلك مكونات React) بشكل ديناميكي وتحميل كل عملية استيراد كجزء منفصل. يمنحك ذلك تقسيم الرموز على مستوى المكوّنات ويتيح لك التحكّم في تحميل الموارد كي يتم تنزيل الرمز الذي يحتاجه المستخدمون فقط للجزء الذي يشاهدونه من الموقع الإلكتروني. في Next.js، يتم عرض هذه المكوّنات من جهة الخادم (SSR) تلقائيًا.

عمليات الاستيراد الديناميكية في العمل

تتضمّن هذه المشاركة عدة إصدارات من نموذج تطبيق يتألف من صفحة بسيطة تحتوي على زر واحد. عند النقر على الزر، يظهر لك جرو لطيف. أثناء التنقل في كل إصدار من التطبيق، ستلاحظ اختلاف عمليات الاستيراد الديناميكية عن عمليات الاستيراد static وكيفية التعامل معها.

في الإصدار الأول من التطبيق، يعيش الجرو في components/Puppy.js. لعرض الجرو على الصفحة، يستورد التطبيق المكوّن Puppy في index.js باستخدام عبارة استيراد ثابتة:

import Puppy from "../components/Puppy";

لمعرفة كيفية تجميع Next.js للتطبيق، عليك فحص تتبُّع الشبكة في DevTools:

  1. لمعاينة الموقع الإلكتروني، اضغط على عرض التطبيق. ثم اضغط على ملء الشاشة ملء الشاشة.

  2. اضغط على Ctrl ‏+ Shift ‏+ J (أو Command ‏+ Option ‏+ J على نظام التشغيل Mac) لفتح DevTools.

  3. انقر على علامة التبويب الشبكة.

  4. ضَع علامة في مربّع الاختيار إيقاف ذاكرة التخزين المؤقت.

  5. إعادة تحميل الصفحة

عند تحميل الصفحة، يتم تجميع كل الرموز البرمجية اللازمة، بما في ذلك Puppy.js المكوّن، في index.js:

علامة التبويب "الشبكة" في "أدوات المطوّر" تعرِض ستة ملفات JavaScript: index.js وapp.js وwebpack.js وmain.js و0.js وملف dll (مكتبة الروابط الديناميكية).

عند الضغط على الزر Click me (انقر عليّ)، تتم إضافة طلب صورة الجرو بتنسيق JPEG فقط إلى علامة التبويب الشبكة:

علامة التبويب "الشبكة" في DevTools بعد النقر على الزرّ، تعرِض الملفات الستة نفسها من JavaScript وصورة واحدة.

الجانب السلبي لهذا النهج هو أنّه حتى إذا لم ينقر المستخدمون على الزر ل الاطّلاع على الجرو، عليهم تحميل المكوّن Puppy لأنّه مضمّن في index.js. في هذا المثال الصغير، لا يشكّل ذلك مشكلة كبيرة، ولكن في التطبيقات المُستخدَمة في الحياة اليومية، غالبًا ما يكون تحميل المكوّنات الكبيرة عند الضرورة فقط تحسُّنًا كبيرًا.

اطّلِع الآن على إصدار ثانٍ من التطبيق تم فيه استبدال الاستيراد الثابت باستيراد ديناميكي. يتضمّن Next.js next/dynamic، ما يجعله ممكنًا استخدام عمليات الاستيراد الديناميكية لأي مكوّنات في Next:

import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";

// ...

const Puppy = dynamic(import("../components/Puppy"));

اتّبِع الخطوات الواردة في المثال الأول لفحص عملية تتبُّع الشبكة.

عند تحميل التطبيق لأول مرة، يتم تنزيل index.js فقط. هذه المرة، أصبح حجمه أصغر بمقدار 0.5 كيلوبايت (انخفض من 37.9 كيلوبايت إلى 37.4 كيلوبايت) لأنّه لا يتضمّن رمز المكوّن Puppy:

أدوات المطوّر: الشبكة تعرض ملفات JavaScript الستة نفسها، باستثناء index.js التي أصبح حجمها الآن أصغر بمقدار 0.5 كيلوبايت.

أصبح المكوّن Puppy الآن في قطعة منفصلة، 1.js، لا يتم تحميلها إلا عند الضغط على الزر:

علامة التبويب "الشبكة" في "أدوات المطوّر" بعد النقر على الزر، تعرِض الملف الإضافي 1.js والصورة المُضافة إلى أسفل قائمة الملفات.

في التطبيقات الواقعية، تكون المكوّنات غالبًا أكبر كثيرًا، ويمكن أن يؤدي تحميلها بشكلٍ بطيء إلى تقليل حجم الحمولة الأولية لملف JavaScript بمئات الكيلوبايت.

عمليات الاستيراد الديناميكية باستخدام مؤشر تحميل مخصّص

عند تحميل الموارد بشكلٍ بطيء، من الممارسات الجيدة توفير مؤشر تحميل في حال حدوث أي تأخيرات. في Next.js، يمكنك إجراء ذلك من خلال تقديم وسيطة إضافية للدالة dynamic():

const Puppy = dynamic(() => import("../components/Puppy"), {
  loading: () => <p>Loading...</p>
});

للاطّلاع على مؤشر التحميل أثناء العمل، يمكنك محاكاة الاتصال البطيء بالشبكة في DevTools:

  1. لمعاينة الموقع الإلكتروني، اضغط على عرض التطبيق. ثم اضغط على ملء الشاشة ملء الشاشة.

  2. اضغط على Ctrl ‏+ Shift ‏+ J (أو Command ‏+ Option ‏+ J على نظام التشغيل Mac) لفتح DevTools.

  3. انقر على علامة التبويب الشبكة.

  4. ضَع علامة في مربّع الاختيار إيقاف ذاكرة التخزين المؤقت.

  5. في القائمة المنسدلة تقييد السرعة، اختَر شبكة الجيل الثالث السريعة.

  6. اضغط على الزر انقر عليّ.

الآن، عند النقر على الزر، يستغرق تحميل المكوّن بعض الوقت ويعرض التطبيق الرسالة "جارٍ التحميل" في هذه الأثناء.

شاشة داكنة مع النص

عمليات الاستيراد الديناميكية بدون إعادة التحميل من جهة العميل

إذا كنت بحاجة إلى عرض مكوّن من جهة العميل فقط (مثل ملف شخصي للدردشة)، يمكنك إجراء ذلك من خلال ضبط الخيار ssr على false:

const Puppy = dynamic(() => import("../components/Puppy"), {
  ssr: false,
});

الخاتمة

من خلال إتاحة عمليات الاستيراد الديناميكية، يوفّر لك Next.js ميزة تقسيم الرموز على مستوى المكوّنات، ما يمكن أن يؤدي إلى تقليل أحمال JavaScript وتحسين وقت تحميل التطبيق. يتم عرض جميع المكوّنات من جهة الخادم تلقائيًا ويمكنك إيقاف هذا الخيار متى لزم الأمر.