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