Tối ưu hoá việc tải tập lệnh của bên thứ ba trong Next.js

Tìm hiểu tầm nhìn đằng sau thành phần Tập lệnh của Next.js. Thành phần này cung cấp một giải pháp tích hợp để tối ưu hoá việc tải tập lệnh của bên thứ ba.

Leena Sohoni
Leena Sohoni

Khoảng 45% yêu cầu từ các trang web phân phát trên thiết bị di động và máy tính là yêu cầu của bên thứ ba, trong đó 33% là tập lệnh. Kích thước, độ trễ và quá trình tải của tập lệnh bên thứ ba có thể ảnh hưởng đáng kể đến hiệu suất của trang web. Thành phần Tập lệnh Next.js đi kèm với các phương pháp hay nhất và mặc định để giúp nhà phát triển giới thiệu tập lệnh của bên thứ ba trong ứng dụng của họ, đồng thời giải quyết các vấn đề về hiệu suất tiềm ẩn ngay từ đầu.

Tập lệnh của bên thứ ba và tác động của các tập lệnh đó đến hiệu suất

Tập lệnh của bên thứ ba cho phép nhà phát triển web tận dụng các giải pháp hiện có để triển khai các tính năng phổ biến và giảm thời gian phát triển. Tuy nhiên, những người tạo ra các tập lệnh này thường không có động lực để xem xét tác động của hiệu suất đối với trang web sử dụng. Các tập lệnh này cũng là hộp đen đối với các nhà phát triển sử dụng chúng.

Tập lệnh chiếm một lượng đáng kể byte của bên thứ ba mà các trang web tải xuống theo nhiều danh mục yêu cầu của bên thứ ba. Theo mặc định, trình duyệt ưu tiên các tập lệnh dựa trên vị trí của các tập lệnh đó trong tài liệu. Điều này có thể làm chậm quá trình khám phá hoặc thực thi các tập lệnh quan trọng đối với trải nghiệm người dùng.

Bạn nên tải sớm các thư viện bên thứ ba cần thiết cho bố cục để hiển thị trang. Bạn nên trì hoãn các bên thứ ba không bắt buộc cho quá trình kết xuất ban đầu để các bên này không chặn quá trình xử lý khác trên luồng chính. Lighthouse có hai quy trình kiểm tra để gắn cờ các tập lệnh chặn kết xuất hoặc chặn luồng chính.

Bài kiểm tra Lighthouse để Loại bỏ các tài nguyên chặn hiển thị và Giảm thiểu mức sử dụng của bên thứ ba

Điều quan trọng là bạn phải xem xét trình tự tải tài nguyên của trang để các tài nguyên quan trọng không bị trì hoãn và các tài nguyên không quan trọng không chặn các tài nguyên quan trọng.

Mặc dù có các phương pháp hay nhất để giảm tác động của bên thứ ba, nhưng không phải ai cũng biết cách triển khai các phương pháp đó cho mọi bên thứ ba mà họ sử dụng. Việc này có thể phức tạp vì:

  • Trung bình, các trang web sử dụng 21 đến 23 bên thứ ba (bao gồm cả tập lệnh) trên thiết bị di động và máy tính. Cách sử dụng và đề xuất có thể khác nhau tuỳ theo từng tính năng.
  • Việc triển khai nhiều bên thứ ba có thể khác nhau tuỳ thuộc vào việc bạn có sử dụng một khung hoặc thư viện giao diện người dùng cụ thể hay không.
  • Các thư viện mới hơn của bên thứ ba thường xuyên được giới thiệu.
  • Các yêu cầu kinh doanh khác nhau liên quan đến cùng một bên thứ ba khiến nhà phát triển khó có thể chuẩn hoá việc sử dụng.

Trọng tâm của Aurora về tập lệnh của bên thứ ba

Một phần trong hoạt động cộng tác của Aurora với các công cụ và khung web nguồn mở là cung cấp các công cụ mặc định mạnh mẽ và có định hướng để giúp nhà phát triển cải thiện các khía cạnh của trải nghiệm người dùng như hiệu suất, khả năng hỗ trợ tiếp cận, bảo mật và khả năng sẵn sàng cho thiết bị di động. Trong năm 2021, chúng tôi tập trung vào việc giúp các ngăn xếp khung cải thiện trải nghiệm người dùng và các chỉ số Chỉ số quan trọng chính của trang web.

