ลบโค้ดที่ไม่ได้ใช้

ฮูเซน จอร์เดห์
ฮูสเซน จอร์เดห์

ใน Codelab นี้ ให้ปรับปรุงประสิทธิภาพของแอปพลิเคชันต่อไปนี้ด้วยการนำทรัพยากร Dependency ที่ไม่ได้ใช้และไม่จำเป็นออก

ภาพหน้าจอแอป

วัดระยะทาง

คุณควรวัดว่าเว็บไซต์ทำงานได้ดีเพียงใดก่อนที่จะเพิ่มการเพิ่มประสิทธิภาพ

  • หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ เต็มหน้าจอ

ลองคลิกลูกแมวตัวโปรดของคุณดูเลย! มีการใช้ฐานข้อมูลเรียลไทม์ของ Firebase ในแอปพลิเคชันนี้ ซึ่งเป็นเหตุผลที่คะแนนอัปเดตแบบเรียลไทม์และซิงค์กับทุกๆ ผู้ใช้แอปพลิเคชัน 🐈

  1. กด "Control+Shift+J" (หรือ "Command+Option+J" ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
  2. คลิกแท็บเครือข่าย
  3. เลือกช่องทำเครื่องหมายปิดใช้แคช
  4. โหลดแอปซ้ำ

ขนาดแพ็กเกจเดิม 992 KB

มีการส่ง JavaScript มูลค่าเกือบ 1 MB เพื่อโหลดแอปพลิเคชันง่ายๆ นี้

ดูคำเตือนของโปรเจ็กต์ในเครื่องมือสำหรับนักพัฒนาเว็บ

  • คลิกแท็บคอนโซล
  • ตรวจสอบว่าได้เปิดใช้ Warnings ในเมนูแบบเลื่อนลงของระดับข้างอินพุต Filter แล้ว

ตัวกรองคําเตือน

  • ดูคำเตือนที่แสดง

คำเตือนของคอนโซล

Firebase ซึ่งเป็นหนึ่งในไลบรารีที่ใช้ในแอปพลิเคชันนี้ เป็นผู้สนับสนุนที่ดีด้วยการให้คำเตือนเพื่อแจ้งให้นักพัฒนาซอฟต์แวร์ทราบว่าอย่านำเข้าแพ็กเกจทั้งหมด แต่ให้เฉพาะคอมโพเนนต์ที่ใช้เท่านั้น กล่าวอีกนัยหนึ่งคือ คุณสามารถนำไลบรารีที่ไม่ได้ใช้ออกได้ในแอปพลิเคชันนี้เพื่อให้โหลดได้เร็วขึ้น

นอกจากนี้ยังมีกรณีที่มีการใช้ไลบรารีบางรายการ แต่อาจมีทางเลือกอื่นที่ง่ายกว่า เราจะสำรวจแนวคิดในการนำไลบรารีที่ไม่จำเป็นออกในช่วงท้ายของบทแนะนำนี้

กำลังวิเคราะห์แพ็กเกจ

แอปพลิเคชันมีทรัพยากร Dependency หลัก 2 รายการดังนี้

  • Firebase: แพลตฟอร์มที่นำเสนอบริการที่มีประโยชน์มากมาย สำหรับ iOS, Android หรือเว็บแอปพลิเคชัน ฐานข้อมูลแบบเรียลไทม์ของทางบริษัทแห่งนี้ใช้เพื่อจัดเก็บและซิงค์ข้อมูลของลูกแมวแต่ละตัวแบบเรียลไทม์
  • Moment.js: ไลบรารียูทิลิตีที่ช่วยให้จัดการวันที่ใน JavaScript ได้ง่ายขึ้น วันเกิดของลูกแมวแต่ละตัวจะอยู่ในฐานข้อมูล Firebase และใช้ moment ในการคำนวณอายุของลูกแมวเป็นสัปดาห์

ทรัพยากร Dependency เพียง 2 รายการทำให้ Bundle มีขนาดเกือบ 1 MB ได้ได้อย่างไร เหตุผลข้อหนึ่งก็คือทรัพยากร Dependency ใดๆ ก็อาจมีการพึ่งพิงของตนเอง ดังนั้นจะมีมากกว่า 2 กรณีหากพิจารณาทุกความลึก/แขนงของ "ต้นไม้" แบบพึ่งพิง เป็นไปได้ง่ายที่แอปพลิเคชันจะมีขนาดใหญ่แบบสัมพัทธ์ อย่างรวดเร็วหากมีการรวมทรัพยากร Dependency ไว้หลายรายการ

วิเคราะห์ Bundler เพื่อให้เข้าใจถึงสิ่งที่จะเกิดขึ้นได้ดีขึ้น มีเครื่องมือมากมายที่ชุมชนสร้างขึ้น ซึ่งจะช่วยในการทำเช่นนี้ได้ เช่น 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()
  ]
};

