Gói Next.js để quản lý thư viện của bên thứ ba

Vào năm 2021, nhóm Chrome Aurora đã giới thiệu Thành phần tập lệnh để cải thiện hiệu suất tải của các tập lệnh bên thứ ba trong Next.js. Kể từ khi ra mắt, chúng tôi đã mở rộng chức năng của công cụ này để giúp nhà phát triển tải tài nguyên của bên thứ ba dễ dàng và nhanh chóng hơn.

Bài đăng trên blog này cung cấp thông tin tổng quan về các tính năng mới hơn mà chúng tôi đã phát hành, đáng chú ý nhất là thư viện @next/third-parties, cũng như thông tin tóm tắt về các sáng kiến trong tương lai trên lộ trình của chúng tôi.

Ảnh hưởng của tập lệnh bên thứ ba đến hiệu suất

41% trong số tất cả các yêu cầu của bên thứ ba trong các trang web Next.js là tập lệnh. Không giống như các loại nội dung khác, tập lệnh có thể mất một khoảng thời gian đáng kể để tải xuống và thực thi, điều này có thể chặn quá trình kết xuất và trì hoãn khả năng tương tác của người dùng. Dữ liệu từ Báo cáo trải nghiệm người dùng trên Chrome (CrUX) cho thấy rằng các trang web Next.js tải nhiều tập lệnh bên thứ ba hơn có tỷ lệ đạt Lượt tương tác đến nội dung hiển thị tiếp theo (INP)Thời gian hiển thị nội dung lớn nhất (LCP) thấp hơn.

Biểu đồ thanh cho thấy tỷ lệ phần trăm Next.js đạt được điểm số INP và LCP tốt giảm xuống theo tỷ lệ với số lượng bên thứ ba được tải
Báo cáo CrUX tháng 12 năm 2023 (110.823 trang web)

Mối tương quan được quan sát trong biểu đồ này không ngụ ý mối quan hệ nhân quả. Tuy nhiên, các thử nghiệm cục bộ cung cấp thêm bằng chứng cho thấy tập lệnh của bên thứ ba ảnh hưởng đáng kể đến hiệu suất trang. Ví dụ: Biểu đồ bên dưới so sánh nhiều chỉ số trong các phòng thí nghiệm khi một vùng chứa Trình quản lý thẻ của Google (bao gồm 18 thẻ được chọn ngẫu nhiên) được thêm vào Taxonomy, một ứng dụng mẫu Next.js phổ biến.

Biểu đồ thanh cho thấy sự khác biệt về nhiều chỉ số trong thử nghiệm khi một trang web được tải có và không có Trình quản lý thẻ của Google
WebPageTest (Di động 4G – Virginia, Hoa Kỳ)

Tài liệu về WebPageTest cung cấp thông tin chi tiết về cách đo lường các thời gian này. Chỉ cần xem nhanh, bạn có thể thấy rõ rằng tất cả các chỉ số trong phòng thí nghiệm này đều chịu ảnh hưởng của vùng chứa GTM. Ví dụ: Tổng thời gian chặn (TBT) – một proxy phòng thí nghiệm hữu ích gần đúng với INP – đã tăng gần 20 lần.

Thành phần tập lệnh

Khi phân phối thành phần <Script> trong Next.js, chúng tôi đã đảm bảo giới thiệu thành phần này thông qua một API thân thiện với người dùng, gần giống với phần tử <script> truyền thống. Bằng cách sử dụng tính năng này, nhà phát triển có thể cùng đặt một tập lệnh của bên thứ ba trong bất kỳ thành phần nào trong ứng dụng của họ và Next.js sẽ xử lý việc sắp xếp tập lệnh sau khi các tài nguyên quan trọng đã tải.

<!-- By default, script will load after page becomes interactive -->
<Script src="https://example.com/sample.js" />

<!-- Script is injected server-side and fetched before any page hydration occurs -->
<Script strategy=”beforeInteractive” src="https://example.com/sample.js" />

<!-- Script is fetched later during browser idle time -->
<Script strategy=”lazyOnload” src="https://example.com/sample.js" />