Một trong những bước quan trọng nhất để đạt được mục tiêu cải thiện hiệu suất khung là nghiên cứu trình tự tải lý tưởng của các tập lệnh bên thứ ba trong Next.js. Các khung như Next.js được định vị riêng để cung cấp các tính năng và giá trị mặc định hữu ích giúp nhà phát triển tải tài nguyên một cách hiệu quả, bao gồm cả tài nguyên của bên thứ ba. Chúng tôi đã nghiên cứu kỹ lưỡng dữ liệu của Bản lưu trữ HTTP và Lighthouse để tìm ra những bên thứ ba chặn việc hiển thị nhiều nhất trên các khung khác nhau.

Để giải quyết vấn đề luồng chính chặn các tập lệnh của bên thứ ba được sử dụng trong ứng dụng, chúng tôi đã tạo Thành phần tập lệnh. Thành phần này đóng gói các tính năng sắp xếp để cung cấp cho nhà phát triển các chế độ kiểm soát tốt hơn cho việc tải tập lệnh của bên thứ ba.

Sắp xếp các tập lệnh của bên thứ ba mà không có thành phần khung

Hướng dẫn hiện có để giảm tác động của các tập lệnh chặn kết xuất cung cấp các phương thức sau để tải và sắp xếp hiệu quả các tập lệnh của bên thứ ba:

  1. Sử dụng thuộc tính async hoặc defer với thẻ <script> để yêu cầu trình duyệt tải các tập lệnh không quan trọng của bên thứ ba mà không chặn trình phân tích cú pháp tài liệu. Các tập lệnh không bắt buộc để tải trang ban đầu hoặc tương tác đầu tiên của người dùng có thể được coi là không quan trọng.

       <script src="https://example.com/script1.js" defer></script>
       <script src="https://example.com/script2.js" async></script>
    
  2. Thiết lập các kết nối sớm tới những nguồn gốc bắt buộc bằng cách sử dụng tính năng kết nối trước và tìm nạp DNS trước. Điều này cho phép các tập lệnh quan trọng bắt đầu tải xuống sớm hơn.

       <head>
           <link rel="preconnect" href="http://PreconnThis.com">
           <link rel="dns-prefetch" href="http://PrefetchThis.com">
       </head>
    
  3. Tải lười các tài nguyên và nội dung nhúng của bên thứ ba sau khi nội dung trang chính tải xong hoặc khi người dùng cuộn xuống phần trang có chứa các tài nguyên và nội dung nhúng đó.

Thành phần Tập lệnh Next.js

Thành phần tập lệnh Next.js triển khai các phương thức trên để sắp xếp các tập lệnh và cung cấp một mẫu để nhà phát triển xác định chiến lược tải. Sau khi bạn chỉ định chiến lược phù hợp, chiến lược đó sẽ tải một cách tối ưu mà không chặn các tài nguyên quan trọng khác.

Thành phần Tập lệnh được xây dựng dựa trên thẻ <script> HTML và cung cấp tuỳ chọn để đặt mức độ ưu tiên tải cho các tập lệnh của bên thứ ba bằng cách sử dụng thuộc tính chiến lược.

// 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" />

Thuộc tính chiến lược có thể nhận 3 giá trị.

  1. beforeInteractive: Bạn có thể sử dụng tuỳ chọn này cho các tập lệnh quan trọng cần thực thi trước khi trang có thể tương tác. Next.js đảm bảo rằng các tập lệnh như vậy được chèn vào HTML ban đầu trên máy chủ và được thực thi trước các tập lệnh JavaScript tự đóng gói khác. Các thành phần quản lý sự đồng ý, tập lệnh phát hiện bot hoặc thư viện trợ giúp cần thiết để hiển thị nội dung quan trọng là những ứng cử viên phù hợp cho chiến lược này.

  2. afterInteractive: Đây là chiến lược mặc định được áp dụng và tương đương với việc tải tập lệnh có thuộc tính trì hoãn. Bạn nên sử dụng thuộc tính này cho các tập lệnh mà trình duyệt có thể chạy sau khi trang có thể tương tác, ví dụ: tập lệnh phân tích. Next.js chèn các tập lệnh này ở phía máy khách và các tập lệnh này sẽ chạy sau khi trang được làm mới. Do đó, trừ phi có quy định khác, tất cả tập lệnh của bên thứ ba được xác định bằng thành phần Tập lệnh đều được Next.js trì hoãn, nhờ đó cung cấp một giá trị mặc định mạnh mẽ.

  3. lazyOnload: Bạn có thể sử dụng tuỳ chọn này để tải lười các tập lệnh có mức độ ưu tiên thấp khi trình duyệt không hoạt động. Bạn không cần phải cung cấp chức năng do các tập lệnh đó cung cấp ngay sau khi trang trở nên tương tác, ví dụ: trình bổ trợ trò chuyện hoặc mạng xã hội.