เมื่อแอปพลิเคชันโหลดซ้ำ คุณจะเห็นการแสดงภาพทั้งแพ็กเกจแทนที่จะเห็นตัวแอปเอง

ตัววิเคราะห์ชุด Webpack

ไม่น่ารักเท่าการเห็นลูกแมว ที่ปรากฏขึ้น ก็จริง แต่ก็ยังมีประโยชน์ได้อย่างน่าทึ่ง การวางเมาส์เหนือแพ็กเกจจะแสดงขนาดที่แสดงได้ใน 3 วิธีดังนี้

ขนาดสถิติ ขนาดก่อนการลดขนาดหรือการบีบอัด
ขนาดที่แยกวิเคราะห์แล้ว ขนาดของพัสดุจริงภายในแพ็กเกจหลังจากรวบรวมแล้ว Webpack เวอร์ชัน 4 (ซึ่งใช้ในแอปพลิเคชันนี้) จะลดขนาดไฟล์ที่คอมไพล์โดยอัตโนมัติ ทำให้มีขนาดเล็กกว่าขนาดสถิติ
ขนาดที่บีบอัด ขนาดของแพ็กเกจหลังจากบีบอัดด้วยการเข้ารหัส gzip หัวข้อนี้มีอยู่ในคู่มือแยกต่างหาก

เครื่องมือวิเคราะห์แพ็กเกจ Webpack-bundle จะช่วยให้ระบุแพ็กเกจที่ไม่ได้ใช้หรือไม่จำเป็นซึ่งคิดเป็นสัดส่วนส่วนใหญ่ของแพ็กเกจได้ง่ายขึ้น

กำลังนำแพ็กเกจที่ไม่ได้ใช้ออก

การแสดงภาพแสดงให้เห็นว่าแพ็กเกจ 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';

ตอนนี้เมื่อแอปโหลดซ้ำ คำเตือนเครื่องมือสำหรับนักพัฒนาเว็บจะไม่แสดง การเปิดแผงเครือข่ายของเครื่องมือสำหรับนักพัฒนาเว็บยังช่วยลดขนาด Bundle ให้ลดลงได้ด้วย

ขนาดไฟล์ลดลงเหลือ 480 KB

ขนาดกลุ่มมีขนาดมากกว่าครึ่งหนึ่งถูกนำออก Firebase มีบริการต่างๆ มากมายและให้นักพัฒนาซอฟต์แวร์มีตัวเลือกในการรวมเฉพาะบริการที่จำเป็นจริงๆ ในแอปพลิเคชันนี้ จะใช้เพียง firebase/database ในการจัดเก็บและซิงค์ข้อมูลทั้งหมด ต้องมีการนำเข้า firebase/app ซึ่งจะตั้งค่าแพลตฟอร์ม API สำหรับแต่ละบริการเสมอ

