ในโค้ดแล็บนี้ ให้ปรับปรุงประสิทธิภาพของแอปพลิเคชันต่อไปนี้ด้วยการนําการพึ่งพาที่ไม่ได้ใช้และไม่จําเป็นออก
วัดระยะทาง
คุณควรวัดประสิทธิภาพของเว็บไซต์ก่อนเพิ่มการเพิ่มประสิทธิภาพเสมอ
- หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ
คลิกแมวน้อยตัวโปรดได้เลย แอปพลิเคชันนี้ใช้ Realtime Database ของ Firebase จึงทำให้คะแนนอัปเดตแบบเรียลไทม์และซิงค์กับผู้ใช้ทุกคนที่ใช้แอปพลิเคชัน 🐈
- กดแป้น Control+Shift+J (หรือ Command+Option+J ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์
- คลิกแท็บเครือข่าย
- เลือกช่องทำเครื่องหมายปิดใช้แคช
- โหลดแอปซ้ำ
ระบบกำลังโหลด 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()
]
};
เมื่อแอปพลิเคชันโหลดซ้ำ คุณควรเห็นภาพรวมของทั้งกลุ่มแทนแอป
ไม่ได้น่ารักเท่าการเห็นลูกแมว 🐱 แต่มีประโยชน์มาก การวางเมาส์เหนือแพ็กเกจใดก็ได้จะแสดงขนาดของแพ็กเกจนั้นใน 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';
ตอนนี้เมื่อโหลดแอปซ้ำ คำเตือนของเครื่องมือสำหรับนักพัฒนาเว็บจะไม่แสดง การเปิดแผงเครือข่ายของเครื่องมือสำหรับนักพัฒนาเว็บยังแสดงให้เห็นการลดขนาดกลุ่มที่น่าพอใจด้วย
มีการนำเนื้อหามากกว่าครึ่งของแพ็กเกจออก Firebase มีบริการที่หลากหลายและช่วยให้นักพัฒนาแอปมีตัวเลือกในการรวมเฉพาะบริการที่จําเป็นเท่านั้น ในแอปพลิเคชันนี้ มีการใช้ firebase/database
เพียงอย่างเดียวในการจัดเก็บและซิงค์ข้อมูลทั้งหมด คุณต้องทำการนําเข้า firebase/app
ซึ่งจะตั้งค่าอินเทอร์เฟซ API สําหรับบริการแต่ละรายการเสมอ
ไลบรารียอดนิยมอื่นๆ อีกมากมาย เช่น lodash
ยังอนุญาตให้นักพัฒนาแอปนำเข้าส่วนต่างๆ ของแพ็กเกจแบบเลือกได้ด้วย การอัปเดตการนําเข้าไลบรารีในแอปพลิเคชันให้มีเฉพาะสิ่งที่ใช้อยู่เท่านั้น จะช่วยปรับปรุงประสิทธิภาพได้อย่างมากโดยไม่ต้องทํางานมาก
แม้ว่าขนาด Bundle จะลดลงไปมากแล้ว แต่เรายังคงต้องดำเนินการเพิ่มเติม 😈
การนำแพ็กเกจที่ไม่จำเป็นออก
การนําเข้าบางส่วนของไลบรารี moment
นั้นทําได้ยากกว่า Firebase แต่คุณอาจนําออกได้ทั้งหมด
วันเกิดของลูกแมวแต่ละตัวจัดเก็บในรูปแบบ Unix (มิลลิวินาที) ในฐานข้อมูล Firebase
ซึ่งเป็นการประทับเวลาของวันที่และเวลาหนึ่งๆ ที่แสดงด้วยจํานวนมิลลิวินาทีที่ผ่านไปนับตั้งแต่วันที่ 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 ได้อีกกว่าครึ่ง
บทสรุป
เมื่อทำ Codelab นี้ คุณควรมีความเข้าใจที่ดีเกี่ยวกับวิธีวิเคราะห์กลุ่มที่เฉพาะเจาะจง และเหตุผลที่การนําแพ็กเกจที่ไม่ได้ใช้หรือไม่จําเป็นออกมีประโยชน์มาก ก่อนเริ่มเพิ่มประสิทธิภาพแอปพลิเคชันด้วยเทคนิคนี้ คุณควรทราบว่าเทคนิคนี้อาจมีความซับซ้อนมากขึ้นอย่างมากในแอปพลิเคชันขนาดใหญ่
ในส่วนการนำไลบรารีที่ไม่ได้ใช้ออก ให้ลองดูว่ามีการนําส่วนใดของกลุ่มไปใช้บ้างและไม่ได้นําส่วนใดไปใช้ สำหรับแพ็กเกจที่ดูลึกลับซึ่งดูเหมือนว่าไม่มีการใช้ที่ใดเลย ให้ลองถอยหลังและตรวจสอบว่าแพ็กเกจดังกล่าวอาจต้องใช้กับ Dependency ระดับบนสุดใด ลองหาวิธีที่จะแยกบัญชีออกจากกันได้
ส่วนการนำไลบรารีที่ไม่จำเป็นออกนั้นอาจมีความซับซ้อนกว่า คุณควรทํางานร่วมกับทีมอย่างใกล้ชิดเพื่อดูว่าสามารถลดความซับซ้อนของโค้ดได้หรือไม่ การนํา moment
ออกจากแอปพลิเคชันนี้อาจดูเหมือนเป็นวิธีที่เหมาะสมเสมอ แต่จะเกิดอะไรขึ้นหากต้องจัดการกับเขตเวลาและภาษาที่แตกต่างกัน หรือในกรณีที่มีการดัดแปลงวันที่ที่ซับซ้อนมากขึ้น การดำเนินการและแยกวิเคราะห์วันที่/เวลาอาจเป็นเรื่องยากมาก แต่ไลบรารีอย่าง moment
และ date-fns
จะช่วยให้การดำเนินการนี้ง่ายขึ้นอย่างมาก
ทุกอย่างมีค่าใช้จ่ายที่ต้องแลกมา และคุณควรประเมินว่าความซับซ้อนและความพยายามในการเปิดตัวโซลูชันที่กําหนดเองนั้นคุ้มค่าหรือไม่ แทนที่จะใช้ไลบรารีของบุคคลที่สาม