การเพิ่มประสิทธิภาพการโหลดสคริปต์ของบุคคลที่สามใน Next.js

ทำความเข้าใจวิสัยทัศน์เบื้องหลังคอมโพเนนต์สคริปต์ของ Next.js ซึ่งมีโซลูชันในตัวเพื่อเพิ่มประสิทธิภาพการโหลดสคริปต์ของบุคคลที่สาม

Leena Sohoni
Leena Sohoni

คำขอประมาณ 45% จากเว็บไซต์ที่แสดงบนอุปกรณ์เคลื่อนที่และเดสก์ท็อปเป็นคำขอของบุคคลที่สาม ซึ่ง 33% เป็นสคริปต์ ขนาด เวลาในการตอบสนอง และการโหลดสคริปต์ของบุคคลที่สามอาจส่งผลต่อประสิทธิภาพของเว็บไซต์อย่างมาก คอมโพเนนต์สคริปต์ Next.js มาพร้อมกับแนวทางปฏิบัติแนะนำและค่าเริ่มต้นที่ฝังอยู่เพื่อช่วยให้นักพัฒนาแอปสามารถนำสคริปต์ของบุคคลที่สามมาใช้ในแอปพลิเคชันของตนได้ พร้อมทั้งแก้ไขปัญหาด้านประสิทธิภาพที่อาจเกิดขึ้นได้ทันที

สคริปต์ของบุคคลที่สามและผลกระทบต่อประสิทธิภาพ

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

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

ควรโหลดไลบรารีของบุคคลที่สามที่จำเป็นสำหรับเลย์เอาต์ตั้งแต่เนิ่นๆ เพื่อแสดงผลหน้าเว็บ ควรเลื่อนเวลาการแสดงผลของบุคคลที่สามที่ไม่จำเป็นสำหรับการแสดงผลเริ่มต้น เพื่อไม่ให้บล็อกการประมวลผลอื่นๆ ในเทรดหลัก Lighthouse มีการตรวจสอบ 2 รายการเพื่อแจ้งว่าสคริปต์ใดบล็อกการแสดงผลหรือบล็อกเทรดหลัก

การตรวจสอบ Lighthouse สำหรับกำจัดทรัพยากรที่บล็อกการแสดงผลและลดการใช้ของบุคคลที่สาม

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

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

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

การมุ่งเน้นของ Aurora ในเรื่องสคริปต์ของบุคคลที่สาม

ส่วนหนึ่งของการทำงานร่วมกันของ Aurora กับเฟรมเวิร์กและเครื่องมือเว็บโอเพนซอร์สคือการจัดหาค่าเริ่มต้นที่มีประสิทธิภาพและเครื่องมือที่เฉพาะเจาะจงเพื่อช่วยให้นักพัฒนาซอฟต์แวร์ปรับปรุงแง่มุมต่างๆ ของประสบการณ์ของผู้ใช้ เช่น ประสิทธิภาพ การช่วยเหลือพิเศษ ความปลอดภัย และความพร้อมใช้งานบนอุปกรณ์เคลื่อนที่ ในปี 2021 เรามุ่งเน้นที่การช่วยให้สแต็กเฟรมเวิร์กปรับปรุงประสบการณ์ของผู้ใช้และเมตริก Core Web Vitals

ขั้นตอนที่สำคัญที่สุดขั้นตอนหนึ่งในการบรรลุเป้าหมายเพื่อปรับปรุงประสิทธิภาพของเฟรมเวิร์กคือการค้นคว้าลำดับการโหลดที่เหมาะสมที่สุดของสคริปต์ของบุคคลที่สามใน Next.js เฟรมเวิร์กอย่าง Next.js มีความโดดเด่นตรงที่สามารถระบุค่าเริ่มต้นและฟีเจอร์ที่เป็นประโยชน์ ซึ่งช่วยให้นักพัฒนาซอฟต์แวร์โหลดทรัพยากรได้อย่างมีประสิทธิภาพ รวมถึงทรัพยากรของบุคคลที่สามด้วย เราได้ศึกษาข้อมูลจาก HTTP Archive และ Lighthouse อย่างละเอียดเพื่อค้นหาว่าบุคคลที่สามรายใดบล็อกการแสดงผลมากที่สุดในเฟรมเวิร์กต่างๆ

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

