ในเดือนพฤษภาคม 2022 ทีม Aurora และ Angular ได้ประกาศว่าพวกเขาจะทำงานร่วมกันในคำสั่งรูปภาพสำหรับ Angular คำสั่งนี้เพิ่งเปิดตัวให้นักพัฒนาซอฟต์แวร์ดูตัวอย่างเป็นส่วนหนึ่งของ Angular v14.2 โพสต์นี้อธิบายวิธีที่คำสั่งรูปภาพใหม่อย่าง NgOptimizedImage
รองรับการเพิ่มประสิทธิภาพรูปภาพใน Angular
ข้อมูลเบื้องต้น
รูปภาพเป็นองค์ประกอบที่พบได้ทั่วไปและสำคัญอย่างยิ่งของประสบการณ์ของผู้ใช้เว็บ โดยหน้าเว็บ99.9% สร้างคำขอรูปภาพอย่างน้อย 1 รูป รูปภาพยังเป็นสิ่งที่มีส่วนสำคัญมากที่สุดต่อขนาดหน้าเว็บ โดยคิดเป็นค่ามัธยฐาน 982 กิโลไบต์ต่อหน้า
รูปภาพอาจส่งผลเสียต่อประสิทธิภาพของหน้าเว็บและเมตริก Core Web Vitals เนื่องจากมีจำนวนและขนาดที่เพิ่มขึ้น รูปภาพเป็นองค์ประกอบ Largest Contentful Paint (LCP) ของหน้าเดสก์ท็อป 79.4% ในปี 2021 ด้วยเหตุนี้ พวกเราจึงพยายามอย่างต่อเนื่องเพื่อค้นหารูปภาพที่เพิ่มประสิทธิภาพแล้ว
ทีม Aurora เชื่อว่าการใช้ประโยชน์จากความสามารถของเฟรมเวิร์กจะช่วยแก้ปัญหาที่นักพัฒนาแอปพบได้ทั่วไป การเริ่มต้นครั้งแรกในวงการการเพิ่มประสิทธิภาพรูปภาพคือ คอมโพเนนต์รูปภาพ Next.js พวกเขาถือว่าคอมโพเนนต์นี้เป็นพื้นที่ทดสอบว่าการเพิ่มประสบการณ์ของนักพัฒนาซอฟต์แวร์ (DX) ของการเพิ่มประสิทธิภาพรูปภาพจะทําให้แอปจำนวนมากขึ้นที่ใช้เฟรมเวิร์กมีประสิทธิภาพดีขึ้นหรือไม่
ผลลัพธ์ชุดแรกจากผู้ใช้ Next.js อย่าง Leboncoin นั้นน่าพอใจ Leboncoin พบว่า LCP ดีขึ้นอย่างมาก (จาก 2.4 วินาทีเป็น 1.7 วินาที) หลังจากเริ่มใช้ next/image
การนำ next/image
มาใช้ในชุมชนในภายหลังมีส่วนทำให้จำนวนต้นทาง Next.js ที่เป็นไปตามเกณฑ์ LCP เพิ่มขึ้น ในไม่ช้าก็เริ่มมีคำขอฟีเจอร์ที่คล้ายกันในเฟรมเวิร์กอื่นๆ ซึ่งหนึ่งในนั้นคือ Angular
ด้วยเหตุนี้ Aurora จึงปรึกษากับ Angular และ Nuxt เพื่อสร้างต้นแบบคอมโพเนนต์รูปภาพสำหรับเฟรมเวิร์กเหล่านี้ คอมโพเนนต์รูปภาพ Nuxt เปิดตัวไปเมื่อปีที่แล้ว ตอนนี้เราเปิดตัวคําสั่งรูปภาพ Angular (NgOptimizedImage
) เพื่อนําค่าเริ่มต้นการเพิ่มประสิทธิภาพรูปภาพมายัง Angular แล้ว
โอกาส
Angular เป็นหนึ่งในเฟรมเวิร์ก JavaScript ชั้นนําที่นักพัฒนาซอฟต์แวร์ใช้ในปัจจุบัน แพ็กเกจนี้ใช้โดยต้นทางมากกว่า 50,000 รายการที่ HTTPArchive ทำการ Crawl บนอุปกรณ์เคลื่อนที่ และมีการดาวน์โหลดเกือบ 3 ล้านครั้งต่อสัปดาห์ใน NPM
เมื่อพิจารณาคะแนน Core Web Vitals พบว่าเปอร์เซ็นต์ของต้นทาง Angular ที่เป็นไปตามเกณฑ์ LCP "ดี" ยังต้องปรับปรุง เว็บไซต์ Angular เพียง 18.74% เท่านั้นที่มี LCP ดีในอุปกรณ์เคลื่อนที่ในเดือนมิถุนายน 2022 เนื่องจากรูปภาพเป็นองค์ประกอบ LCP ของหน้าเว็บมากกว่า 70% ในอุปกรณ์เคลื่อนที่และเดสก์ท็อป รูปภาพ LCP ที่ไม่ได้เพิ่มประสิทธิภาพจึงอาจเป็นสาเหตุหลักประการหนึ่งที่ทำให้ LCP ในเว็บไซต์ Angular ช้าลง
คำสั่งรูปภาพ Angular ได้รับการออกแบบมาเพื่อช่วยปรับปรุงตัวเลขเหล่านี้
MVP สําหรับคําสั่ง NgOptimizedImage
MVP ของคำสั่งรูปภาพ Angular สร้างขึ้นจากบทเรียนจากคอมโพเนนต์รูปภาพที่ Aurora สร้างขึ้นจนถึงปัจจุบัน พร้อมกับปรับการออกแบบให้เข้ากับประสบการณ์การแสดงผลฝั่งไคลเอ็นต์ของ Angular ปัญหาด้านการเพิ่มประสิทธิภาพรูปภาพมาตรฐานหลายอย่างได้รับการแก้ไขแล้วโดยการดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้
- ระบุค่าเริ่มต้นที่รัดกุม
- แสดงข้อผิดพลาดหรือคำเตือนเพื่อให้เป็นไปตามแนวทางปฏิบัติแนะนำ
ไฮไลต์ของการออกแบบมีดังนี้
การโหลดแบบ Lazy Loading อัจฉริยะ
รูปภาพที่ผู้ใช้มองไม่เห็นเมื่อหน้าเว็บโหลด (เช่น รูปภาพที่อยู่ด้านล่างของหน้าเว็บหรือรูปภาพภาพสไลด์ที่ซ่อนอยู่) ควรโหลดแบบเลื่อนดูเมื่อถึงเวลา การโหลดแบบเลื่อนเวลาช่วยให้เบราว์เซอร์มีทรัพยากรว่างสำหรับโหลดข้อความ สื่อ หรือสคริปต์ที่สำคัญอื่นๆ รูปภาพส่วนใหญ่ไม่สำคัญและควรใช้การโหลดแบบเลื่อนดูทีละหน้า แต่มีเพียงหน้าเว็บ 7.8% ที่ใช้การโหลดแบบเลื่อนดูทีละหน้าแบบเนทีฟในปี 2021
คำสั่งรูปภาพ Angular จะโหลดแบบ Lazy Loading รูปภาพที่ไม่สําคัญโดยค่าเริ่มต้น และจะโหลดเฉพาะรูปภาพที่ทําเครื่องหมายเป็น
priority
โดยเฉพาะ วิธีนี้ช่วยให้มั่นใจได้ว่ารูปภาพส่วนใหญ่จะแสดงลักษณะการโหลดที่ดีที่สุดการจัดลําดับความสําคัญของรูปภาพสําคัญ
การเพิ่มคำแนะนำเกี่ยวกับทรัพยากร (เช่น
preload
หรือpreconnect
) เพื่อจัดลําดับความสําคัญในการโหลดรูปภาพที่สําคัญเป็นแนวทางปฏิบัติแนะนํา แต่แอปส่วนใหญ่ไม่ได้ใช้ ตามข้อมูลใน Web Almanac ปี 2021 มีเพียงหน้าเว็บบนอุปกรณ์เคลื่อนที่ 12.7% ที่ใช้คำแนะนำการจองล่วงหน้า และหน้าเว็บบนอุปกรณ์เคลื่อนที่เพียง 22.1% ที่ใช้คำแนะนำการโหลดล่วงหน้าคำสั่งรูปภาพจะทำงาน 2 ด้านเมื่อมีการทําเครื่องหมายรูปภาพว่าสำคัญ
- ซึ่งจะตั้งค่า fetchpriority ของรูปภาพเป็น
"high"
เพื่อให้เบราว์เซอร์ทราบว่าควรดาวน์โหลดรูปภาพดังกล่าวโดยให้ความสําคัญสูง - ในโหมดการพัฒนา การตรวจสอบรันไทม์จะยืนยันว่ามีการใส่คำแนะนำแหล่งข้อมูล
preconnect
ไว้ซึ่งสอดคล้องกับต้นทางของรูปภาพ
ในโหมดการพัฒนา คำสั่งดังกล่าวจะใช้ PerformanceObserver API เพื่อยืนยันว่ามีการทําเครื่องหมาย รูปภาพ LCP เป็น
priority
ตามที่คาดไว้ หากไม่ได้ทําเครื่องหมายเป็นpriority
ระบบจะแสดงข้อผิดพลาดเพื่อแจ้งให้นักพัฒนาแอปเพิ่มแอตทริบิวต์priority
ลงในรูปภาพ LCPท้ายที่สุดแล้ว การทำงานอัตโนมัติและการปฏิบัติตามข้อกำหนดนี้ช่วยให้มั่นใจได้ว่ารูปภาพ LCP จะมีคำแนะนำ
preconnect
, ค่าแอตทริบิวต์fetchpriority
เป็นhigh
และจะไม่แสดงแบบ Lazy Load- ซึ่งจะตั้งค่า fetchpriority ของรูปภาพเป็น
การกำหนดค่าที่เพิ่มประสิทธิภาพสำหรับเครื่องมือรูปภาพยอดนิยม
เราขอแนะนําให้แอปพลิเคชัน Angular ใช้ CDN รูปภาพ ซึ่งมักจะให้บริการเพิ่มประสิทธิภาพโดยค่าเริ่มต้น
คำสั่งนี้สนับสนุนให้ใช้ CDN รูปภาพโดยมอบประสบการณ์การใช้งาน (DX) ที่น่าสนใจอย่างยิ่งสำหรับนักพัฒนาแอปในการกำหนดค่า CDN ในแอป โดยรองรับ API ของโปรแกรมโหลดที่ช่วยให้คุณกำหนดผู้ให้บริการ CDN และ URL พื้นฐานในการกำหนดค่าได้ เมื่อกําหนดค่าแล้ว คุณจะต้องกําหนดชื่อชิ้นงานในมาร์กอัปเท่านั้น ตัวอย่างเช่น
// in module providers: provideImgixLoader('https://mysite.net/assets/') // in markup <img ngSrc="image.png" > <img ngSrc="image2.png" >
ซึ่งเทียบเท่ากับการใส่แท็กรูปภาพต่อไปนี้และลดมาร์กอัปที่นักพัฒนาแอปต้องใส่สำหรับรูปภาพทุกรูป
<img src="https://mysite.net/assets/image.png"> <img src="https://mysite.net/assets/image2.png">
คำสั่งรูปภาพมีโปรแกรมโหลดในตัวที่มีการกำหนดค่าที่เหมาะสมที่สุดสำหรับ CDN รูปภาพที่ได้รับความนิยมสูงสุด โปรแกรมโหลดเหล่านี้จะจัดรูปแบบ URL รูปภาพโดยอัตโนมัติเพื่อให้แน่ใจว่ามีการใช้รูปแบบรูปภาพและการตั้งค่าการบีบอัดที่แนะนำสำหรับ CDN แต่ละรายการ
ข้อผิดพลาดและคําเตือนในตัว
นอกจากการเพิ่มประสิทธิภาพในตัวข้างต้นแล้ว คำสั่งดังกล่าวยังมีการตรวจสอบในตัวเพื่อให้มั่นใจว่านักพัฒนาซอฟต์แวร์ได้ปฏิบัติตามแนวทางปฏิบัติแนะนำในมาร์กอัปรูปภาพ คำสั่งรูปภาพจะดำเนินการตรวจสอบต่อไปนี้
รูปภาพที่ไม่มีขนาด: คำสั่งรูปภาพจะแสดงข้อผิดพลาดหากมาร์กอัปรูปภาพไม่ได้กำหนดความกว้างและความสูงอย่างชัดเจน รูปภาพที่ไม่มีการปรับขนาดอาจทำให้เกิดการเปลี่ยนแปลงเลย์เอาต์ ซึ่งส่งผลต่อเมตริกการเปลี่ยนแปลงเลย์เอาต์สะสม (CLS) ของหน้า แนวทางปฏิบัติแนะนำเพื่อป้องกันปัญหานี้คือรูปภาพควรระบุแอตทริบิวต์
width
และheight
สัดส่วนการแสดงผล: คำสั่งรูปภาพจะแสดงข้อผิดพลาดเพื่อให้นักพัฒนาซอฟต์แวร์ทราบหากสัดส่วนการแสดงผลของ
width
:height
ที่กําหนดไว้ใน HTML ไม่ใกล้เคียงกับสัดส่วนการแสดงผลจริงของรูปภาพที่แสดงผล ซึ่งอาจทำให้รูปภาพบิดเบี้ยวบนหน้าจอ กรณีนี้อาจเกิดขึ้นได้หาก- คุณกําหนดขนาด (ความกว้างหรือความสูง) ที่ไม่ถูกต้องโดยไม่ตั้งใจ หรือ
- หากคุณกำหนดขนาด 1 รายการเป็นเปอร์เซ็นต์ใน CSS แต่ไม่ได้กำหนดอีก 1 รายการ (เช่น
width: 100%
ต้องกำหนดheight: auto
เพื่อให้รูปภาพขยายทั้ง 2 ขนาด)
รูปภาพขนาดใหญ่เกิน: หากรูปภาพไม่ได้กำหนด
srcset
และรูปภาพภายในมีขนาดใหญ่กว่ารูปภาพที่แสดงผลอย่างมาก คำสั่งจะแสดงคำเตือนที่แนะนำให้ใช้แอตทริบิวต์srcset
และsizes
ความหนาแน่นของรูปภาพ: คำสั่งจะแสดงข้อผิดพลาดหากคุณพยายามใส่รูปภาพใน
srcset
ที่มีความหนาแน่นของพิกเซลมากกว่า3x
โดยทั่วไปเราไม่แนะนําให้ใช้คําอธิบายที่สูงกว่า2x
เนื่องจากอาจส่งผลให้อุปกรณ์เคลื่อนที่ที่มีความละเอียดสูงต้องดาวน์โหลดรูปภาพขนาดใหญ่ นอกจากนี้ ดวงตาของมนุษย์ไม่สามารถแยกความแตกต่างได้มากนักเมื่อใช้การขยายมากกว่า 2 เท่า
ความท้าทาย
การปรับกลยุทธ์การเพิ่มประสิทธิภาพรูปภาพให้ทำงานภายในเฟรมเวิร์กฝั่งไคลเอ็นต์เป็นปัญหาหลักเมื่อออกแบบ NgOptimizedImage
ประสบการณ์การแสดงผลเริ่มต้นใน Next.js คือการแสดงผลฝั่งเซิร์ฟเวอร์ (SSR) หรือการสร้างเว็บไซต์แบบคงที่ (SSG) ส่วนใน Angular คือการแสดงผลฝั่งไคลเอ็นต์ (CSR) แม้ว่า Angular จะรองรับไลบรารี SSR อย่าง angular/universal แต่แอป Angular ส่วนใหญ่ (~60%) ใช้ CSR
คำสั่งรูปภาพสร้างขึ้นทั้งหมดสําหรับ CSR เพื่อให้สอดคล้องกับกรณีการใช้งานทั่วไปในแอป Angular ข้อจำกัดนี้ทำให้เกิดข้อจำกัดเพิ่มเติม และทีมต้องคิดหาวิธีสร้างการเพิ่มประสิทธิภาพที่เฉพาะเจาะจงสำหรับแอป CSR
ปัญหาที่พบมีดังนี้
คำแนะนำเกี่ยวกับแหล่งข้อมูลที่รองรับ
การโหลดเนื้อหาสําคัญล่วงหน้าช่วยให้เบราว์เซอร์ค้นพบเนื้อหาเหล่านั้นได้เร็วขึ้น อย่างไรก็ตาม การใส่คำแนะนำแหล่งข้อมูลในแอป Angular มีความซับซ้อนเนื่องจากเหตุผลต่อไปนี้
การเพิ่มด้วยตนเอง: นักพัฒนาแอปจะเพิ่มคำแนะนำทรัพยากร
preload
ด้วยตนเองได้ยาก Angular ใช้ไฟล์ index.html ที่แชร์ไฟล์เดียวสําหรับทั้งโปรเจ็กต์หรือสําหรับเส้นทางทั้งหมดในเว็บไซต์ ดังนั้น<head>
ของเอกสารจึงเหมือนกันสำหรับทุกเส้นทาง (อย่างน้อยก็ในเวลาที่แสดง) การเพิ่มคำแนะนำpreload
ลงใน<head>
หมายความว่าระบบจะโหลดทรัพยากรไว้ล่วงหน้าสำหรับทุกเส้นทาง แม้ว่าจะไม่จำเป็นก็ตาม ดังนั้นจึงไม่แนะนำให้เพิ่มคำแนะนำpreload
ด้วยตนเองการเพิ่มอัตโนมัติระหว่างการแสดงผล: การใช้เฟรมเวิร์กเพื่อเพิ่มคำแนะนำการโหลดล่วงหน้าในส่วนหัวของเอกสารระหว่างการแสดงผลในแอป CSR ไม่ได้ช่วยอะไร เนื่องจากการแสดงผลเกิดขึ้นหลังจากที่ดาวน์โหลดและเรียกใช้ JavaScript แล้ว
<head>
จึงแสดงผลช้าเกินไปที่จะมีประโยชน์สำหรับคำสั่งเวอร์ชันแรก คำแนะนำ
preconnect
และfetchpriority
ร่วมกันจะจัดลําดับความสําคัญของรูปภาพแทนpreload
อย่างไรก็ตาม ตอนนี้ Aurora กำลังทำงานร่วมกับทีม Angular CLI เพื่อเปิดใช้การแทรกคำแนะนำทรัพยากรโดยอัตโนมัติเมื่อถึงเวลาสร้าง โปรดติดตามดูการเพิ่มประสิทธิภาพขนาดและรูปแบบรูปภาพบนเซิร์ฟเวอร์
เนื่องจากโดยทั่วไปแอป Angular จะแสดงผลฝั่งไคลเอ็นต์ ระบบจึงไม่สามารถบีบอัดรูปภาพในระบบไฟล์ ณ เวลาที่มีคำขอและจะแสดงรูปภาพตามที่เป็นอยู่ ดังนั้น เราขอแนะนำให้ใช้ CDN รูปภาพเพื่อบีบอัดรูปภาพและแปลงเป็นรูปแบบสมัยใหม่ เช่น WebP หรือ AVIF ตามคำขอ
แม้ว่าคำสั่งจะไม่บังคับให้ใช้ CDN รูปภาพ แต่เราขอแนะนำให้ใช้ CDN กับคำสั่งและโปรแกรมโหลดในตัวเพื่อให้ใช้ตัวเลือกการกำหนดค่าที่ถูกต้อง
ผลกระทบ
การสาธิตต่อไปนี้แสดงให้เห็นความแตกต่างที่คำสั่งรูปภาพ Angular สามารถสร้างต่อประสิทธิภาพของรูปภาพ โดยจะเปรียบเทียบเว็บไซต์ 2 เว็บไซต์ ดังนี้
เว็บไซต์ที่ 1: ใช้องค์ประกอบ <img>
เดิมที่มีรูปภาพที่แสดงผ่าน CDN ของ Imgix (พร้อมตัวเลือกการกําหนดค่าเริ่มต้น)
เว็บไซต์ที่ 2: ใช้คําสั่งรูปภาพสําหรับรูปภาพทั้งหมด รวมถึงการเพิ่มประสิทธิภาพที่แนะนําโดยคําเตือนหรือข้อผิดพลาดที่ไดเรกทีฟแสดงโดยตรง
ทีมได้ทํางานร่วมกับพาร์ทเนอร์เพื่อตรวจสอบผลกระทบด้านประสิทธิภาพของคําสั่งรูปภาพในแอปพลิเคชัน Angular ขององค์กรจริง
โดยหนึ่งในพาร์ทเนอร์เหล่านี้คือ Land's End เว็บไซต์ดังกล่าวถือเป็นกรณีทดสอบที่ดีสำหรับผลลัพธ์ที่แอปพลิเคชันจริงอาจเห็น
การทดสอบในแล็บของ Lighthouse ดำเนินการในสภาพแวดล้อม QA ก่อนและหลังการใช้คำสั่งรูปภาพ LCP มัธยฐานในเดสก์ท็อปลดลงจาก 12.0 วินาทีเป็น 3.0 วินาที ซึ่งถือเป็นการปรับปรุง LCP ขึ้น 75% ในอุปกรณ์เคลื่อนที่ ค่ามัธยฐานของ LCP ลดลงจาก 20.2 วินาทีเป็น 12.0 วินาที (ปรับปรุงขึ้น 40.6%)
แผนกลยุทธ์ในอนาคต
นี่เป็นเพียงการเปิดตัวครั้งแรกของการออกแบบสำหรับคำสั่งรูปภาพ Angular เรามีแผนที่จะเพิ่มฟีเจอร์อื่นๆ อีกมากมายในเวอร์ชันในอนาคต ซึ่งรวมถึง
การรองรับรูปภาพที่ปรับเปลี่ยนตามพื้นที่โฆษณาได้ดียิ่งขึ้น
ปัจจุบัน
NgOptimizedImage
รองรับการใช้srcset
แต่ต้องระบุแอตทริบิวต์srcset
และsizes
ด้วยตนเองสำหรับรูปภาพแต่ละรูป ในอนาคต คำสั่งนี้จะสร้างแอตทริบิวต์srcset
และsizes
โดยอัตโนมัติการแทรกคำแนะนำแหล่งข้อมูลโดยอัตโนมัติ
คุณอาจผสานรวมกับ Angular CLI เพื่อสร้างแท็กการจองล่วงหน้าและโหลดล่วงหน้าสําหรับรูปภาพ LCP ที่สําคัญได้
การรองรับ Angular SSR
เวอร์ชัน MVP ได้รับการออกแบบโดยคำนึงถึงข้อจำกัดของ CSR ของ Angular แต่คุณก็ควรสำรวจโซลูชันการเพิ่มประสิทธิภาพรูปภาพสำหรับ Angular SSR (angular/universal) ด้วย
การปรับปรุงประสบการณ์การใช้งานสำหรับนักพัฒนาแอป
NgOptimizedImage
กำหนดให้ต้องระบุแอตทริบิวต์width
และheight
สำหรับรูปภาพแต่ละรูป อย่างไรก็ตาม การระบุข้อมูลเหล่านี้สำหรับรูปภาพแต่ละรูปอาจทำให้นักพัฒนาแอปบางรายรู้สึกเหนื่อยหน่าย เราอาจปรับปรุงประสบการณ์การใช้งานของนักพัฒนาแอปในส่วนนี้ในรุ่นถัดไป ดังนี้- รองรับโหมดเพิ่มเติม (คล้ายกับตัวเลือกเลย์เอาต์รูปภาพ "
fill
" ใน Next.js) ที่ไม่จําเป็นต้องกําหนดความกว้าง/ความสูงอย่างชัดเจน - การใช้การผสานรวม CLI เพื่อตั้งค่าความกว้างและความสูงของรูปภาพในเครื่องโดยอัตโนมัติโดยพิจารณาจากขนาดจริงของรูปภาพ
- รองรับโหมดเพิ่มเติม (คล้ายกับตัวเลือกเลย์เอาต์รูปภาพ "
บทสรุป
คำสั่งรูปภาพ Angular จะพร้อมให้นักพัฒนาซอฟต์แวร์ใช้งานเป็นระยะๆ โดยเริ่มจากเวอร์ชันตัวอย่างสำหรับนักพัฒนาซอฟต์แวร์ใน v14.2.0 ลองใช้ NgOptimizedImage
แล้วแสดงความคิดเห็น
ขอขอบคุณ Katie Hempenius และ Alex Castle เป็นอย่างยิ่งสำหรับการมีส่วนร่วม