ลดเพย์โหลด JavaScript ด้วยการแยกโค้ด

ฮูเซน จอร์เดห์
ฮูสเซน จอร์เดห์
เจเรมี แวกเนอร์
เจเรมี แวกเนอร์

ไม่มีใครชอบรอ ผู้ใช้กว่า 50% ละทิ้งเว็บไซต์หากใช้เวลาโหลดนานกว่า 3 วินาที

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

เหตุใดการแยกโค้ดจึงมีประโยชน์

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

เมื่อพูดถึง Core Web Vitals การลดเพย์โหลด JavaScript ที่ดาวน์โหลดเมื่อเริ่มต้นจะทำให้ First Input Delay (FID) และการโต้ตอบกับ Next Paint (INP) ดีขึ้น สาเหตุคือเมื่อเพิ่มพื้นที่ว่างในเทรดหลัก แอปพลิเคชันจะสามารถตอบสนองต่อข้อมูลของผู้ใช้ได้เร็วขึ้นโดยการลดค่าใช้จ่ายเกี่ยวกับการแยกวิเคราะห์ คอมไพล์ และการดำเนินการที่เกี่ยวข้องกับการดำเนินการ

โดยเฉพาะหากเว็บไซต์ของคุณใช้การแสดงผลฝั่งไคลเอ็นต์อย่างมาก การลดขนาดเพย์โหลด JavaScript ที่ทำให้เกิดมาร์กอัปอาจทำให้ได้รับ Largest Contentful Paint (LCP) ดีขึ้น ทั้งนี้ขึ้นอยู่กับสถาปัตยกรรมของเว็บไซต์ ข้อผิดพลาดนี้อาจเกิดขึ้นเมื่อเบราว์เซอร์ค้นพบทรัพยากร LCP ได้ช้าจนกว่ามาร์กอัปฝั่งไคลเอ็นต์จะเสร็จสิ้น หรือเมื่อเทรดหลักไม่ว่างที่จะแสดงผลองค์ประกอบ LCP ดังกล่าว ทั้ง 2 สถานการณ์นี้อาจทำให้เวลา LCP ของหน้าเว็บล่าช้า

วัดระยะทาง

Lighthouse แสดงการตรวจสอบที่ล้มเหลวเมื่อใช้เวลานานในการดำเนินการ JavaScript ทั้งหมดในหน้าเว็บ

การตรวจสอบ Lighthouse ที่ล้มเหลวซึ่งแสดงสคริปต์ที่ใช้เวลานานเกินไปในการดำเนินการ

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

โปรแกรมสร้างโมดูลยอดนิยม เช่น Webpack, Parcel และ Rollup จะช่วยให้คุณแยกแพ็กเกจได้โดยใช้การนำเข้าแบบไดนามิก เช่น ลองพิจารณาข้อมูลโค้ดต่อไปนี้ที่แสดงตัวอย่างเมธอด someFunction ที่จะเริ่มทำงานเมื่อส่งแบบฟอร์ม

import moduleA from "library";

form.addEventListener("submit", e => {
  e.preventDefault();
  someFunction();
});

const someFunction = () => {
  // uses moduleA
}

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

form.addEventListener("submit", e => {
  e.preventDefault();
  import('library.moduleA')
    .then(module => module.default) // using the default export
    .then(() => someFunction())
    .catch(handleError());
});

const someFunction = () => {
    // uses moduleA
}

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

แม้ว่าข้อมูลโค้ดก่อนหน้านี้จะเป็นตัวอย่างง่ายๆ แต่การโหลดแบบ Lazy Loading ของบุคคลที่สามจะไม่ใช่รูปแบบที่พบได้ทั่วไปในแอปพลิเคชันขนาดใหญ่ โดยปกติแล้วทรัพยากร Dependency ของบุคคลที่สามจะแบ่งออกเป็นกลุ่มผู้ให้บริการแยกต่างหากที่แคชได้เพราะไม่ได้อัปเดตบ่อยเท่าที่ควร อ่านเพิ่มเติมเกี่ยวกับวิธีที่ SplitChunksPlugin ช่วยคุณทำสิ่งนี้ได้

การแยกในระดับเส้นทางหรือคอมโพเนนต์เมื่อใช้เฟรมเวิร์กฝั่งไคลเอ็นต์เป็นวิธีที่ง่ายกว่าในการโหลดส่วนต่างๆ ของแอปพลิเคชัน เฟรมเวิร์กยอดนิยมจำนวนมากที่ใช้ Webpack ให้บทคัดย่อเพื่อทำให้การโหลดแบบ Lazy Loading นั้นง่ายดายกว่าการเจาะลึกการกำหนดค่าด้วยตนเอง