إزالة الرموز غير المستخدَمة

في هذا الدرس التطبيقي حول الترميز، حسِّن أداء التطبيق التالي من خلال وإزالة أي تبعيات غير مستخدمة وغير ضرورية.

لقطة شاشة التطبيق

القياس

ومن الأفضل دائمًا قياس مستوى أداء موقع الويب قبل وإضافة التحسينات.

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

انقر على قطتك المفضَّلة. لـ Firebase قاعدة بيانات الوقت الفعلي هي استخدام في هذا التطبيق، وهذا هو سبب تحديث النتيجة في الوقت الفعلي متزامنًا مع كل شخص آخر يستخدم التطبيق. 🐈

  1. اضغط على "Control+Shift+J" (أو "Command+Option+J" على أجهزة Mac) لفتح "أدوات مطوري البرامج".
  2. انقر على علامة التبويب الشبكة.
  3. ضع علامة في مربّع الاختيار إيقاف ذاكرة التخزين المؤقت.
  4. أعِد تحميل التطبيق.

حجم الحزمة الأصلي هو 992 كيلوبايت

يتم شحن 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.config.js:

const path = require("path");

//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

يمكنك إضافته الآن كمكون إضافي في نهاية الملف داخل مصفوفة plugins:

module.exports = {
  //...
  plugins: [
    //...
    new BundleAnalyzerPlugin()
  ]
};

عند إعادة تحميل التطبيق، ينبغي أن يظهر لك تمثيل بصري الحزمة بدلاً من التطبيق نفسه.

أداة تحليل حزم Webpack

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

حجم الإحصاءات الحجم قبل أي تصغير أو ضغط.
الحجم الذي تم تحليله حجم الحزمة الفعلية داخل الحزمة بعد تجميعها. يحد الإصدار 4 من حزمة الويب (المستخدم في هذا التطبيق) من ملفات مجمعة تلقائيًا، ولهذا السبب أصغر من الإحصائيات الحجم.
حجم Gzipped حجم الحزمة بعد ضغطها بترميز gzip. هذا النمط الموضوع في دليل منفصل.

باستخدام أداة تحليل حزمة Webpack، يكون من الأسهل تحديد البيانات غير المستخدَمة أو الحزم غير الضرورية التي تشكل نسبة كبيرة من الحزمة.

إزالة الحزم غير المستخدَمة

يُظهر التمثيل البصري أنّ حزمة 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';

لا يظهر تحذير "أدوات مطوري البرامج" عند إعادة تحميل التطبيق. يؤدي فتح تعرض لوحة شبكة أدوات مطوّري البرامج أيضًا انخفاضًا جيدًا في حجم الحزمة:

تم تقليل حجم الحزمة إلى 480 كيلوبايت

تمت إزالة أكثر من نصف حجم الحزمة. يوفّر Firebase العديد من ويمنح المطورين خيار تضمين فقط الخدمات احتاجت. في هذا التطبيق، تم استخدام firebase/database فقط لتخزين البيانات ومزامنتها. جميع البيانات. استيراد firebase/app، الذي يعمل على إعداد مساحة عرض واجهة برمجة التطبيقات لكل خدمة من الخدمات المختلفة مطلوبة دائمًا.

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

وعلى الرغم من أن حجم الحزمة قد انخفض قليلاً، لا يزال هناك المزيد عملاً ينبغي القيام به! 😈

إزالة الطرود غير الضرورية

على عكس Firebase، لا يمكن استيراد أجزاء من مكتبة moment بالشكل بسهولة، ولكن ربما يمكن إزالتها تمامًا؟

يتم حفظ تاريخ ميلاد كل قطة لطيفة بتنسيق Unix (مللي ثانية) في قاعدة بيانات Firebase.

تواريخ الميلاد المخزَّنة بتنسيق Unix

هذا طابع زمني لتاريخ ووقت معينين ممثلين بعدد بالمللي ثانية التي انقضت منذ 1 كانون الثاني (يناير) 1970 الساعة 00:00 بالتوقيت العالمي المنسق (UTC). إذا كانت قيمة يمكن حساب التاريخ والوقت بنفس التنسيق، وهي دالة صغيرة للعثور عمر كل قطة صغيرة في الأسابيع.

وكما هو الحال دائمًا، حاول عدم النسخ واللصق أثناء المتابعة هنا. البدء بـ إزالة 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>
    `})
});

الآن أعد تحميل التطبيق وألق نظرة على لوحة الشبكة مرة أخرى.

تم تقليل حجم الحزمة إلى 225 كيلوبايت

تم تقليل حجم حزمتنا بأكثر من النصف مرة أخرى!

الخاتمة

من خلال هذا الدرس التطبيقي حول الترميز، يجب أن يكون لديك فهم جيد لكيفية تحليل حزمة معينة ولماذا يمكن أن تكون مفيدة للغاية لإزالة غير المستخدمة أو غير الضرورية حزم. قبل البدء في تحسين أي تطبيق باستخدام هذا الأسلوب، من معرفة أن هذا قد يكون أكثر تعقيدًا بكثير في التطبيقات.

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

عندما يتعلق الأمر بإزالة المكتبات غير اللازمة، قد تحتاج إلى اتّخاذ بعض الإجراءات أمرًا معقدًا. من المهم العمل عن كثب مع فريقك ومعرفة ما إذا كان هناك إمكانية تبسيط أجزاء من قاعدة التعليمات البرمجية. جارٍ إزالة moment في هذه المشاركة تطبيق قد يبدو أنه سيكون التصرف الصحيح الذي يجب القيام به في كل مرة، ولكن ما ما إذا كانت هناك مناطق زمنية وأماكن مختلفة يجب التعامل معها؟ أو ماذا لو كانت هناك عمليات التلاعب بالتواريخ أكثر تعقيدًا؟ يمكن أن تُحدث الأشياء عند التلاعب بالتواريخ/الأوقات وتحليلها، ومكتبات مثل moment وتعمل date-fns على تبسيط ذلك بشكل كبير.

كل شيء هو عبارة عن مقايضة، ومن المهم تقييم ما إذا كانت مدى التعقيد والجهد اللازمين لطرح حل مخصص بدلاً من الاعتماد على ومكتبة تابعة لجهة خارجية