วิธีเร่งความเร็วแอป Next.js ด้วยกลยุทธ์การแยกโค้ดและการโหลดอย่างชาญฉลาด
สิ่งที่คุณจะได้เรียนรู้
โพสต์นี้จะอธิบายการแยกโค้ดประเภทต่างๆ และวิธีใช้การนําเข้าแบบไดนามิกเพื่อเพิ่มความเร็วของแอป Next.js
การแยกโค้ดตามเส้นทางและตามคอมโพเนนต์
โดยค่าเริ่มต้น Next.js จะแยก JavaScript ออกเป็นกลุ่มแยกกันสำหรับแต่ละเส้นทาง เมื่อผู้ใช้โหลดแอปพลิเคชัน Next.js จะส่งเฉพาะโค้ดที่จําเป็นสําหรับเส้นทางเริ่มต้นเท่านั้น เมื่อผู้ใช้ไปยังส่วนต่างๆ ของแอปพลิเคชัน ระบบจะดึงข้อมูลกลุ่มที่เชื่อมโยงกับเส้นทางอื่นๆ การแยกโค้ดตามเส้นทางจะลดจํานวนสคริปต์ที่ต้องแยกวิเคราะห์และคอมไพล์พร้อมกัน ซึ่งส่งผลให้หน้าเว็บโหลดเร็วขึ้น
แม้ว่าการแยกโค้ดตามเส้นทางจะเป็นค่าเริ่มต้นที่ดี แต่คุณก็เพิ่มประสิทธิภาพกระบวนการโหลดเพิ่มเติมได้ด้วยการแยกโค้ดที่ระดับคอมโพเนนต์ หากคอมโพเนนต์ในแอปมีขนาดใหญ่ คุณควรแยกคอมโพเนนต์เหล่านั้นออกเป็นส่วนๆ วิธีนี้ช่วยให้โหลดคอมโพเนนต์ขนาดใหญ่ที่ไม่สําคัญหรือแสดงผลเฉพาะเมื่อผู้ใช้โต้ตอบบางอย่าง (เช่น การคลิกปุ่ม) แบบ Lazy Load ได้
Next.js รองรับ import()
แบบไดนามิก ซึ่งช่วยให้คุณนําเข้าโมดูล JavaScript (รวมถึงคอมโพเนนต์ React) แบบไดนามิกและโหลดการนําเข้าแต่ละรายการเป็นกลุ่มแยกกันได้ วิธีนี้ช่วยให้คุณแบ่งโค้ดระดับคอมโพเนนต์และควบคุมการโหลดทรัพยากรได้ เพื่อให้ผู้ใช้ดาวน์โหลดเฉพาะโค้ดที่ต้องการสำหรับส่วนในเว็บไซต์ที่กําลังดู ใน Next.js คอมโพเนนต์เหล่านี้จะแสดงผลฝั่งเซิร์ฟเวอร์ (SSR) โดยค่าเริ่มต้น
การนําเข้าแบบไดนามิกที่ใช้งานจริง
โพสต์นี้มีตัวอย่างแอปหลายเวอร์ชันที่ประกอบด้วยหน้าเว็บง่ายๆ ที่มีปุ่มเดียว เมื่อคลิกปุ่ม คุณจะเห็นลูกสุนัขน่ารัก เมื่อเลื่อนดูแอปแต่ละเวอร์ชัน คุณจะเห็นความแตกต่างระหว่างการนําเข้าแบบไดนามิกกับการนําเข้าแบบคงที่ และวิธีใช้งาน
ในแอปเวอร์ชันแรก ลูกสุนัขอาศัยอยู่ใน components/Puppy.js
หากต้องการแสดงลูกสุนัขในหน้าเว็บ แอปจะนําเข้าคอมโพเนนต์ Puppy
ใน index.js
ด้วยคำสั่งนําเข้าแบบคงที่ ดังนี้
import Puppy from "../components/Puppy";
หากต้องการดูวิธีที่ Next.js รวมแอป ให้ตรวจสอบการติดตามเครือข่ายใน DevTools โดยทำดังนี้
หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ
กดแป้น Control+Shift+J (หรือ Command+Option+J ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์
คลิกแท็บเครือข่าย
เลือกช่องทำเครื่องหมายปิดใช้แคช
โหลดหน้าเว็บซ้ำ
เมื่อคุณโหลดหน้าเว็บ โค้ดที่จำเป็นทั้งหมด รวมถึงคอมโพเนนต์ Puppy.js
จะรวมอยู่ใน index.js
เมื่อกดปุ่ม Click me ระบบจะเพิ่มเฉพาะคำขอ JPEG ของสุนัขลงในแท็บเครือข่าย
ข้อเสียของแนวทางนี้คือ แม้ว่าผู้ใช้จะไม่คลิกปุ่มเพื่อดูลูกสุนัข แต่ก็ต้องโหลดคอมโพเนนต์ Puppy
เนื่องจากรวมอยู่ใน index.js
ในตัวอย่างนี้ การดำเนินการนี้อาจไม่ใช่เรื่องใหญ่ แต่ในแอปพลิเคชันในชีวิตจริง มักจะเป็นการปรับปรุงที่ยิ่งใหญ่ในการโหลดคอมโพเนนต์ขนาดใหญ่เฉพาะเมื่อจำเป็นเท่านั้น
ตอนนี้มาดูแอปเวอร์ชันที่ 2 ซึ่งมีการนําเข้าแบบไดนามิกแทนที่การนําเข้าแบบคงที่ Next.js มี next/dynamic
ซึ่งทำให้นําเข้าแบบไดนามิกสําหรับคอมโพเนนต์ใดก็ได้ใน Next ได้
import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";
// ...
const Puppy = dynamic(import("../components/Puppy"));
ทำตามขั้นตอนจากตัวอย่างแรกเพื่อตรวจสอบการติดตามเครือข่าย
เมื่อคุณโหลดแอปครั้งแรก ระบบจะดาวน์โหลดเฉพาะ index.js
เท่านั้น ครั้งนี้มีขนาดเล็กลง 0.5 KB (จาก 37.9 KB เหลือ 37.4 KB) เนื่องจากไม่มีโค้ดสำหรับคอมโพเนนต์ Puppy
ดังนี้
ตอนนี้คอมโพเนนต์ Puppy
อยู่ในกลุ่มแยกต่างหาก 1.js
ซึ่งจะโหลดก็ต่อเมื่อคุณกดปุ่มเท่านั้น
ในแอปพลิเคชันในชีวิตจริง คอมโพเนนต์มักจะมีขนาดใหญ่กว่ามาก และการโหลดแบบเลื่อนเวลาสามารถลดเพย์โหลด JavaScript เริ่มต้นได้หลายร้อยกิโลไบต์
การนําเข้าแบบไดนามิกที่มีตัวบ่งชี้การโหลดที่กําหนดเอง
เมื่อใช้การโหลดแบบ Lazy Loading คุณควรระบุตัวบ่งชี้การโหลดไว้เผื่อในกรณีที่เกิดความล่าช้า ใน Next.js คุณทําได้โดยระบุอาร์กิวเมนต์เพิ่มเติมให้กับฟังก์ชัน dynamic()
ดังนี้
const Puppy = dynamic(() => import("../components/Puppy"), {
loading: () => <p>Loading...</p>
});
หากต้องการดูการทำงานของตัวบ่งชี้การโหลด ให้จําลองการเชื่อมต่อเครือข่ายที่ช้าใน DevTools โดยทําดังนี้
หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ
กดแป้น Control+Shift+J (หรือ Command+Option+J ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์
คลิกแท็บเครือข่าย
เลือกช่องทำเครื่องหมายปิดใช้แคช
ในรายการแบบเลื่อนลงการจำกัด ให้เลือก Fast 3G
กดปุ่มคลิกฉัน
ตอนนี้เมื่อคลิกปุ่ม ระบบจะใช้เวลาสักครู่ในการโหลดคอมโพเนนต์และแอปจะแสดงข้อความ "กำลังโหลด…" ในระหว่างนี้
การนําเข้าแบบไดนามิกที่ไม่มี SSR
หากต้องการแสดงผลคอมโพเนนต์ฝั่งไคลเอ็นต์เท่านั้น (เช่น วิดเจ็ตแชท) ให้ตั้งค่าตัวเลือก ssr
เป็น false
ดังนี้
const Puppy = dynamic(() => import("../components/Puppy"), {
ssr: false,
});
บทสรุป
Next.js รองรับการนําเข้าแบบไดนามิก จึงมีการแยกโค้ดระดับคอมโพเนนต์ ซึ่งจะช่วยลดเพย์โหลด JavaScript และปรับปรุงเวลาในการโหลดแอปพลิเคชันได้ คอมโพเนนต์ทั้งหมดจะแสดงผลฝั่งเซิร์ฟเวอร์โดยค่าเริ่มต้น และคุณปิดใช้ตัวเลือกนี้ได้เมื่อใดก็ตามที่ต้องการ