การจัดลำดับสคริปต์ของบุคคลที่สามโดยไม่มีคอมโพเนนต์เฟรมเวิร์ก

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

  1. ใช้แอตทริบิวต์ async หรือ defer กับแท็ก <script> ที่บอกให้เบราว์เซอร์โหลดสคริปต์บุคคลที่สามที่ไม่สำคัญโดยไม่บล็อกโปรแกรมแยกวิเคราะห์เอกสาร สคริปต์ที่ไม่จำเป็นสำหรับการโหลดหน้าเว็บครั้งแรกหรือการโต้ตอบของผู้ใช้ครั้งแรกอาจถือว่าไม่สำคัญ

       <script src="https://example.com/script1.js" defer></script>
       <script src="https://example.com/script2.js" async></script>
    
  2. สร้างการเชื่อมต่อกับต้นทางที่จำเป็นตั้งแต่เนิ่นๆ โดยใช้การเชื่อมต่อล่วงหน้าและ dns-prefetch ซึ่งจะช่วยให้สคริปต์ที่สำคัญเริ่มดาวน์โหลดได้เร็วขึ้น

       <head>
           <link rel="preconnect" href="http://PreconnThis.com">
           <link rel="dns-prefetch" href="http://PrefetchThis.com">
       </head>
    
  3. โหลดแบบ Lazy Loading สำหรับทรัพยากรและการฝังของบุคคลที่สามหลังจากที่เนื้อหาหลักของหน้าโหลดเสร็จแล้ว หรือเมื่อผู้ใช้เลื่อนลงไปยังส่วนของหน้าที่มีทรัพยากรและการฝังเหล่านั้นอยู่

คอมโพเนนต์สคริปต์ Next.js

คอมโพเนนต์สคริปต์ Next.js จะใช้วิธีการข้างต้นในการจัดลำดับสคริปต์และมีเทมเพลตให้นักพัฒนาซอฟต์แวร์กำหนดกลยุทธ์การโหลดของตนเอง เมื่อระบุกลยุทธ์ที่เหมาะสมแล้ว ระบบจะโหลดอย่างเหมาะสมที่สุดโดยไม่บล็อกทรัพยากรที่สำคัญอื่นๆ

คอมโพเนนต์สคริปต์สร้างขึ้นจากแท็ก HTML <script> และมีตัวเลือกในการตั้งค่าลำดับความสำคัญในการโหลดสำหรับสคริปต์ของบุคคลที่สามโดยใช้แอตทริบิวต์กลยุทธ์

// Example for beforeInteractive:
<Script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver" strategy="beforeInteractive" />

// Example for afterInteractive (default):
<Script src="https://example.com/samplescript.js" />

// Example for lazyonload:
<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />

