Vào tháng 5 năm 2022, nhóm Aurora và Angular thông báo rằng họ sẽ cộng tác để triển khai chỉ thị về hình ảnh cho Angular. Chỉ thị này gần đây đã được phát hành cho bản dùng thử cho nhà phát triển dưới dạng một phần của Angular phiên bản 14.2. Bài đăng này nói về cách lệnh hình ảnh mới (NgOptimizedImage
) hỗ trợ hoạt động tối ưu hoá hình ảnh trong Angular.
Thông tin khái quát
Hình ảnh là một thành phần phổ biến và quan trọng trong trải nghiệm người dùng web, với 99,9% số trang web tạo yêu cầu liên quan đến một hoặc nhiều hình ảnh. Hình ảnh cũng là yếu tố quan trọng nhất ảnh hưởng đến trọng lượng trang, chiếm trung bình là 982 kilobyte trên mỗi trang.
Do số lượng và kích thước ngày càng tăng, hình ảnh có thể cản trở hiệu suất của trang web và ảnh hưởng đến các chỉ số trong Chỉ số quan trọng chính của trang web. Đối với 79,4% số trang dành cho máy tính, hình ảnh là phần tử Nội dung lớn nhất hiển thị (LCP) vào năm 2021. Do đó, việc theo đuổi hình ảnh tối ưu hoá đã trở thành nỗ lực không ngừng của nhiều người trong chúng ta.
Đội ngũ Aurora tin tưởng vào việc tận dụng sức mạnh của các khung làm việc để cung cấp các giải pháp tích hợp cho những thách thức thường gặp của nhà phát triển. Bước đột phá đầu tiên của họ vào không gian tối ưu hoá hình ảnh là thành phần hình ảnh Next.js. Họ coi thành phần này là nơi thử nghiệm xem việc cải thiện trải nghiệm tối ưu hoá hình ảnh (DX) của nhà phát triển có thể giúp tăng hiệu suất cho nhiều ứng dụng sử dụng khung hơn hay không.
Nhóm kết quả đầu tiên từ người dùng Next.js Leboncoin rất đáng khích lệ. Leboncoin đã cải thiện đáng kể LCP (từ 2,4 giây lên 1,7 giây) sau khi họ bắt đầu sử dụng next/image
. Việc sử dụng next/image
tiếp theo trong cộng đồng đã góp phần làm tăng số nguồn gốc Next.js đáp ứng ngưỡng LCP. Chẳng bao lâu nữa, đã có yêu cầu cho các tính năng tương tự trong các khung khác, một trong số đó là Góc.
Do đó, Aurora đã tham khảo ý kiến của Angular và Nuxt để tạo nguyên mẫu cho các thành phần hình ảnh cho những khung này. Thành phần hình ảnh Nuxt đã được phát hành vào năm ngoái. Hiện tại, lệnh hình ảnh Angular (NgOptimizedImage
) đã được phát hành để đưa các chế độ tối ưu hoá hình ảnh mặc định sang Angular.
Cơ hội
Angular là một trong những khung JavaScript hàng đầu được các nhà phát triển sử dụng hiện nay. API này được hơn 50 nghìn nguồn gốc thu thập thông tin do HTTPArchive thu thập trên thiết bị di động và có gần 3 triệu lượt tải xuống hằng tuần trên kháng nghị
![LCP cho các trang web Angular trong một năm qua.](https://developer.chrome.com/static/blog/angular-image-directive/image/lcp-angular-websites-th-313c9b6e8afd2.png?authuser=5&hl=vi)
Nhìn vào điểm số Core Web Vitals, tỷ lệ phần trăm nguồn gốc Angular đáp ứng ngưỡng LCP "tốt" vẫn cần được cải thiện. Chỉ 18,74% trang web Angular có LCP tốt trên thiết bị di động vào tháng 6 năm 2022. Vì hình ảnh là phần tử LCP của hơn 70% số trang web trên thiết bị di động và máy tính, nên hình ảnh LCP chưa được tối ưu hoá có thể là một trong những nguyên nhân chính khiến LCP kém hơn trên trang web Angular.
Lệnh hình ảnh Angular được thiết kế để giúp cải thiện những số liệu này.
MVP cho lệnh NgOptimizedImage
MVP của lệnh hình ảnh Angular được xây dựng dựa trên những bài học từ các thành phần hình ảnh mà Aurora đã xây dựng cho đến nay trong khi điều chỉnh thiết kế cho phù hợp với trải nghiệm kết xuất phía máy khách của Angular. Nhiều vấn đề khi tối ưu hoá hình ảnh chuẩn đã được giải quyết bằng một trong hai cách sau:
- Cung cấp giá trị mặc định mạnh.
- Gửi lỗi hoặc cảnh báo để đảm bảo tuân thủ các phương pháp hay nhất.
Sau đây là những điểm nổi bật của thiết kế này:
Tải từng phần thông minh
Hình ảnh không hiển thị với người dùng khi tải trang (ví dụ: hình ảnh dưới màn hình đầu tiên hoặc hình ảnh băng chuyền ẩn) tốt nhất nên được tải từng phần. Tính năng tải từng phần giúp giải phóng các tài nguyên của trình duyệt để tải văn bản, nội dung nghe nhìn hoặc tập lệnh quan trọng khác. Hầu hết hình ảnh đều không quan trọng và nên được tải từng phần, nhưng chỉ có 7,8% số trang sử dụng tính năng tải từng phần gốc vào năm 2021.
Theo mặc định, lệnh hình ảnh Angular tải từng phần các hình ảnh không quan trọng và chỉ tải nhanh các hình ảnh được đánh dấu đặc biệt là
priority
. Điều này đảm bảo rằng hầu hết hình ảnh đều thể hiện hành vi tải tối ưu.Sắp xếp thứ tự ưu tiên các hình ảnh quan trọng
Thêm gợi ý về tài nguyên (ví dụ:
preload
hoặcpreconnect
) để ưu tiên tải các hình ảnh quan trọng là một phương pháp hay nhất được đề xuất. Tuy nhiên, hầu hết các ứng dụng đều không dùng đến phần mở rộng này. Theo Niên giám web năm 2021, chỉ 12,7% trang dành cho thiết bị di động sử dụng gợi ý kết nối trước và chỉ 22,1% trang dành cho thiết bị di động sử dụng gợi ý tải trước.Lệnh hình ảnh hoạt động trên hai mặt trước khi các hình ảnh được đánh dấu là ưu tiên.
- Thao tác này sẽ đặt tìm nạp ưu tiên hình ảnh thành
"high"
để trình duyệt biết rằng nên tải hình ảnh xuống với mức độ ưu tiên cao. - Ở chế độ phát triển, quy trình kiểm tra thời gian chạy sẽ xác nhận rằng gợi ý tài nguyên
preconnect
đã được đưa vào tương ứng với nguồn gốc của hình ảnh.
Ở chế độ phát triển, lệnh này cũng dùng API PerformanceObserver để xác minh rằng hình ảnh LCP đã được đánh dấu
priority
là dự kiến. Nếu thuộc tính này không được đánh dấu làpriority
, sẽ xảy ra lỗi, hướng dẫn nhà phát triển thêm thuộc tínhpriority
vào hình ảnh LCP.Cuối cùng, sự kết hợp giữa tự động hoá và tuân thủ này đảm bảo rằng hình ảnh LCP có gợi ý
preconnect
, giá trị thuộc tínhfetchpriority
làhigh
và không tải từng phần.- Thao tác này sẽ đặt tìm nạp ưu tiên hình ảnh thành
Cấu hình được tối ưu hoá cho công cụ hình ảnh phổ biến
Các ứng dụng Angular nên sử dụng CDN hình ảnh, thường cung cấp dịch vụ tối ưu hoá theo mặc định.
Chỉ thị này khuyến khích nhà phát triển sử dụng CDN hình ảnh bằng cách mang đến trải nghiệm đặc biệt hấp dẫn cho nhà phát triển (DX) để định cấu hình các CDN trong ứng dụng. Lệnh này hỗ trợ một API trình tải cho phép bạn xác định nhà cung cấp CDN và URL cơ sở trong cấu hình của mình. Sau khi định cấu hình, bạn chỉ phải xác định tên tài sản trong mã đánh dấu. Ví dụ:
// in module providers: provideImgixLoader('https://mysite.net/assets/') // in markup <img ngSrc="image.png" > <img ngSrc="image2.png" >
Điều này tương đương với việc thêm các thẻ hình ảnh sau đây và giảm bớt công sức mà nhà phát triển thẻ đánh dấu phải đưa vào cho mỗi hình ảnh.
<img src="https://mysite.net/assets/image.png"> <img src="https://mysite.net/assets/image2.png">
Lệnh hình ảnh cung cấp các trình tải tích hợp sẵn với cấu hình tối ưu cho các CDN hình ảnh phổ biến nhất. Những trình tải này sẽ tự động định dạng URL hình ảnh để đảm bảo sử dụng các chế độ cài đặt nén và định dạng hình ảnh đề xuất cho mỗi CDN.
Lỗi và cảnh báo tích hợp sẵn
Ngoài các tính năng tối ưu hoá tích hợp sẵn ở trên, lệnh này cũng có các bước kiểm tra tích hợp để đảm bảo rằng nhà phát triển đã tuân theo các phương pháp hay nhất được đề xuất về mã đánh dấu hình ảnh. Lệnh hình ảnh thực hiện các bước kiểm tra sau đây.
Hình ảnh chưa có kích thước: Lệnh hình ảnh sẽ báo lỗi nếu mã đánh dấu hình ảnh không xác định chiều rộng và chiều cao rõ ràng. Hình ảnh chưa định kích thước có thể gây thay đổi bố cục, ảnh hưởng đến chỉ số Điểm thay đổi bố cục (CLS) của trang. Phương pháp hay nhất được đề xuất để ngăn chặn điều này là hình ảnh phải chỉ định các thuộc tính
width
vàheight
.Tỷ lệ khung hình: Lệnh hình ảnh sẽ báo lỗi để cho nhà phát triển biết liệu tỷ lệ khung hình
width
:height
được xác định trong HTML có không gần với tỷ lệ khung hình thực tế của hình ảnh được kết xuất hay không. Điều này có thể khiến hình ảnh bị méo trên màn hình. Điều này có thể xảy ra nếu- Bạn đã xác định sai kích thước (chiều rộng hoặc chiều cao) do nhầm lẫn hoặc
- Nếu bạn đã xác định một kích thước theo tỷ lệ phần trăm trong CSS nhưng không xác định kích thước còn lại (ví dụ:
width: 100%
cầnheight: auto
để đảm bảo hình ảnh phát triển ở cả hai chiều).
Hình ảnh quá khổ: Nếu hình ảnh không xác định
srcset
và hình ảnh nội tại lớn hơn đáng kể so với hình ảnh kết xuất, thì lệnh sẽ hiển thị cảnh báo đề xuất việc sử dụng các thuộc tínhsrcset
vàsizes
.Mật độ hình ảnh: Lệnh sẽ báo lỗi nếu bạn cố gắng đưa một hình ảnh vào
srcset
có mật độ pixel lớn hơn3x
. Bạn thường không nên dùng những đoạn mô tả cao hơn2x
vì việc này có hệ quả ngoài ý muốn khi buộc thiết bị di động có độ phân giải cao phải tải những hình ảnh cực lớn xuống. Hơn nữa, mắt người thực sự không thể phân biệt được nhiều khác biệt lớn hơn 2 lần.
Thử thách
Việc điều chỉnh các chiến lược tối ưu hoá hình ảnh cho phù hợp với hoạt động trong khung phía máy khách là một thách thức chính khi thiết kế NgOptimizedImage
. Trải nghiệm hiển thị mặc định trên Next.js là Kết xuất phía máy chủ (SSR) hoặc Tạo trang web tĩnh (SSG), trong khi trên Angular là Kết xuất phía máy khách (CSR). Mặc dù Angular hỗ trợ thư viện SSR – góc/phổ thông – nhưng hầu hết ứng dụng Angular (~60%) đều sử dụng CSR.
Lệnh hình ảnh được xây dựng hoàn toàn cho CSR để phù hợp với trường hợp sử dụng thông thường trong các ứng dụng Angular. Điều này đặt ra các hạn chế bổ sung và đội ngũ của chúng tôi phải suy nghĩ lại về cách xây dựng các biện pháp tối ưu hoá cụ thể cho các ứng dụng CSR.
Bạn gặp phải một số thách thức như sau:
Hỗ trợ gợi ý về tài nguyên
Tải trước các thành phần quan trọng giúp trình duyệt phát hiện các thành phần đó sớm hơn. Tuy nhiên, việc đưa các gợi ý tài nguyên vào ứng dụng Angular khá phức tạp vì:
Thêm thủ công: Nhà phát triển khó có thể thêm gợi ý tài nguyên
preload
theo cách thủ công. Angular sử dụng một tệpindex.html dùng chung cho toàn bộ dự án hoặc cho tất cả các tuyến trong trang web. Do đó,<head>
của tài liệu là giống nhau ở mọi tuyến (ít nhất là tại thời gian cung cấp). Việc thêm bất kỳ gợi ýpreload
nào vào<head>
có nghĩa là tài nguyên sẽ được tải trước cho tất cả các tuyến, ngay cả khi không bắt buộc. Do đó, bạn không nên thêm gợi ýpreload
theo cách thủ công.Tự động thêm trong quá trình kết xuất: Việc sử dụng khung để thêm gợi ý tải trước vào phần đầu tài liệu trong quá trình kết xuất trong ứng dụng CSR không có tác dụng. Vì hiển thị xảy ra sau khi JavaScript được tải xuống và thực thi, nên
<head>
sẽ kết xuất quá muộn để có bất kỳ giá trị nào.Đối với phiên bản đầu tiên của lệnh này, tổ hợp gợi ý
preconnect
và gợi ýfetchpriority
sẽ phân phát để ưu tiên hình ảnh thay vìpreload
. Tuy nhiên, Aurora hiện đang làm việc với nhóm Angular CLI để bật tính năng tự động chèn các gợi ý về tài nguyên trong thời gian xây dựng. Hãy chú ý theo dõi nhé!Tối ưu hoá kích thước và định dạng hình ảnh trên máy chủ
Vì các ứng dụng Angular thường được hiển thị phía máy khách, nên hình ảnh trên hệ thống tệp không thể nén được tại thời điểm yêu cầu và được phân phát nguyên trạng. Vì lý do này, bạn nên sử dụng CDN hình ảnh để nén hình ảnh và chuyển đổi chúng thành các định dạng hiện đại như WebP hoặc AVIF theo yêu cầu.
Mặc dù lệnh này không thực thi việc sử dụng CDN của hình ảnh, nhưng bạn nên sử dụng cùng với lệnh và các trình tải tích hợp sẵn giúp đảm bảo dùng đúng tuỳ chọn cấu hình.
Mức độ tác động
Bản minh hoạ sau đây minh hoạ sự khác biệt mà lệnh hình ảnh Angular có thể tạo ra đối với hiệu suất của hình ảnh. Công cụ này so sánh hai trang web:
Trang web thứ nhất: Sử dụng các phần tử <img>
gốc có hình ảnh phân phát qua CDN của Imgix (với các lựa chọn cấu hình mặc định).
Trang web 2: Sử dụng lệnh hình ảnh cho tất cả các hình ảnh. Ngoài ra, chỉ số này còn có các hoạt động tối ưu hoá được đề xuất trực tiếp khi có cảnh báo hoặc lỗi do lệnh tạo ra.
![So sánh cuộn phim: Trang web 1 có thẻ hình ảnh gốc so với Trang web 2 có lệnh hình ảnh Angular.](https://developer.chrome.com/static/blog/angular-image-directive/image/filmstrip-comparison-web-c03e5b7f51387.png?authuser=5&hl=vi)
Nhóm này đã làm việc với các đối tác để xác thực tác động của lệnh hình ảnh đối với hiệu suất của các ứng dụng Angular thực tế dành cho doanh nghiệp.
Một trong những đối tác này là Land's End. Dự kiến trang web của họ sẽ là một trường hợp thử nghiệm tốt cho những kết quả mà các ứng dụng thực tế có thể thấy.
Hoạt động kiểm thử Lighthouse trong phòng thí nghiệm đã được thực hiện trên môi trường đảm bảo chất lượng của họ trước và sau khi sử dụng lệnh hình ảnh. Trên máy tính, LCP trung bình của họ giảm từ 12 giây xuống còn 3 giây, tức là cải thiện 75% LCP. Trên thiết bị di động, LCP trung bình giảm từ 20,2 giây xuống 12 giây (cải thiện 40,6%).
Lộ trình tương lai
Đây chỉ là phần đầu tiên của thiết kế cho lệnh hình ảnh Angular. Chúng tôi dự định cung cấp nhiều tính năng khác cho các phiên bản trong tương lai, bao gồm:
Hỗ trợ tốt hơn cho hình ảnh thích ứng:
NgOptimizedImage
hiện hỗ trợ sử dụngsrcset
, nhưng bạn phải cung cấp các thuộc tínhsrcset
vàsizes
cho từng hình ảnh theo cách thủ công. Trong tương lai, lệnh này có thể tự động tạo các thuộc tínhsrcset
vàsizes
.Tự động chèn gợi ý tài nguyên
Bạn có thể tích hợp với Angular CLI để tạo kết nối trước và tải trước thẻ cho các hình ảnh LCP quan trọng.
Hỗ trợ Angular SSR
Phiên bản MVP được thiết kế dựa trên các quy tắc ràng buộc của Angular CSR, nhưng bạn cũng cần tìm hiểu các giải pháp tối ưu hoá hình ảnh cho Angular SSR (góc/phổ thông).
Các điểm cải tiến về trải nghiệm cho nhà phát triển
NgOptimizedImage
yêu cầu chỉ định các thuộc tínhwidth
vàheight
cho mỗi hình ảnh. Tuy nhiên, đối với một số nhà phát triển, việc chỉ định giá trị này cho từng hình ảnh có thể khiến một số nhà phát triển cảm thấy khó chịu. Có thể cải thiện trải nghiệm của nhà phát triển trong lần lặp tiếp theo như sau:- Hỗ trợ chế độ bổ sung (tương tự như tuỳ chọn bố cục hình ảnh "
fill
" trong Next.js) không yêu cầu xác định chiều rộng/chiều cao rõ ràng. - Sử dụng tính năng tích hợp CLI để tự động đặt chiều rộng và chiều cao cho hình ảnh cục bộ bằng cách xác định kích thước thực tế của hình ảnh.
- Hỗ trợ chế độ bổ sung (tương tự như tuỳ chọn bố cục hình ảnh "
Kết luận
Chỉ thị hình ảnh Angular sẽ được cung cấp cho nhà phát triển theo từng giai đoạn, bắt đầu từ phiên bản xem trước dành cho nhà phát triển ở phiên bản 14.2.0. Hãy dùng thử NgOptimizedImage
và để lại ý kiến phản hồi!
Xin đặc biệt cảm ơn Katie Hempenius và Alex Castle vì những đóng góp của họ.