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

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

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

วัดระยะทาง

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

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

คลิกลูกแมวตัวโปรดได้เลย แอปพลิเคชันนี้ใช้ Realtime Database ของ Firebase จึงทำให้คะแนนอัปเดตแบบเรียลไทม์และซิงค์กับผู้ใช้ทุกคนที่ใช้แอปพลิเคชัน 🐈

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

ขนาดเดิมของกลุ่มคือ 992 KB

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

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

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

ตัวกรองคำเตือน

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

คำเตือนในคอนโซล

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

นอกจากนี้ยังมีกรณีที่ใช้ไลบรารีหนึ่งๆ แต่อาจมีทางเลือกที่ง่ายกว่านั้น เราจะพูดถึงแนวคิดในการนําไลบรารีที่ไม่จําเป็นออกในบทแนะนํานี้ในภายหลัง

การวิเคราะห์แพ็กเกจ

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

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

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

วิเคราะห์เครื่องมือจัดกลุ่มเพื่อให้ทราบสถานการณ์ได้ดียิ่งขึ้น มีเครื่องมือที่ชุมชนสร้างขึ้นหลายรายการที่จะช่วยคุณดำเนินการนี้ เช่น 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 Bundle

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

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

เครื่องมือ webpack-bundle-analyzer ช่วยให้ระบุแพ็กเกจที่ไม่ได้ใช้หรือไม่จำเป็นซึ่งคิดเป็นสัดส่วนมากของ 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 ยังอนุญาตให้นักพัฒนาแอปนำเข้าส่วนต่างๆ ของแพ็กเกจแบบเลือกได้ด้วย การอัปเดตการนําเข้าไลบรารีในแอปพลิเคชันให้มีเฉพาะสิ่งที่ใช้อยู่เท่านั้น จะช่วยปรับปรุงประสิทธิภาพได้อย่างมากโดยไม่ต้องทํางานมาก

แม้ว่าขนาด Bundle จะลดลงไปมากแล้ว แต่เรายังคงต้องดำเนินการเพิ่มเติม 😈

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

การนําเข้าบางส่วนของไลบรารี 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';

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 ซึ่งอยู่ในรูปแบบมิลลิวินาทีอยู่แล้ว) แล้วหารด้วยจํานวนมิลลิวินาทีใน 1 สัปดาห์

สุดท้าย คุณสามารถนำอินสแตนซ์ 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>
    `})
});

ตอนนี้ให้โหลดแอปพลิเคชันอีกครั้งและดูที่แผงเครือข่ายอีกครั้ง

ขนาด Bundle ลดลงเหลือ 225 KB

เราลดขนาด Bundle ได้อีกกว่าครึ่ง

บทสรุป

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

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

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

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