Nhà phát triển có thể cho Next.js biết cách ứng dụng của họ sử dụng tập lệnh bằng cách chỉ định chiến lược. Điều này cho phép khung áp dụng các phương pháp tối ưu hoá và phương pháp hay nhất để tải tập lệnh trong khi vẫn đảm bảo trình tự tải tốt nhất.

Khi sử dụng thành phần Tập lệnh, nhà phát triển có thể đặt tập lệnh của bên thứ ba ở bất kỳ đâu trong ứng dụng đối với các bên thứ ba tải muộn và ở cấp tài liệu đối với các tập lệnh quan trọng. Điều này có nghĩa là thành phần Tập lệnh có thể được đặt cùng với thành phần sử dụng tập lệnh. Sau khi được bổ sung, tập lệnh sẽ được chèn vào đầu tài liệu được kết xuất ban đầu hoặc ở cuối phần nội dung, tuỳ thuộc vào chiến lược được sử dụng.

Đo lường tác động

Chúng tôi đã sử dụng các mẫu cho ứng dụng thương mạiblog khởi động của Next.js để tạo hai ứng dụng minh hoạ giúp đo lường tác động của việc đưa các tập lệnh của bên thứ ba vào. Các bên thứ ba thường dùng cho Trình quản lý thẻ của Google và các tính năng nhúng mạng xã hội ban đầu được đưa trực tiếp vào các trang của các ứng dụng này, sau đó được đưa vào thông qua thành phần Tập lệnh. Sau đó, chúng tôi so sánh hiệu suất của các trang này trên WebPageTest.

Tập lệnh của bên thứ ba trong ứng dụng thương mại Next.js

Các tập lệnh của bên thứ ba đã được thêm vào mẫu ứng dụng thương mại cho bản minh hoạ như bên dưới.

Trước Sau
Trình quản lý thẻ của Google với tính năng không đồng bộ Thành phần tập lệnh có chiến lược = afterInteractive cho cả hai tập lệnh
Nút Theo dõi trên Twitter không có tính năng không đồng bộ hoặc trì hoãn
Cấu hình tập lệnh và thành phần tập lệnh cho bản minh hoạ 1 với 2 tập lệnh.

Bản so sánh sau đây cho thấy tiến trình trực quan cho cả hai phiên bản của bộ khởi động thương mại Next.js. Như đã thấy, LCP xảy ra sớm hơn gần 1 giây khi thành phần Tập lệnh được bật bằng chiến lược tải phù hợp.

So sánh dải phim cho thấy sự cải thiện về LCP

Tập lệnh của bên thứ ba trong blog Next.js

Các tập lệnh của bên thứ ba đã được thêm vào ứng dụng blog minh hoạ như bên dưới.

Trước Sau
Trình quản lý thẻ của Google với tính năng không đồng bộ Thành phần tập lệnh có chiến lược = lazyonload cho mỗi trong số 4 tập lệnh
Nút Theo dõi trên Twitter với tính năng không đồng bộ
Nút Đăng ký trên YouTube không có tính năng không đồng bộ hoặc trì hoãn
Nút Theo dõi trên LinkedIn không có tính năng không đồng bộ hoặc trì hoãn
Cấu hình Tập lệnh và Thành phần tập lệnh cho bản minh hoạ 2 với 4 tập lệnh.
Video cho thấy tiến trình tải trang chỉ mục có và không có thành phần Tập lệnh. FCP cải thiện 0,5 giây với thành phần Tập lệnh.

Như trong video, First Contentful Paint (FCP) (Hiển thị nội dung đầu tiên) xảy ra ở 0,9 giây trên trang không có thành phần Tập lệnh và 0,4 giây trên trang có thành phần Tập lệnh.

Bước tiếp theo cho thành phần Tập lệnh

Mặc dù các tuỳ chọn chiến lược cho afterInteractivelazyOnload cung cấp khả năng kiểm soát đáng kể đối với các tập lệnh chặn kết xuất, nhưng chúng tôi cũng đang tìm hiểu các tuỳ chọn khác có thể tăng cường tiện ích của thành phần Tập lệnh.

