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 giải pháp tích hợp sẵn để 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 được 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à việc tải tập lệnh của 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 tích hợp để 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 tập lệnh này đến hiệu suất

Tập lệnh của bên thứ ba cho phép các 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, người tạo ra các tập lệnh này thường không có bất kỳ động lực nào để xem xét tác động của hiệu suất đến trang web đang sử dụng. Những tập lệnh này cũng là một hộp đen cho các nhà phát triển sử dụng chúng.

Các tập lệnh chiếm một số lượng đáng kể byte của bên thứ ba được các trang web tải xuống từ nhiều danh mục yêu cầu của bên thứ ba. Theo mặc định, trình duyệt sẽ ư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ể trì hoãn việc 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 thư viện của bên thứ ba cần thiết cho bố cục để hiển thị trang. Các bên thứ ba không cần thiết cho hoạt động kết xuất ban đầu phải được trì hoãn để không chặn các quá trình xử lý khác trên luồng chính. Lighthouse có hai bài kiểm tra để gắn cờ các tập lệnh chặn hiển thị hoặc chặn luồng chính.

Kiểm tra bằng 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à phải xem xét trình tự tải tài nguyên trên trang của bạn để 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 các 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 này 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 khác nhau (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ỳ từng trường hợp.
  • Việc triển khai nhiều bên thứ ba có thể khác nhau tuỳ thuộc vào việc sử dụng một khung hay thư viện giao diện người dùng cụ thể.
  • Các thư viện mới hơn của bên thứ ba thường xuyên được giới thiệu.
  • Việc thay đổi các yêu cầu kinh doanh liên quan đến cùng một bên thứ ba khiến nhà phát triển gặp khó khăn trong việc chuẩn hoá việc sử dụng.

Aurora tập trung vào các tập lệnh của bên thứ ba

Một phần trong cộng tác của Aurora với các công cụ và khung ứng dụng nguồn mở là cung cấp các công cụ mạnh mẽ về giá trị mặc định và công cụ cố định, 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, chẳng hạn như hiệu suất, khả năng hỗ trợ tiếp cận, tính bảo mật và mức độ 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à việc 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ị duy nhất để cung cấp các tính năng và mặc định hữu ích giúp nhà phát triển tải tài nguyên hiệu quả, bao gồm cả bên thứ ba. Chúng tôi đã nghiên cứu chuyên sâu về HTTP Archivedữ liệu Lighthouse để tìm ra bên thứ ba đã chặn kết xuất nhiều nhất trên các khung khác nhau.

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

Sắp xếp trình tự các tập lệnh của bên thứ ba mà không cần 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 hiển thị cung cấp các phương pháp sau để tải và sắp xếp trình tự tập lệnh bên thứ ba một cách hiệu quả:

  1. Dùng thuộc tính async hoặc defer có 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. Những tập lệnh không bắt buộc cho lượt tải trang ban đầu hoặc lượt 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 kết nối sớm với những nguồn gốc bắt buộc bằng cách sử dụng kết nối trước và tìm nạp trước DNS. Đ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 từng phần 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 có chứa các tài nguyên đó trên trang.

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 pháp ở trên để sắp xếp trình tự các tập lệnh và cung cấp mẫu để các nhà phát triển xác định chiến lược tải của họ. Sau khi bạn chỉ định chiến lược phù hợp, chiến lược này 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 <script> HTML và cung cấp một lựa 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 ba giá trị.

  1. beforeInteractive: Bạn có thể dùng tuỳ chọn này cho các tập lệnh quan trọng sẽ thực thi trước khi trang có khả năng tương tác. Next.js đảm bảo rằng các tập lệnh đó được chèn vào HTML ban đầu trên máy chủ và được thực thi trước các JavaScript tự nhóm khác. Việc quản lý sự đồng ý, tập lệnh phát hiện bot hoặc thư viện trình trợ giúp cần thiết để hiển thị nội dung quan trọng là những đề xuất 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 một 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 tương tác – ví dụ: tập lệnh phân tích. Next.js sẽ 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 chạy sau khi trang được bổ sung nước. Do đó, trừ khi có quy định khác, tất cả các tập lệnh bên thứ ba được xác định bằng thành phần Tập lệnh đều bị Next.js trì hoãn, do đó cung cấp giá trị mặc định mạnh mẽ.

  3. lazyOnload: Tuỳ chọn này có thể được dùng để tải từng phần các tập lệnh có mức độ ưu tiên thấp khi trình duyệt ở trạng thái rảnh. 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 tương tác – ví dụ: trình bổ trợ trò chuyện hoặc mạng xã hội.

Các nhà phát triển có thể cho Next.js biết cách ứng dụng của họ dùng một tập lệnh bằng cách chỉ định chiến lược đó. Việc này cho phép khung áp dụng các biện pháp tối ưu hoá và các 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 sau 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ị trí với thành phần sử dụng tập lệnh. Sau khi quá trình uống nước được đưa vào cơ thể, tập lệnh sẽ được chèn vào phần đầu của tài liệu được kết xuất ban đầu hoặc ở phần dưới cùng của 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ại Next.js và blog dành cho người mới bắt đầu để tạo hai ứng dụng minh hoạ giúp đo lường tác động của việc thêm tập lệnh của bên thứ ba. Trước tiên, những bên thứ ba thường dùng để nhúng Trình quản lý thẻ của Google và mạng xã hội đã được đưa trực tiếp vào các trang của những ứng dụng này, sau đó trực tiếp đưa vào 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 trong công cụ WebPageTest.

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

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ư được cung cấp dưới đây.

Trước Sau
Trình quản lý thẻ của Google không đồng bộ Thành phần tập lệnh có chiến lược = afterFuture cho cả hai tập lệnh
Nút Theo dõi trên Twitter không có chế độ đồ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 có 2 tập lệnh.

Thông tin 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ộ công cụ 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 với thành phần Tập lệnh được bật bằng chiến lược tải phù hợp.

Thông tin so sánh dải phim thể hiện sự ứng biến ở 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ư được cung cấp dưới đây.

Trước Sau
Trình quản lý thẻ của Google không đồng bộ Thành phần tập lệnh có chiến lược = lazyonload cho mỗi tập lệnh trong số 4 tập lệnh
Nút Theo dõi trên Twitter không đồng bộ
Nút Đăng ký YouTube không cần đồng bộ hoặc trì hoãn
Nút Theo dõi LinkedIn mà không cần đồ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 có 4 tập lệnh.
Video hiển thị 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ó thành phần Script cải thiện 0,5 giây.

Như trong video, First Contentful Paint (FCP) xuất hiện tại 0,9 giây trên trang mà không có thành phần Script và 0,4 giây với thành phần Script.

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 mang lại khả năng kiểm soát đáng kể đối với các tập lệnh chặn hiển thị, nhưng chúng tôi cũng đang tìm hiểu các tuỳ chọn khác có thể làm tăng tiện ích của thành phần Tập lệnh.

Sử dụng nhân viên web

Bạn có thể sử dụng nhân viên web để chạy tập lệnh độc lập trên các luồng trong nền. Việc này có thể giải phóng luồng chính để xử lý các tác vụ xử lý giao diện người dùng và cải thiện hiệu suất. Web Workers là lựa chọn phù hợp nhất để giảm tải quá trình xử lý JavaScript, thay vì công việc giao diện người dùng, ra khỏi luồng chính. Những tập lệnh dùng cho dịch vụ 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ể phù hợp để thực thi trên một luồng ở chế độ nền. Bạn có thể dùng một thư viện gọn nhẹ của bên thứ ba – PartyTown – để tách riêng các tập lệnh như vậy thành một trình chạy web.

Khi triển khai thành phần tập lệnh Next.js hiện tại, 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 sẽ giới thiệu một lựa chọn chiến lược mới là 'worker'. Lựa chọn này sẽ 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 trình thực thi web. Chúng tôi hoan nghênh nhận xét của 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 nội dung nhúng từ nguồn cấp dữ liệu mạng xã hội có thể khiến bố cục thay đổi khi tải từng phần. Điều này ảnh hưởng đến trải nghiệm người dùng và chỉ số Điểm số tổng hợp về mức thay đổi bố cục (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ể sử dụng thành phần Tập lệnh để tải các nội dung nhúng có thể làm thay đổi bố cục. Chúng tôi đang cân nhắc việc tăng cường tính năng này để cung cấp các lựa chọn cấu hình giúp giảm CLS. Tính năng này có thể được cung cấp 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 để bao gồm 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) thường được cố định. Các gói này có thể được đóng gói thêm trong các thành phần trình bao bọc riêng lẻ cho từng loại tập lệnh. Chỉ có một tập hợp tối thiểu gồm các thuộc tính dành riêng cho ứng dụng (chẳng hạn như mã theo dõi) được cung cấp cho nhà phát triển. 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 khung này sử dụng chiến lược tối ưu nhất.

Kết luận

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 đang 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 đó (thành phần Tập lệnh Next.js thực hiện theo mặc định). Nhà phát triển có thể đảm bảo rằng các tập lệnh được đưa vào sẽ không trì hoãn chức năng quan trọng trừ phi họ áp dụng rõ ràng chiến lược beforeInteractive. Giống như thành phần Tập lệnh Next.js, các nhà phát triển khung cũng có thể cân nhắ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 việc tạo ra 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ể cải thiện thành phần Tập lệnh để đáp ứng các trường hợp sử dụng khác.

Thư cảm ơn

Cảm ơn Kara Erickson, Janicklas Saga, Katie Hempenius, Philip Walton, Jeremy WagnerAddy Osmani đã phản hồi về bài đăng này.