การเพิ่มประสิทธิภาพรูปภาพด้วยคำสั่ง Angular Image Directive

Kara Erickson
Kara Erickson
Leena Sohoni
Leena Sohoni

เมื่อเดือนพฤษภาคม 2022 ทีม Aurora และ Angular ได้ประกาศว่าจะทำงานร่วมกันตามคำสั่งเกี่ยวกับรูปภาพสำหรับ Angular เราเพิ่งเปิดตัวคำสั่งสำหรับตัวอย่างสำหรับนักพัฒนาซอฟต์แวร์ซึ่งเป็นส่วนหนึ่งของ Angular v14.2 โพสต์นี้พูดถึงวิธีที่คำสั่งรูปภาพใหม่ ซึ่งก็คือ NgOptimizedImage จะรองรับการเพิ่มประสิทธิภาพรูปภาพใน Angular

ข้อมูลเบื้องต้น

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

เนื่องจากจำนวนและขนาดที่เพิ่มขึ้น รูปภาพจึงอาจขัดขวางประสิทธิภาพของหน้าเว็บและส่งผลต่อเมตริก Core Web Vitals สําหรับหน้าเว็บในเดสก์ท็อป 79.4% รูปภาพเป็นองค์ประกอบ Largest Contentful Paint (LCP) ในปี 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 ชั้นนำที่นักพัฒนาซอฟต์แวร์ใช้กันในปัจจุบัน มีต้นทางมากกว่า 5 หมื่นครั้งที่รวบรวมข้อมูลโดย HTTPArchive บนอุปกรณ์เคลื่อนที่และมีการดาวน์โหลดเกือบ 3 ล้านครั้งต่อสัปดาห์บน NPM

LCP สำหรับเว็บไซต์ Angular ในช่วง 1 ปีที่ผ่านมา

เมื่อดูคะแนน Core Web Vitals ซึ่งเป็นเปอร์เซ็นต์ของต้นทางของ Angular ที่เป็นไปตาม "ดี" เกณฑ์ LCP ยังคงต้องปรับปรุง เว็บไซต์ Angular เพียง 18.74% ที่มี LCP ที่ดีในอุปกรณ์เคลื่อนที่ในเดือนมิถุนายน 2022 เนื่องจากรูปภาพเป็นองค์ประกอบ LCP ของหน้าเว็บมากกว่า 70% บนอุปกรณ์เคลื่อนที่และเดสก์ท็อป รูปภาพ LCP ที่ไม่ได้เพิ่มประสิทธิภาพจึงอาจเป็นหนึ่งในสาเหตุหลักที่ทำให้ LCP มีคุณภาพต่ำในเว็บไซต์ Angular

คำสั่งรูปภาพ Angular ได้รับการออกแบบมาเพื่อช่วยปรับปรุงตัวเลขเหล่านี้

MVP ของคำสั่ง NgEnhancedImage

MVP ของ Angular image Directive สร้างขึ้นจากบทเรียนจากองค์ประกอบรูปภาพที่ Aurora สร้างขึ้นในปัจจุบัน ขณะเดียวกันก็ปรับการออกแบบให้เข้ากับประสบการณ์การแสดงผลฝั่งไคลเอ็นต์ของ Angular ปัญหาการเพิ่มประสิทธิภาพรูปภาพมาตรฐานส่วนใหญ่ได้รับการแก้ไขแล้วใน

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

