في هذا الدرس التطبيقي حول الترميز، يمكنك تحسين أداء التطبيق التالي عن طريق إزالة أي اعتماديات غير مستخدَمة وغير ضرورية.
قياس
ننصحك بقياس مستوى أداء موقع الويب أولاً قبل إضافة أي عمليات تحسين.
- لمعاينة الموقع الإلكتروني، اضغط على عرض التطبيق، ثم اضغط على ملء الشاشة .
انقر على قطتك المفضَّلة. تُستخدم قاعدة بيانات Firebase في الوقت الفعلي في هذا التطبيق، ولهذا السبب يتم تحديث النتيجة في الوقت الفعلي وتتم مزامنتها مع كل شخص آخر يستخدم التطبيق. 🐈
- اضغط على "Control+Shift+J" (أو "Command+Option+J" على نظام التشغيل Mac) لفتح "أدوات مطوّري البرامج".
- انقر على علامة التبويب الشبكة.
- ضع علامة في مربّع الاختيار إيقاف ذاكرة التخزين المؤقت.
- أعِد تحميل التطبيق.
يتم شحن ما يقرب من 1 ميغابايت من JavaScript لتحميل هذا التطبيق البسيط.
ألقِ نظرة على تحذيرات المشروع في "أدوات مطوري البرامج".
- انقر على علامة التبويب وحدة التحكّم.
- احرص على تفعيل
Warnings
في القائمة المنسدلة للمستويات بجانب إدخالFilter
.
- اطّلِع على التحذير المعروض.
نظام Firebase، الذي يعدّ من المكتبات المستخدمة في هذا التطبيق، نظامًا ساميًا جيدًا من خلال تقديم تحذير للسماح للمطورين بعدم استيراد الحزمة بالكامل، ولكن فقط المكونات المستخدمة. بعبارة أخرى، هناك مكتبات غير مستخدمة يمكن إزالتها في هذا التطبيق لتسريع عملية التحميل.
هناك أيضًا حالات يتم فيها استخدام مكتبة معيّنة، ولكن قد يكون هناك بديل أبسط منها. تعرَّف لاحقًا على مفهوم إزالة المكتبات غير الضرورية في هذا البرنامج التعليمي.
جارٍ تحليل الحزمة
هناك تبعيتان رئيسيتان في التطبيق:
- Firebase: نظام أساسي يوفر عددًا من الخدمات المفيدة لنظام التشغيل iOS أو Android أو تطبيقات الويب. هنا يتم استخدام قاعدة بيانات الوقت الفعلي الخاصة بها لتخزين معلومات كل هررة ومزامنتها في الوقت الفعلي.
- Moment.js: مكتبة أدوات تسهِّل معالجة التواريخ في JavaScript. يتم تخزين تاريخ ميلاد كل هرّة صغيرة في
قاعدة بيانات Firebase، ويتم استخدام
moment
لاحتساب عمره بالأسابيع.
كيف يمكن أن تساهم تبعيتان فقط في حجم حزمة يبلغ 1 ميغابايت تقريبًا؟ حسنًا، أحد الأسباب هو أن أي تبعية يمكن أن يكون لها تبعيات خاصة بها، لذلك هناك أكثر من اثنتين فقط إذا تم أخذ كل عمق/فرع من "شجرة" التبعية في الاعتبار. من السهل أن يصبح التطبيق كبيرًا بسرعة نسبيًا إذا تم تضمين العديد من التبعيات.
حلِّل أداة الحِزم للحصول على فكرة أفضل عمّا يجري. هناك عدد من الأدوات المختلفة المصمّمة من خلال المنتدى التي يمكنها المساعدة في ذلك، مثل أداة webpack-bundle-analyzer
.
سبق أن تم تضمين حزمة هذه الأداة في التطبيق على أنّها devDependency
.
"devDependencies": {
//...
"webpack-bundle-analyzer": "^2.13.1"
},
وهذا يعني أنه يمكن استخدامها مباشرة في ملف إعداد حزمة الويب.
استيراده في بداية webpack.config.js
:
const path = require("path");
//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
.BundleAnalyzerPlugin;
أضِفه الآن كمكوّن إضافي في نهاية الملف داخل مصفوفة plugins
:
module.exports = {
//...
plugins: [
//...
new BundleAnalyzerPlugin()
]
};
عند إعادة تحميل التطبيق، من المفترَض أن يظهر لك عرض مرئي للحزمة بأكملها بدلاً من التطبيق نفسه.
هذه ليست لطيفة مثل رؤية بعض القطط \r، ولكنها مفيدة جدًا على الرغم من ذلك. يُظهر تحريك مؤشر الماوس فوق أي من الحزم حجمها ممثلًا بثلاث طرق مختلفة:
حجم الإحصاءات | الحجم قبل أي تقليل أو ضغط. |
---|---|
الحجم التحليلي | حجم الحزمة الفعلية داخل الحزمة بعد تجميعها. يعمل الإصدار 4 من حزمة الويب (الذي يُستخدم في هذا التطبيق) على تصغير الملفات المجمّعة تلقائيًا، وهذا هو سبب تصغيرها من حجم الإحصائيات. |
الحجم المضغوط بتنسيق Gzip | حجم الحزمة بعد ضغطها بترميز 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';
والآن، لا يظهر التحذير في "أدوات مطوري البرامج" عندما تتم إعادة تحميل التطبيق. يؤدي فتح لوحة الشبكة في أدوات مطوّري البرامج إلى ظهور انخفاض جيد في حجم الحزمة:
تمت إزالة أكثر من نصف حجم الحزمة. يوفر 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
في تبسيط ذلك بشكل كبير.
كل شيء هو مقايضة، ومن المهم قياس ما إذا كان الأمر يستحق التعقيد والجهد المبذول لطرح حل مخصّص بدلاً من الاعتماد على مكتبة تابعة لجهة خارجية.