Hàng chục nghìn ứng dụng Next.js (bao gồm cả các trang web phổ biến như Patreon, TargetNotion) sử dụng thành phần <Script>. Mặc dù hiệu quả, nhưng một số nhà phát triển đã nêu ra mối lo ngại về những điều sau:

  • Vị trí đặt thành phần <Script> trong ứng dụng Next.js, đồng thời tuân thủ hướng dẫn cài đặt khác nhau của các nhà cung cấp bên thứ ba (trải nghiệm nhà phát triển).
  • Chiến lược tải nào là tối ưu nhất để sử dụng cho các tập lệnh của bên thứ ba (trải nghiệm người dùng).

Để giải quyết cả hai vấn đề này, chúng tôi đã ra mắt @next/third-parties – một thư viện chuyên biệt cung cấp một bộ thành phần và tiện ích được tối ưu hoá dành riêng cho các bên thứ ba phổ biến.

Trải nghiệm dành cho nhà phát triển: giúp quản lý thư viện bên thứ ba dễ dàng hơn

Nhiều tập lệnh của bên thứ ba được sử dụng trong một tỷ lệ đáng kể các trang web Next.js, trong đó Trình quản lý thẻ của Google là phổ biến nhất, được 66% trang web sử dụng. @next/third-parties được xây dựng dựa trên thành phần <Script> bằng cách giới thiệu các trình bao bọc cấp cao hơn được thiết kế để đơn giản hoá việc sử dụng cho các trường hợp sử dụng phổ biến này.

import { GoogleAnalytics } from "@next/third-parties/google";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
      <GoogleTagManager gtmId="GTM-XYZ" />
    </html>
  );
}

Google Analytics – một tập lệnh bên thứ ba khác được sử dụng rộng rãi (52% trang web Next.js) – cũng có một thành phần chuyên dụng riêng.

import { GoogleAnalytics } from "@next/third-parties/google";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
      <GoogleAnalytics gaId="G-XYZ" />
    </html>
  );
}

@next/third-parties đơn giản hoá quá trình tải các tập lệnh thường dùng, nhưng cũng mở rộng khả năng phát triển các tiện ích cho các danh mục bên thứ ba khác, chẳng hạn như các mục nhúng. Ví dụ: Google Maps và YouTube được nhúng trong 8%4% trang web Next.js tương ứng. Chúng tôi cũng đã vận chuyển các thành phần để giúp các trang web này tải dễ dàng hơn.

import { GoogleMapsEmbed } from "@next/third-parties/google";
import { YouTubeEmbed } from "@next/third-parties/google";

export default function Page() {
  return (
    <>
      <GoogleMapsEmbed
        apiKey="XYZ"
        height={200}
        width="100%"
        mode="place"
        q="Brooklyn+Bridge,New+York,NY"
      />
      <YouTubeEmbed videoid="ogfYd705cRs" height={400} params="controls=0" />
    </>
  );
}

Trải nghiệm người dùng: giúp thư viện bên thứ ba tải nhanh hơn

Trong một thế giới lý tưởng, mọi thư viện bên thứ ba được sử dụng rộng rãi sẽ được tối ưu hoá hoàn toàn, khiến mọi hoạt động trừu tượng giúp cải thiện hiệu suất của thư viện trở nên không cần thiết. Tuy nhiên, cho đến khi điều đó trở thành hiện thực, chúng ta có thể cố gắng cải thiện trải nghiệm người dùng khi tích hợp thông qua các khung phổ biến như Next.js. Chúng ta có thể thử nghiệm nhiều kỹ thuật tải, đảm bảo rằng các tập lệnh được sắp xếp theo đúng cách và cuối cùng là chia sẻ ý kiến phản hồi với các nhà cung cấp bên thứ ba để khuyến khích các thay đổi ở thượng nguồn.

Ví dụ: tính năng nhúng video trên YouTube. Trong đó, một số phương thức triển khai thay thế có hiệu suất tốt hơn nhiều so với phương thức nhúng gốc. Hiện tại, thành phần <YouTubeEmbed> do @next/third-parties xuất ra sử dụng lite-youtube-embed. Khi được minh hoạ trong phần so sánh "Hello, World" Next.js, thành phần này tải nhanh hơn đáng kể.