แอตทริบิวต์ strategy มีค่าได้ 3 ค่า

  1. beforeInteractive: ตัวเลือกนี้อาจใช้กับสคริปต์ที่สำคัญซึ่งควรทำงานก่อนที่หน้าเว็บจะมีการโต้ตอบ Next.js ช่วยให้มั่นใจว่าสคริปต์ดังกล่าวจะแทรกลงใน HTML เริ่มต้นบนเซิร์ฟเวอร์และดำเนินการก่อน JavaScript อื่นๆ ที่รวมไว้ในตัว การจัดการความยินยอม สคริปต์การตรวจจับบ็อต หรือไลบรารีตัวช่วยที่จำเป็นต่อการแสดงผลเนื้อหาที่สำคัญเป็นตัวเลือกที่ดีสำหรับกลยุทธ์นี้

  2. afterInteractive: นี่คือกลยุทธ์เริ่มต้นที่ใช้และเทียบเท่ากับการโหลดสคริปต์ที่มีแอตทริบิวต์ defer ควรใช้กับสคริปต์ที่เบราว์เซอร์เรียกใช้ได้หลังจากที่หน้าเว็บเป็นแบบอินเทอร์แอกทีฟ เช่น สคริปต์การวิเคราะห์ Next.js จะแทรกสคริปต์เหล่านี้ในฝั่งไคลเอ็นต์ และสคริปต์จะทำงานหลังจากที่หน้าเว็บได้รับการไฮเดรต ดังนั้น Next.js จะเลื่อนสคริปต์ของบุคคลที่สามทั้งหมดที่กำหนดโดยใช้คอมโพเนนต์สคริปต์ออกไป เว้นแต่จะระบุไว้เป็นอย่างอื่น ซึ่งจะทำให้ค่าเริ่มต้นมีประสิทธิภาพสูง

  3. lazyOnload: ตัวเลือกนี้อาจใช้เพื่อโหลดสคริปต์ที่มีลำดับความสำคัญต่ำแบบ Lazy Loading เมื่อเบราว์เซอร์ไม่มีการใช้งาน ฟังก์ชันการทำงานที่สคริปต์ดังกล่าวมีให้นั้นไม่จำเป็นต้องใช้ทันทีหลังจากที่หน้าเว็บกลายเป็นแบบอินเทอร์แอกทีฟ เช่น ปลั๊กอินแชทหรือโซเชียลมีเดีย

นักพัฒนาแอปสามารถบอก Next.js ได้ว่าแอปพลิเคชันของตนใช้สคริปต์อย่างไรโดยการระบุกลยุทธ์ ซึ่งจะช่วยให้เฟรมเวิร์กใช้การเพิ่มประสิทธิภาพและแนวทางปฏิบัติแนะนำเพื่อโหลดสคริปต์ได้ พร้อมทั้งรับประกันลำดับการโหลดที่ดีที่สุด

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

การวัดผลกระทบ

เราใช้เทมเพลตสำหรับแอปอีคอมเมิร์ซและบล็อกเริ่มต้นของ Next.js เพื่อสร้างแอปสาธิต 2 แอปที่ช่วยวัดผลกระทบของการรวมสคริปต์ของบุคคลที่สาม บุคคลที่สามที่ใช้กันโดยทั่วไปสำหรับ Google Tag Manager และการฝังโซเชียลมีเดียจะรวมอยู่ในหน้าของแอปเหล่านี้โดยตรงในตอนแรก จากนั้นจึงรวมผ่านคอมโพเนนต์สคริปต์ จากนั้นเราได้เปรียบเทียบประสิทธิภาพของหน้าเว็บเหล่านี้ใน WebPageTest

สคริปต์ของบุคคลที่สามในแอป Next.js Commerce

มีการเพิ่มสคริปต์ของบุคคลที่สามลงในเทมเพลตแอปอีคอมเมิร์ซสำหรับการสาธิตตามที่ระบุด้านล่าง

ก่อน หลัง
Google Tag Manager ที่มี async คอมโพเนนต์สคริปต์ที่มีกลยุทธ์ = afterInteractive สำหรับทั้ง 2 สคริปต์
ปุ่มติดตามของ Twitter ที่ไม่มี Async หรือ Defer
การกำหนดค่าสคริปต์และคอมโพเนนต์สคริปต์สำหรับการสาธิต 1 ที่มี 2 สคริปต์

การเปรียบเทียบต่อไปนี้แสดงความคืบหน้าด้านภาพของ Next.js commerce starter-kit ทั้ง 2 เวอร์ชัน ดังที่เห็น LCP เกิดขึ้นเร็วขึ้นเกือบ 1 วินาทีเมื่อเปิดใช้คอมโพเนนต์สคริปต์ด้วยกลยุทธ์การโหลดที่เหมาะสม

การเปรียบเทียบแถบฟิล์มที่แสดงการปรับปรุง LCP