ไลบรารียอดนิยมอื่นๆ อีกมากมาย เช่น lodash ยังอนุญาตให้นักพัฒนาซอฟต์แวร์เลือกนำเข้าส่วนต่างๆ ของแพ็กเกจได้ด้วย โดยไม่ต้องทำอะไรมาก การอัปเดตไลบรารีจะนำเข้าในแอปพลิเคชันเพื่อรวมเฉพาะสิ่งที่ใช้งานอยู่ สามารถช่วยปรับปรุงประสิทธิภาพการทำงานได้อย่างมาก

แม้ว่าขนาดแพ็กเกจจะลดลงไปบ้างแล้ว แต่ยังคงมีงานที่ต้องทำมากกว่านี้ 😈

การนำแพ็กเกจที่ไม่จำเป็นออก

การนำเข้าส่วนต่างๆ ของไลบรารี moment อาจทำได้ยากง่าย ซึ่งต่างจากที่ Firebase อาจนำออกทั้งหมดก็ได้

วันเกิดของลูกแมวน่ารักแต่ละตัวจะจัดเก็บไว้ในรูปแบบ 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';

มี Listener เหตุการณ์ของ 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 ออกจาก Listener เหตุการณ์ได้โดยใช้ฟังก์ชันนี้แทน

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 KB

ขนาดแพ็กเกจของเราลดลงมากกว่าครึ่งหนึ่งอีกครั้ง!

บทสรุป

การใช้ Codelab นี้จะทำให้คุณเข้าใจวิธีวิเคราะห์แพ็กเกจหนึ่งๆ เป็นอย่างดีและเหตุผลที่การนำแพ็กเกจที่ไม่ได้ใช้หรือไม่จำเป็นออกจึงมีประโยชน์ ก่อนที่จะเริ่มเพิ่มประสิทธิภาพแอปพลิเคชันด้วยเทคนิคนี้ คุณต้องทราบว่าวิธีนี้อาจซับซ้อนกว่ามากในแอปพลิเคชันขนาดใหญ่

สำหรับการนำไลบรารีที่ไม่ได้ใช้ออก ให้ลองดูว่าส่วนใดของแพ็กเกจที่ใช้งานอยู่และส่วนใดที่ไม่ได้ใช้งาน สำหรับแพ็กเกจที่ดูลึกลับซึ่งดูเหมือนว่าจะไม่มีการใช้งานที่ใด ให้ย้อนกลับไปดูทรัพยากร Dependency ระดับบนสุดที่อาจจำเป็นต้องใช้ ลองหาวิธีที่จะแยก ความแตกต่างระหว่างกัน

เมื่อพูดถึงการนำไลบรารีที่ไม่จำเป็นออก ทุกอย่างอาจซับซ้อนขึ้นเล็กน้อย คุณต้องทำงานร่วมกับทีมอย่างใกล้ชิดและดูว่ามีโอกาสที่จะทำให้ส่วนต่างๆ ของฐานของโค้ดง่ายขึ้นหรือไม่ การนำ moment ออกจากแอปพลิเคชันนี้อาจดูเหมือนเป็นสิ่งที่ควรทำทุกครั้ง แต่จะเกิดอะไรขึ้นหากมีเขตเวลาและภาษาต่างๆ ที่จำเป็นต้องจัดการ หรือถ้ามีการจัดการวันที่ที่ซับซ้อนขึ้น ควรทำอย่างไร สิ่งต่างๆ อาจซับซ้อนอย่างมากเมื่อปรับเปลี่ยนและแยกวิเคราะห์วันที่/เวลา และไลบรารีอย่าง moment และ date-fns ก็ลดความซับซ้อนลงอย่างมาก

ทุกสิ่งล้วนเป็นข้อดีข้อเสีย และสิ่งสำคัญคือต้องวัดว่าคุ้มค่ากับความซับซ้อนและความพยายามในการเปิดตัวโซลูชันที่กำหนดเองแทนการพึ่งพาไลบรารีของบุคคลที่สามหรือไม่