Ảnh GIF cho thấy thông tin so sánh tốc độ tải trang giữa thành phần Nhúng YouTube và iframe YouTube thông thường
WebPageTest (Di động 4G – Virginia, Hoa Kỳ)

Tương tự như vậy, đối với Google Maps, chúng ta đưa loading="lazy" vào làm thuộc tính mặc định cho phần nhúng để đảm bảo rằng bản đồ chỉ tải khi ở một khoảng cách nhất định so với khung nhìn. Đây có vẻ như là một thuộc tính rõ ràng cần đưa vào, đặc biệt là vì tài liệu của Google Maps có đưa thuộc tính này vào đoạn mã mẫu của họ, nhưng chỉ 45% trang web Next.js nhúng Google Maps mới sử dụng loading="lazy".

Chạy tập lệnh của bên thứ ba trong worker web

Một kỹ thuật nâng cao mà chúng tôi đang khám phá trong @next/third-parties là giúp bạn dễ dàng chuyển các tập lệnh của bên thứ ba sang một worker web. Được phổ biến bởi các thư viện như Partytown, điều này có thể làm giảm đáng kể tác động của tập lệnh bên thứ ba đối với hiệu suất trang bằng cách di chuyển hoàn toàn các tập lệnh đó ra khỏi luồng chính.

Ảnh GIF động sau đây cho thấy sự khác biệt về thời gian chặn luồng chính và tác vụ dài khi áp dụng các chiến lược <Script> khác nhau cho vùng chứa GTM trong trang web Next.js. Xin lưu ý rằng mặc dù việc chuyển đổi giữa các tuỳ chọn chiến lược chỉ làm chậm thời điểm thực thi các tập lệnh này, nhưng việc di chuyển các tập lệnh này sang một worker web sẽ loại bỏ hoàn toàn thời gian của các tập lệnh này trên luồng chính.

Ảnh GIF cho thấy sự khác biệt về thời gian chặn luồng chính cho các chiến lược Tập lệnh khác nhau
WebPageTest (Di động 4G – Virginia, Hoa Kỳ)

Trong ví dụ cụ thể này, việc di chuyển quá trình thực thi vùng chứa GTM và các tập lệnh thẻ liên kết của vùng chứa đó sang một worker web đã giảm TBT xuống 92%.

Xin lưu ý rằng nếu không được quản lý cẩn thận, kỹ thuật này có thể âm thầm phá vỡ nhiều tập lệnh của bên thứ ba, khiến việc gỡ lỗi trở nên khó khăn. Trong những tháng tới, chúng tôi sẽ xác thực xem có thành phần nào của bên thứ ba do @next/third-parties cung cấp hoạt động đúng cách khi chạy trong trình chạy web hay không. Nếu có, chúng tôi sẽ nỗ lực để cung cấp một cách dễ dàng và không bắt buộc để nhà phát triển sử dụng kỹ thuật này.

Các bước tiếp theo

Trong quá trình phát triển gói này, rõ ràng là cần phải tập trung các đề xuất tải của bên thứ ba để các khung khác cũng có thể hưởng lợi từ cùng một kỹ thuật cơ bản được sử dụng. Điều này đã thúc đẩy chúng tôi xây dựng Third Party Capital (Vốn của bên thứ ba), một thư viện sử dụng JSON để mô tả các kỹ thuật tải của bên thứ ba, hiện đóng vai trò là nền tảng cho @next/third-parties.

Trong các bước tiếp theo, chúng tôi sẽ tiếp tục tập trung cải thiện các thành phần được cung cấp cho Next.js cũng như mở rộng nỗ lực để đưa các tiện ích tương tự vào các khung và nền tảng CMS phổ biến khác. Chúng tôi hiện đang cộng tác với các nhà bảo trì Nuxt và dự định phát hành các tiện ích tương tự của bên thứ ba được điều chỉnh cho phù hợp với hệ sinh thái của họ trong thời gian sắp tới.

Nếu một trong các bên thứ ba mà bạn sử dụng trong ứng dụng Next.js được @next/third-parties hỗ trợ, hãy cài đặt gói và thử nghiệm! Chúng tôi rất mong nhận được ý kiến phản hồi của bạn trên GitHub.