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, 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
Lễ hội Houssein Djirdeh
Houssein Djirdeh

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à các tập lệnh. Kích thước, độ trễ và hoạt động 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 Next.js Script đi kèm với các phương pháp hay nhất và các giá trị mặc định được tích hợp để giúp nhà phát triển đưa các tập lệnh của bên thứ ba vào ứng dụng của họ, đồng thời giải quyết các vấn đề 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, người tạo 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 đối với 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.

Các tập lệnh chiếm một lượng đáng kể byte của bên thứ ba được các trang web tải xuống trên các danh mục yêu cầu khác nhau 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 bắt buộc đối với bố cục để hiển thị trang. Các bên thứ ba không bắt buộc phải hiển thị ban đầu phải được trì hoãn để 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 luồng hiển thị hoặc tập lệnh chặn luồng chính.

Các bài 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à 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 này cho từng bên thứ ba mà họ sử dụng. Quá trình 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 đối với từng tính năng.
  • Việc triển khai nhiều bên thứ ba có thể khác nhau tuỳ theo việc bạn 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 được ra mắt thường xuyên.
  • Việc thay đổi các yêu cầu kinh doanh liên quan đến cùng một bên thứ ba sẽ khiến các nhà phát triển gặp khó khăn trong việc chuẩn hoá việc sử dụng công cụ đó.

Aurora tập trung vào kịch bản của bên thứ ba

Một phần trong quá trình hợp tác của Aurora với các công cụ và khung web nguồn mở là cung cấp các chế độ 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, khả năng bảo mật và mức độ sẵn sàng của 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ố Các chỉ số quan trọng về trang web tương ứng.

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 cho các tập lệnh của bên thứ ba trong Next.js. Các khung như Next.js có vị thế đặc biệt để cung cấp các giá trị mặc định và tính năng 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ả các bên thứ ba. Chúng tôi đã nghiên cứu dữ liệu chuyên sâu về Kho lưu trữ HTTP và Lighthouse để tìm hiểu xem bên thứ ba chặn kết xuất hình ảnh nào nhiều nhất trên các khung khác nhau.

Để giải quyết vấn đề các tập lệnh của bên thứ ba chặn luồng chính được dùng trong một ứng dụng, chúng tôi đã xây dựng 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 theo trình tự để mang lại 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 theo trình tự 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 có sẵn để giảm tác động của tập lệnh chặn hiển thị cung cấp các phương thức sau để tải và sắp xếp trình tự tập lệnh của bên thứ ba một cách hiệu quả:

  1. Sử 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 cần thiết 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 xem 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 đến các 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 trước DNS. Việc 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 trang chứa chúng.

Thành phần Next.js Script