Sử dụng worker web

Bạn có thể sử dụng trình chạy web để chạy các tập lệnh độc lập trên các luồng trong nền. Điều này có thể giải phóng luồng chính để xử lý các tác vụ trên giao diện người dùng và cải thiện hiệu suất. Worker trên web phù hợp nhất để giảm tải quá trình xử lý JavaScript, thay vì công việc trên giao diện người dùng, khỏi luồng chính. Các tập lệnh dùng để hỗ trợ khách hàng hoặc tiếp thị, thường không tương tác với giao diện người dùng, có thể là ứng cử viên phù hợp để thực thi trên luồng trong nền. Bạn có thể sử dụng một thư viện nhẹ của bên thứ ba – PartyTown – để tách các tập lệnh đó thành một worker web.

Với cách triển khai hiện tại của thành phần tập lệnh Next.js, bạn nên trì hoãn các tập lệnh này trên luồng chính bằng cách đặt chiến lược thành afterInteractive hoặc lazyOnload. Trong tương lai, chúng tôi đề xuất giới thiệu một tuỳ chọn chiến lược mới, 'worker', cho phép Next.js sử dụng PartyTown hoặc một giải pháp tuỳ chỉnh để chạy tập lệnh trên worker web. Chúng tôi hoan nghênh ý kiến phản hồi của các nhà phát triển về RFC này.

Giảm thiểu CLS

Nội dung nhúng của bên thứ ba như quảng cáo, video hoặc nguồn cấp dữ liệu mạng xã hội có thể gây ra sự thay đổi bố cục khi tải lười. Điều này ảnh hưởng đến trải nghiệm người dùng và chỉ số Mức thay đổi bố cục tích luỹ (CLS) của trang. Bạn có thể giảm thiểu CLS bằng cách chỉ định kích thước của vùng chứa nơi nội dung nhúng sẽ tải.

Bạn có thể dùng thành phần Tập lệnh để tải các nội dung nhúng có thể gây ra sự thay đổi bố cục. Chúng tôi đang cân nhắc việc mở rộng tính năng này để cung cấp các tuỳ chọn cấu hình giúp giảm CLS. Bạn có thể cung cấp tính năng này trong chính thành phần Tập lệnh hoặc dưới dạng thành phần đồng hành.

Thành phần trình bao bọc

Cú pháp và chiến lược tải để đưa các tập lệnh phổ biến của bên thứ ba như Google Analytics hoặc Trình quản lý thẻ của Google (GTM) vào thường được cố định. Bạn có thể đóng gói thêm các thành phần này trong các thành phần trình bao bọc riêng lẻ cho từng loại tập lệnh. Nhà phát triển chỉ có thể sử dụng một nhóm thuộc tính tối thiểu dành riêng cho ứng dụng (chẳng hạn như mã theo dõi). Thành phần trình bao bọc sẽ giúp nhà phát triển bằng cách:

  1. Giúp họ dễ dàng thêm các thẻ tập lệnh phổ biến.
  2. Đảm bảo rằng khung sử dụng chiến lược tối ưu nhất.

Kết luận

Các tập lệnh của bên thứ ba thường được tạo để đưa các tính năng cụ thể vào trang web sử dụng. Để giảm tác động của các tập lệnh không quan trọng, bạn nên trì hoãn các tập lệnh đó – theo mặc định, thành phần Tập lệnh Next.js sẽ thực hiện việc này. Nhà phát triển có thể yên tâm rằng các tập lệnh được đưa vào sẽ không làm chậm chức năng quan trọng, trừ phi họ áp dụng chiến lược beforeInteractive một cách rõ ràng. Giống như thành phần Tập lệnh Next.js, nhà phát triển khung cũng có thể cân nhắc việc xây dựng các tính năng này trong các khung khác. Chúng tôi đang tích cực tìm hiểu để ra mắt một thành phần tương tự với nhóm Nuxt.js. Dựa trên ý kiến phản hồi, chúng tôi cũng hy vọng có thể nâng cao Thành phần tập lệnh hơn nữa để đáp ứng các trường hợp sử dụng khác.

Thư cảm ơn

Cảm ơn Kara Erickson, Janicklas Ralph, Katie Hempenius, Philip Walton, Jeremy WagnerAddy Osmani đã góp ý cho bài đăng này.