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

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

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

วัดระยะทาง

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

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

คลิกแมวน้อยตัวโปรดได้เลย แอปพลิเคชันนี้ใช้ 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 จะใช้ในการคำนวณอายุของลูกแมวในหน่วยสัปดาห์

ทรัพยากร Dependency เพียง 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 วิธีดังนี้

ขนาดสถิติ ขนาดก่อนการย่อขนาดหรือการบีบอัด
ขนาดที่แยกวิเคราะห์ ขนาดจริงของแพ็กเกจภายในแพ็กเกจหลังจากทำการคอมไพล์แล้ว 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 จะลดลงไปมากแล้ว แต่เรายังคงต้องดำเนินการเพิ่มเติม 😈

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

ต่างจาก 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';

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

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

แพ็กเกจมีขนาดลดลงเหลือ 225 KB

ขนาดของชุดของเราลดลงมากกว่าครึ่งอีกครั้ง!

บทสรุป

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

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

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

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