Thành phần Next.js Script triển khai các phương pháp trên để sắp xếp trình tự 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 của họ. Sau khi được chỉ định, chiến lược phù hợp 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 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://polyfill.io/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ể sử 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ó tính tương tác. Next.js đảm bảo rằng các tập lệnh đó sẽ được đưa vào HTML ban đầu trên máy chủ và được thực thi trước các JavaScript tự gói khác. Chiến lược này nên có tính năng 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.

  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 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 cấp nước. Do đó, trừ khi 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 Script sẽ được Next.js trì hoãn, do đó tạo ra một chế độ mặc định hiệu quả.

  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. Chức năng do các tập lệnh đó cung cấp không cần thiết ngay sau khi trang có tính tương tác (ví dụ: trình bổ trợ trò chuyện hoặc trình bổ trợ 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. Nhờ đó, khung áp dụng các biện 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 hiệu quả nhất.

Khi sử dụng thành phần Script, 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 dành cho bên thứ ba tải muộn cũng như ở 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 bằng tập lệnh. Sau khi quá trình thêm nước, tập lệnh sẽ được chèn vào phần đầu của tài liệu được hiển thị ban đầu hoặc ở cuối phần nội dung, tùy 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, các bên thứ ba thường dùng cho Trình quản lý thẻ của Google và nội dung nhúng trên mạng xã hội đã được thêm trực tiếp vào các trang của những ứng dụng này, sau đó là 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 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ư bên dưới.

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 = afterInteractive 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 Thành phần tập lệnh và tập lệnh cho bản minh hoạ 1 gồm 2 tập lệnh.

So sánh sau đây cho thấy tiến trình trực quan cho cả hai phiên bản của Next.js commerce starter-kit. Như đã thấy, LCP xảy ra gần 1 giây trước đó khi thành phần Tập lệnh được bật với chiến lược tải phù hợp.

So sánh đoạn phim cho thấy tính ứng biến trong LCP

Các 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 không đồng bộ Thành phần tập lệnh có chiến lược = tải từng phần cho từng tập lệnh trong số 4 tập lệnh
Nút Theo dõi trên Twitter có chế độ không đồng bộ
Nút Đăng ký trên YouTube không đồng bộ hoặc trì hoãn
Nút Theo dõi trên LinkedIn không đồng bộ hoặc trì hoãn
Cấu hình thành phần tập lệnh và tập lệnh cho bản minh hoạ 2 gồm 4 tập lệnh.
Video minh hoạ tiến trình tải trang chỉ mục khi 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 Script.

Như bạn có thể thấy trong video, Thời gian hiển thị nội dung đầu tiên (FCP) xuất hiện tại 0,9 giây trên trang không có thành phần Tập lệnh và 0,4 giây với thành phần Tập lệnh.

Nội dung tiếp theo dành 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 quyền kiểm soát đáng kể đối với các tập lệnh chặn hiển thị, nhưng chúng ta cũng đang tìm hiểu các lựa chọn khác giúp tăng tiện ích của thành phần Script.

Sử dụng trình chạy web

Bạn có thể dùng trình chạy web để chạy các tập lệnh độc lập trên luồng nền. Việc này có thể giải phóng luồng chính nhằm xử lý các thao tác trên giao diện người dùng và cải thiện hiệu suất. Web Worker phù hợp nhất để giảm tải cho quá trình xử lý JavaScript, thay vì công việc trên giao diện người dùng, ngoài luồng chính. Các tập lệnh dùng cho hoạt độ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à lựa chọn phù hợp để thực thi trên 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 các tập lệnh đó thành một trình chạy web.

Với việc 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 đề xuất giới thiệu một tuỳ chọn chiến lược mới là '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 web worker. Chúng tôi hoan nghênh bình luận của các nhà phát triển trên RFC này.

Giảm thiểu CLS (Điểm số tổng hợp về mức thay đổi bố cục)

Nội dung nhúng của bên thứ ba như quảng cáo, video hoặc nội dung nhúng nguồn cấp dữ liệu trên mạng xã hội có thể làm thay đổi bố cục 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) cho 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.

Có thể 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 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. Điều 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 trong 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 là cố định. Bạn có thể tiếp tục đóng gói các tập lệnh 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. Chỉ một tập hợp tối thiểu các thuộc tính dành riêng cho ứng dụng (chẳng hạn như mã theo dõi) sẽ được cung cấp cho nhà phát triển. Các thành phần trình bao bọc sẽ giúp nhà phát triển bằng cách:

  1. Giúp nhà tiếp thị 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 để nâng cao.

Kết luận

Tập lệnh của bên thứ ba thường được tạo để bao gồm các tính năng cụ thể trong trang web đang 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 này—mà thành phần Next.js Script sẽ thực hiện theo mặc định. Nhà phát triển đảm bảo rằng các tập lệnh đi kèm 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 Next.js Script, nhà phát triển khung cũng có thể xem xét tạo các tính năng này trong các khung khác. Chúng tôi đang tích cực khám phá việc tạo ra 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 sẽ cải thiện hơn nữa thành phần Tập lệnh để bao gồm các trường hợp sử dụng khác.

Thư cảm ơn

Cảm ơn Kara Erickson, Janicklas Brian, Katie Hempenius, Philip Walton, Jeremy WagnerAddy Osmani đã chia sẻ ý kiến phản hồi về bài đăng này.