في هذا الدرس التطبيقي حول الترميز، يمكنك تحسين أداء التطبيق التالي من خلال إزالة أي تبعيات غير مستخدَمة وغير ضرورية.
القياس
من الأفضل دائمًا قياس مستوى أداء الموقع الإلكتروني أولاً قبل إضافة التحسينات.
- لمعاينة الموقع الإلكتروني، اضغط على عرض التطبيق. ثم اضغط على ملء الشاشة .
انقر على القطة الصغيرة المفضّلة لديك. يتم استخدام قاعدة بيانات Realtime من Firebase في هذا التطبيق، ولهذا السبب يتم تعديل النتيجة في الوقت الفعلي ويتم مزامنة النتيجة مع كل مستخدم آخر يستخدم التطبيق. 🐈
- اضغط على Ctrl + Shift + J (أو Command + Option + J على نظام التشغيل Mac) لفتح DevTools.
- انقر على علامة التبويب الشبكة.
- ضَع علامة في مربّع الاختيار إيقاف ذاكرة التخزين المؤقت.
- أعِد تحميل التطبيق.
يتم تحميل رمز JavaScript بحجم 1 ميغابايت تقريبًا لتحميل هذا التطبيق البسيط.
اطّلِع على تحذيرات المشروع في أدوات المطوّرين.
- انقر على علامة التبويب وحدة التحكّم.
- تأكَّد من تفعيل
Warnings
في القائمة المنسدلة للمستويات بجانب إدخالFilter
.
- اطّلِع على التحذير المعروض.
تُقدّم Firebase، وهي إحدى المكتبات المستخدَمة في هذا التطبيق، تحذيرًا يُعلم المطوّرين بعدم استيراد الحزمة بالكامل، بل فقط المكوّنات المستخدَمة. بعبارة أخرى، هناك مكتبات غير مستخدَمة يمكن إزالتها من هذا التطبيق لتحميله بشكل أسرع.
هناك أيضًا حالات يتم فيها استخدام مكتبة معيّنة، ولكن قد يكون هناك بديل أبسط. سيتم لاحقًا في هذا الدليل التمهيدي مناقشة مفهوم إزالة المكتبات غير الضرورية.
تحليل الحزمة
هناك تبعيتان رئيسيتان في التطبيق:
- Firebase: منصة تقدّم عددًا من خدمات المفيدة لتطبيقات iOS أو Android أو الويب. في هذه الحالة، يتم استخدام قاعدة بياناته في الوقت الفعلي لتخزين معلومات كل قطة ومزامنتها في الوقت الفعلي.
- Moment.js: مكتبة أدوات تسهّل التعامل مع
التواريخ في JavaScript. يتم تخزين تاريخ ميلاد كل قطة في قاعدة بيانات
Firebase، ويتم استخدام
moment
لاحتساب عمرها بالأسابيع.
كيف يمكن أن تساهم تبعيتان فقط في حجم حِزمة يبلغ 1 ميغابايت تقريبًا؟ حسنًا، أحد الأسباب هو أنّ أيّ تبعية يمكن أن تتضمّن بدورها تبعيات خاصة بها، لذا هناك عدد أكبر بكثير من تبعيتين فقط إذا تمّ أخذ كلّ عمق/فرع من "شجرة" تبعية في الاعتبار. من السهل أن يصبح التطبيق كبيرًا بشكلٍ نسبي سريعًا إذا تم تضمين العديد من التبعيات.
حلِّل أداة تجميع الحِزم للحصول على فكرة أفضل عن المشكلة. هناك عدد من الأدوات المختلفة التي أنشأها المنتدى والتي يمكن أن تساعد في إجراء ذلك، مثل أداة
webpack-bundle-analyzer
.
تم تضمين حزمة هذه الأداة في التطبيق كـ devDependency
.
"devDependencies": {
//...
"webpack-bundle-analyzer": "^2.13.1"
},
وهذا يعني أنّه يمكن استخدامه مباشرةً في ملف إعدادات webpack.
استورِده في بداية webpack.config.js
:
const path = require("path");
//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
.BundleAnalyzerPlugin;
أضِفه الآن كمكوّن إضافي في نهاية الملف ضمن صفيف plugins
:
module.exports = {
//...
plugins: [
//...
new BundleAnalyzerPlugin()
]
};
عند إعادة تحميل التطبيق، من المفترض أن يظهر لك عرض مرئي للمجموعة الكاملة بدلاً من التطبيق نفسه.
قد لا يكون هذا الحلّ لطيفًا مثل رؤية بعض القطط 🐱، ولكنه مفيد للغاية. عند تمرير مؤشر الماوس فوق أي من الحِزم، يظهر حجمها بثلاث طُرق مختلفة:
حجم الإحصاءات | الحجم قبل أي تصغير أو ضغط |
---|---|
الحجم الذي تم تحليله | حجم الحزمة الفعلية داخل الحزمة بعد تجميعها يعمل الإصدار 4 من webpack (الذي يتم استخدامه في هذا التطبيق) على تصغير الملفات المجمّعة تلقائيًا، ولهذا السبب يكون حجمه أصغر من حجم الإحصاءات. |
الحجم بعد ضغطه | حجم الحزمة بعد ضغطها باستخدام ترميز gzip يتم تناول هذا الموضوع في دليل منفصل. |
باستخدام أداة webpack-bundle-analyzer، من الأسهل تحديد الحِزم غير المستخدَمة أو غير المطلوبة التي تشكّل نسبة كبيرة من الحزمة.
إزالة الحِزم غير المستخدَمة
يوضّح التصور البصري أنّ حزمة firebase
تتألّف من الكثير من
العناصر، وليس مجرد قاعدة بيانات. ويشمل ذلك حِزمًا إضافية، مثل:
firestore
auth
storage
messaging
functions
هذه خدمات رائعة يوفّرها Firebase (يمكنك الرجوع إلى المستندات للحصول على مزيد من المعلومات)، ولكن لا يتم استخدام أي منها في التطبيق، لذلك ليس هناك سبب لاستيرادها كلها.
يمكنك التراجع عن التغييرات في webpack.config.js
للاطّلاع على التطبيق مرة أخرى:
- أزِل
BundleAnalyzerPlugin
من قائمة الإضافات:
plugins: [
//...
new BundleAnalyzerPlugin()
];
- والآن، أزِل عملية الاستيراد غير المستخدَمة من أعلى الملف:
const path = require("path");
//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
من المفترض أن يتم تحميل التطبيق بشكل طبيعي الآن. عدِّل src/index.js
لتعديل عمليات استيراد
Firebase.
import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';
الآن عند إعادة تحميل التطبيق، لا يظهر تحذير "أدوات مطوّري البرامج". يؤدي فتح لوحة الشبكة في DevTools أيضًا إلى خفض كبير في حجم الحِزمة:
تمّت إزالة أكثر من نصف حجم الحزمة. توفّر Firebase العديد من خدمات
مختلفة وتمنح المطوّرين خيار تضمين الخدمات التي يحتاجون إليها فقط. في هذا التطبيق، تم استخدام firebase/database
فقط لتخزين
كل البيانات ومزامنتها. إنّ استيراد firebase/app
، الذي يُعدّ واجهة برمجة التطبيقات لكلٍّ من الخدمات المختلفة، مطلوب دائمًا.
تتيح أيضًا العديد من المكتبات الشائعة الأخرى، مثل lodash
، للمطوّرين
استيراد أجزاء مختلفة من حِزمهم بشكل انتقائي. بدون الحاجة إلى بذل الكثير من الجهد، يمكن أن يؤدي تعديل عمليات استيراد المكتبات في أحد التطبيقات لتضمين ما يتم استخدامه فقط إلى تحسينات كبيرة في الأداء.
على الرغم من أنّ حجم الحِزمة قد انخفض بشكل كبير، لا يزال هناك مزيد من العمل الذي يجب تنفيذه. 😈
إزالة الحِزم غير المطلوبة
على عكس Firebase، لا يمكن استيراد أجزاء من مكتبة moment
بسهولة، ولكن هل يمكن إزالتها بالكامل؟
يتم تخزين تاريخ ميلاد كل قطة لطيفة بتنسيق Unix (بالأجزاء من الثانية) في قاعدة بيانات Firebase.
هذا هو الطابع الزمني لتاريخ ووقت محدّدَين يتم تمثيلهما بعدد المللي ثانية التي انقضت منذ 1 كانون الثاني (يناير) 1970، 00:00 بالتوقيت العالمي المنسق. إذا كان بالإمكان احتساب التاريخ والوقت الحاليَين بالتنسيق نفسه، يمكن إنشاء وظيفة صغيرة لمعرفة عمر كل قطة بالأسابيع.
كالعادة، ننصحك بعدم النسخ واللصق أثناء اتّباع هذه الخطوات. ابدأ بمحاولة
إزالة moment
من عمليات الاستيراد في src/index.js
.
import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';
هناك مستمع أحداث Firebase يعالج تغييرات القيمة في قاعدة بياناتنا:
favoritesRef.on("value", (snapshot) => { ... })
فوق ذلك، أضِف دالة صغيرة لاحتساب عدد الأسابيع من تاريخ معيّن:
const ageInWeeks = birthDate => {
const WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
const diff = Math.abs((new Date).getTime() - birthDate);
return Math.floor(diff / WEEK_IN_MILLISECONDS);
}
في هذه الدالة، يتم احتساب الفرق بالمللي ثانية بين التاريخ والوقت الحاليين(new Date).getTime()
وتاريخ الميلاد (المَعلمةbirthDate
، التي تم تحويلها
بالمللي ثانية) وتقسيمه على عدد المللي ثوانٍ في
أسبوع واحد.
أخيرًا، يمكن إزالة جميع نُسخ moment
في مستمع الأحداث من خلال
الاستفادة من هذه الدالة بدلاً من ذلك:
favoritesRef.on("value", (snapshot) => { const { kitties, favorites, names, birthDates } = snapshot.val(); favoritesScores = favorites; kittiesList.innerHTML = kitties.map((kittiePic, index) => {const birthday = moment(birthDates[index]);return ` <li> <img src=${kittiePic} onclick="favKittie(${index})"> <div class="extra"> <div class="details"> <p class="name">${names[index]}</p><p class="age">${moment().diff(birthday, 'weeks')} weeks old</p><p class="age">${ageInWeeks(birthDates[index])} weeks old</p> </div> <p class="score">${favorites[index]} ❤</p> </div> </li> `}) });
أعِد الآن تحميل التطبيق واطّلِع على لوحة الشبكة مرة أخرى.
تم تقليل حجم الحزمة بمقدار النصف مرة أخرى.
الخاتمة
من خلال هذا الدليل التعليمي حول الرموز البرمجية، من المفترض أن يكون لديك فهم جيد لكيفية تحليل ملف برمجي معيّن وسبب أهمية إزالة الحِزم غير المستخدَمة أو غير المطلوبة. قبل بدء تحسين تطبيق باستخدام هذه التقنية، من المهم معرفة أنّ هذا الإجراء قد يكون أكثر تعقيدًا في التطبيقات الأكبر حجمًا.
في ما يتعلّق بإزالة المكتبات غير المستخدَمة، حاوِل معرفة الأجزاء التي يتم استخدامها من الحِزمة والأجزاء التي لا يتم استخدامها. إذا صادفت حزمة تبدو غامضة ويبدو أنّها لا يتم استخدامها في أي مكان، يمكنك الرجوع إلى الوراء والتحقّق مما إذا كانت هناك أي تبعيات من المستوى الأعلى قد تحتاج إليها. حاوِل العثور على طريقة مناسبة لفصلهما عن بعضهما.
عندما يتعلق الأمر بإزالة المكتبات غير المطلوبة، قد تكون الأمور أكثر صعوبةً. من المهم العمل عن كثب مع فريقك والتحقّق مما إذا كان هناك
احتمال لتبسيط أجزاء من قاعدة البيانات. قد يبدو أنّ إزالة moment
في
هذا التطبيق هو الإجراء المناسب في كل مرة، ولكن ماذا عن
المناطق الزمنية واختلافات اللغة التي يجب التعامل معها؟ أو
ماذا لو كانت هناك عمليات أكثر تعقيدًا لتعديل التواريخ؟ يمكن أن تصبح الأمور
معقدة جدًا عند التلاعب بالتواريخ أو الأوقات وتحليلها، وتبسِّط مكتبات مثل moment
وdate-fns
هذه العملية بشكل كبير.
كل شيء له مفاضلة، ومن المهم تقييم ما إذا كان الأمر يستحق التعقيد والجهد المبذولَين لطرح حل مخصّص بدلاً من الاعتماد على مكتبة تابعة لجهة خارجية.