สคริปต์ของบุคคลที่สามในบล็อก Next.js

ระบบได้เพิ่มสคริปต์ของบุคคลที่สามลงในแอปบล็อกสาธิตตามที่ระบุด้านล่าง

ก่อน หลัง
Google Tag Manager ที่มี async คอมโพเนนต์สคริปต์ที่มี strategy = lazyonload สำหรับสคริปต์ทั้ง 4 รายการ
ปุ่มติดตาม Twitter ที่มีการเรียกใช้แบบไม่พร้อมกัน
ปุ่มติดตามของ YouTube ที่ไม่มี async หรือ defer
ปุ่มติดตามของ LinkedIn ที่ไม่มี async หรือ defer
การกำหนดค่าสคริปต์และคอมโพเนนต์สคริปต์สำหรับการสาธิต 2 ที่มีสคริปต์ 4 รายการ
วิดีโอแสดงความคืบหน้าในการโหลดหน้าดัชนีที่มีและไม่มีคอมโพเนนต์สคริปต์ FCP ดีขึ้น 0.5 วินาทีเมื่อใช้คอมโพเนนต์สคริปต์

ดังที่เห็นในวิดีโอ First Contentful Paint (FCP) เกิดขึ้นที่ 0.9 วินาทีในหน้าเว็บที่ไม่มีคอมโพเนนต์สคริปต์ และ 0.4 วินาทีในหน้าเว็บที่มีคอมโพเนนต์สคริปต์

สิ่งที่จะเกิดขึ้นต่อไปสำหรับคอมโพเนนต์สคริปต์

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

การใช้ Web Worker

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

ในการติดตั้งใช้งานคอมโพเนนต์สคริปต์ Next.js ในปัจจุบัน เราขอแนะนำให้เลื่อนสคริปต์เหล่านี้ในเทรดหลักโดยตั้งค่ากลยุทธ์เป็น afterInteractive หรือ lazyOnload ในอนาคต เราเสนอให้เปิดตัวตัวเลือกกลยุทธ์ใหม่ 'worker' ซึ่งจะช่วยให้ Next.js ใช้ PartyTown หรือโซลูชันที่กำหนดเองเพื่อเรียกใช้สคริปต์ใน Web Worker ได้ เรายินดีรับฟังความคิดเห็นจากนักพัฒนาแอปเกี่ยวกับ RFC นี้

การลด CLS

การฝังของบุคคลที่สาม เช่น โฆษณา วิดีโอ หรือการฝังฟีดโซเชียลมีเดีย อาจทำให้เลย์เอาต์เปลี่ยนเมื่อโหลดแบบ Lazy Loading ซึ่งจะส่งผลต่อประสบการณ์ของผู้ใช้และเมตริก Cumulative Layout Shift (CLS) ของหน้าเว็บ คุณลด CLS ได้โดยระบุขนาดของคอนเทนเนอร์ที่จะโหลดการฝัง

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

คอมโพเนนต์ Wrapper

ไวยากรณ์และกลยุทธ์การโหลดสําหรับการรวมสคริปต์ยอดนิยมของบุคคลที่สาม เช่น Google Analytics หรือ Google Tag Manager (GTM) มักจะคงที่ ซึ่งสามารถรวมไว้ในคอมโพเนนต์ Wrapper แต่ละรายการสำหรับสคริปต์แต่ละประเภทได้อีก นักพัฒนาแอปจะเข้าถึงได้เฉพาะแอตทริบิวต์ที่เจาะจงแอปพลิเคชัน (เช่น รหัสติดตาม) เพียงไม่กี่รายการเท่านั้น คอมโพเนนต์ Wrapper จะช่วยนักพัฒนาแอปได้ดังนี้

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

บทสรุป

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

คำขอบคุณ

ขอขอบคุณ Kara Erickson, Janicklas Ralph, Katie Hempenius, Philip Walton, Jeremy Wagner และ Addy Osmani สำหรับความคิดเห็นเกี่ยวกับโพสต์นี้