การออกแบบนี้มีจุดเด่นดังต่อไปนี้

  1. การโหลดแบบ Lazy Loading อัจฉริยะ

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

    คำสั่งรูปภาพ Angular จะโหลดรูปภาพที่ไม่สำคัญโดยค่าเริ่มต้นและโหลดเฉพาะรูปภาพที่ทำเครื่องหมายพิเศษว่าเป็น priority เท่านั้น วิธีนี้ช่วยให้รูปภาพส่วนใหญ่แสดงลักษณะการโหลดที่เหมาะสมที่สุด

  2. การจัดลำดับความสำคัญของรูปภาพที่สำคัญ

    การเพิ่มคําแนะนําด้านทรัพยากร (เช่น 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 Loading

  3. การกำหนดค่าที่เพิ่มประสิทธิภาพสำหรับเครื่องมือรูปภาพยอดนิยม

    เราขอแนะนำให้แอปพลิเคชัน Angular ใช้ CDN รูปภาพ ซึ่งมักให้บริการเพิ่มประสิทธิภาพโดยค่าเริ่มต้น

    คำสั่งนี้ส่งเสริมการใช้ CDN รูปภาพโดยการให้ประสบการณ์การใช้งาน (DX) ที่น่าสนใจเป็นพิเศษสำหรับนักพัฒนาแอปในการกำหนดค่าในแอป รองรับ 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 แต่ละรายการ

  4. ข้อผิดพลาดและคำเตือนในตัว

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

    1. รูปภาพที่ไม่มีขนาด: คำสั่งรูปภาพจะแสดงข้อผิดพลาดหากมาร์กอัปรูปภาพไม่ได้กำหนดความกว้างและความสูงที่ชัดเจน รูปภาพที่ไม่ได้ปรับขนาดอาจทำให้เกิดการเปลี่ยนเลย์เอาต์ ซึ่งส่งผลต่อเมตริก Cumulative Layout Shift (CLS) ของหน้าเว็บ แนวทางปฏิบัติแนะนำเพื่อป้องกันปัญหานี้คือ รูปภาพควรมีการระบุแอตทริบิวต์ width และ height

    2. สัดส่วนภาพ: คำสั่งรูปภาพแสดงข้อผิดพลาดเพื่อแจ้งให้นักพัฒนาแอปทราบว่าสัดส่วนภาพ width:height ที่กำหนดไว้ใน HTML ไม่ใกล้เคียงกับสัดส่วนภาพจริงของรูปภาพที่แสดงผล ซึ่งอาจทำให้รูปภาพดูบิดเบี้ยวบนหน้าจอได้ เหตุการณ์นี้อาจเกิดขึ้นได้หาก

      1. คุณกำหนดขนาดที่ไม่ถูกต้อง (ความกว้างหรือความสูง) โดยไม่ได้ตั้งใจ หรือ
      2. หากคุณกำหนดมิติข้อมูลหนึ่งตามเปอร์เซ็นต์ใน CSS แต่ไม่ได้กำหนดอีกมิติข้อมูล (เช่น width: 100% ต้องใช้ height: auto เพื่อให้รูปภาพมีขนาดใหญ่ขึ้นในทั้ง 2 มิติข้อมูล)
    3. รูปภาพที่ใหญ่เกินขนาด: หากรูปภาพไม่ได้กำหนด srcset และรูปภาพภายในมีขนาดใหญ่กว่ารูปภาพที่แสดงผลอย่างมาก คำสั่งจะแสดงคำเตือนที่แนะนำการใช้แอตทริบิวต์ srcset และ sizes

    4. ความหนาแน่นของรูปภาพ: คำสั่งนี้จะแสดงข้อผิดพลาดหากคุณพยายามรวมรูปภาพใน srcset ที่มีความหนาแน่นของพิกเซลมากกว่า 3x โดยทั่วไปเราไม่แนะนำให้ใช้คำอธิบายที่สูงกว่า 2x เนื่องจากผลที่ตามมาจากการบังคับให้อุปกรณ์เคลื่อนที่ความละเอียดสูงดาวน์โหลดรูปภาพขนาดใหญ่โดยไม่ตั้งใจ ยิ่งไปกว่านั้น ดวงตาของมนุษย์ไม่สามารถบอกความแตกต่างได้มากกว่า 2 เท่า

ความท้าทาย

การปรับกลยุทธ์การเพิ่มประสิทธิภาพให้รูปภาพเพื่อให้ทํางานภายในเฟรมเวิร์กฝั่งไคลเอ็นต์ถือเป็นความท้าทายหลักในการออกแบบ NgOptimizedImage ประสบการณ์การแสดงผลเริ่มต้นใน Next.js คือการแสดงผลฝั่งเซิร์ฟเวอร์ (SSR) หรือการสร้างเว็บไซต์แบบคงที่ (SSG) ขณะที่ใน Angular คือการแสดงผลฝั่งไคลเอ็นต์ (CSR) แม้ว่า Angular จะรองรับไลบรารี SSR ซึ่งก็คือ Angular/Universal - แอป Angular ส่วนใหญ่ (ประมาณ 60%) จะใช้ CSR

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

ปัญหาบางส่วนที่พบมีดังนี้

  1. คำแนะนำเกี่ยวกับแหล่งข้อมูลสนับสนุน

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

    การเพิ่มด้วยตนเอง: นักพัฒนาซอฟต์แวร์จะเพิ่มคำแนะนำแหล่งข้อมูล preload ด้วยตนเองได้ยาก Angular ใช้ไฟล์ index.html ที่ใช้ร่วมกัน 1 ไฟล์สำหรับทั้งโครงการหรือทุกเส้นทางในเว็บไซต์ ดังนั้น <head> ของเอกสารจะเหมือนกันในทุกเส้นทาง (อย่างน้อยตามเวลาที่ให้บริการ) การเพิ่มคำแนะนำ preload ลงใน <head> หมายความว่าระบบจะโหลดทรัพยากรไว้ล่วงหน้าสำหรับทุกเส้นทางแม้จะไม่จำเป็นก็ตาม ดังนั้น ไม่แนะนําให้เพิ่มคําแนะนํา preload ด้วยตนเอง

    การเพิ่มอัตโนมัติระหว่างการแสดงภาพ: การใช้เฟรมเวิร์กเพื่อเพิ่มคำแนะนำการโหลดล่วงหน้าไว้ที่ส่วนหัวของเอกสารระหว่างการแสดงภาพในแอป CSR ไม่ช่วยอะไร เนื่องจากการแสดงผลเกิดขึ้นหลังจากดาวน์โหลดและเรียกใช้ JavaScript แล้ว <head> จึงจะแสดงผลช้าเกินไปที่จะไม่มีค่าใดๆ

    สำหรับคำสั่งเวอร์ชันแรก ระบบจะใช้คำแนะนำ preconnect รายการร่วมกับคำแนะนำ fetchpriority รายการเพื่อจัดลำดับความสำคัญรูปภาพแทน preload อย่างไรก็ตาม ขณะนี้ Aurora กำลังทำงานร่วมกับทีม Angular CLI เพื่อเปิดใช้การแทรกคำแนะนำเกี่ยวกับทรัพยากรโดยอัตโนมัติในเวลาบิลด์ โปรดอดใจรอ

  2. การเพิ่มประสิทธิภาพขนาดและรูปแบบรูปภาพในเซิร์ฟเวอร์

    เนื่องจากแอป Angular มักแสดงผลที่ฝั่งไคลเอ็นต์ ระบบไฟล์จึงไม่สามารถบีบอัดรูปภาพในระบบไฟล์ได้เมื่อส่งคำขอและจะแสดงผลตามที่เห็น ด้วยเหตุนี้ เราจึงขอแนะนำให้ใช้ CDN สำหรับรูปภาพเพื่อบีบอัดรูปภาพและแปลงเป็นรูปแบบที่ทันสมัย เช่น WebP หรือ AVIF ตามคำขอ

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

ผลกระทบ

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

Website 1: ใช้องค์ประกอบ <img> แบบเนทีฟที่มีรูปภาพที่แสดงผ่าน Imgix CDN (ที่มีตัวเลือกการกำหนดค่าเริ่มต้น)

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

วันที่ การเปรียบเทียบแถบฟิล์ม: เว็บไซต์ 1 ที่มีแท็กรูปภาพดั้งเดิมเทียบกับเว็บไซต์ 2 ที่มีคำสั่งรูปภาพ Angular

ทีมทำงานร่วมกับพาร์ทเนอร์เพื่อตรวจสอบผลกระทบด้านประสิทธิภาพของคำสั่งเกี่ยวกับรูปภาพที่มีต่อแอปพลิเคชัน 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 (เชิงมุม/สากล) ด้วย

  • การปรับปรุงประสบการณ์ของนักพัฒนาแอป

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

    1. รองรับโหมดเพิ่มเติม (คล้ายกับตัวเลือกเลย์เอาต์รูปภาพใน Next.js "fill") ที่ไม่ต้องกำหนดความกว้าง/ความสูงที่ชัดเจน
    2. การใช้การผสานรวม CLI เพื่อตั้งค่าความกว้างและความสูงโดยอัตโนมัติสำหรับรูปภาพในเครื่องด้วยการกำหนดขนาดจริงของรูปภาพ

บทสรุป

คำสั่งรูปภาพ Angular จะพร้อมใช้งานสำหรับนักพัฒนาแอปเป็นขั้นตอน โดยเริ่มจากเวอร์ชันตัวอย่างของนักพัฒนาแอปใน v14.2.0 ลองใช้ NgOptimizedImage และแสดงความคิดเห็นดูสิ

ขอขอบคุณ Katie Hempenius และ Alex Castle สำหรับการมีส่วนร่วม