サードパーティ ライブラリを管理するための Next.js パッケージ

2021 年、Chrome Aurora チームは、Next.js のサードパーティ スクリプトの読み込みパフォーマンスを改善するために スクリプト コンポーネントを導入しました。リリース以来、Google はサードパーティ リソースの読み込みをデベロッパーにとってより簡単かつ迅速に行うための機能を拡張してきました。

このブログ投稿では、リリースされた新しい機能(特に @next/third-parties ライブラリ)の概要と、ロードマップ上の今後のイニシアチブの概要について説明します。

サードパーティ スクリプトがパフォーマンスに及ぼす影響

Next.js サイトのすべてのサードパーティ リクエストの 41% はスクリプトです。他のコンテンツ タイプとは異なり、スクリプトのダウンロードと実行にかなりの時間がかかることがあります。これにより、レンダリングがブロックされ、ユーザー操作が遅れる可能性があります。Chrome ユーザー エクスペリエンス レポート(CrUX)のデータによると、サードパーティ スクリプトを多く読み込む Next.js サイトでは、Interaction to Next Paint(INP)Largest Contentful Paint(LCP)の合格率が低くなっています。

読み込まれるサードパーティの数に比例して、良好な INP スコアと LCP スコアを達成した Next.js の割合が減少していることを示す棒グラフ
2023 年 12 月の CrUX レポート(110,823 サイト)

このグラフに示されている相関は、因果関係を意味するものではありません。ただし、ローカル テストでは、サードパーティ スクリプトがページのパフォーマンスに大きく影響するという追加の証拠が得られました。たとえば、以下のグラフは、ランダムに選択された 18 個のタグで構成される Google タグ マネージャー コンテナを、人気のある Next.js サンプルアプリである Taxonomy に追加した場合の各種 Labs 指標を比較したものです。

Google タグ マネージャーありの場合となしの場合で、サイトが読み込まれたときのさまざまなラボ指標の差異を示す棒グラフ
WebPageTest(モバイル 4G - 米国バージニア)

これらの時間の測定方法について詳しくは、WebPageTest のドキュメントをご覧ください。一見すると、これらのラボ指標のすべてが GTM コンテナの影響を受けることがわかります。たとえば、INP に近似する有用なラボ プロキシである Total Blocking Time(TBT) は、ほぼ 20 倍に増加しました。

スクリプト コンポーネント

Next.js で <Script> コンポーネントをリリースした際には、従来の <script> 要素によく似たユーザー フレンドリーな API を通じてコンポーネントを導入しました。これを使用すると、デベロッパーはアプリケーション内の任意のコンポーネントにサードパーティ スクリプトを同じ場所に配置できます。重要なリソースが読み込まれた後に、Next.js がスクリプトの順序付けを行います。

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

PatreonTargetNotion などの人気サイトを含む、数万もの Next.js アプリケーションが <Script> コンポーネントを使用しています。効果的であるにもかかわらず、一部のデベロッパーは次のような懸念を表明しています。

  • サードパーティ プロバイダのさまざまなインストール手順を遵守しつつ、Next.js アプリ内で <Script> コンポーネントを配置する場所(デベロッパー エクスペリエンス)
  • さまざまなサードパーティ スクリプト(ユーザー エクスペリエンス)に最適な読み込み方法。

これらの懸念の両方に対処するため、Google は @next/third-parties をリリースしました。これは、一般的なサードパーティ向けに最適化された一連のコンポーネントとユーティリティを提供する専用のライブラリです。

デベロッパー エクスペリエンス: サードパーティ ライブラリの管理を容易に

Next.js サイトの相当割合で多くのサードパーティ スクリプトが使用されています。Google タグ マネージャーが最も人気があり、サイトの 66% で使用されています@next/third-parties は、これらの一般的なユースケースでの使用を簡素化するように設計された上位レベルのラッパーを導入することで、<Script> コンポーネント上に構築されています。

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 アナリティクス(Next.js サイトの 52%)も、広く使用されているサードパーティ スクリプトであり、専用のコンポーネントがあります。

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 は、よく使用されるスクリプトの読み込みプロセスを簡素化するだけでなく、埋め込みなど、他のサードパーティ カテゴリ向けのユーティリティを開発する機能も拡張します。たとえば、Google マップと YouTube の埋め込みは、Next.js ウェブサイトのそれぞれ 8%4% で使用されています。また、読み込みを容易にするためのコンポーネントも提供されています。

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" />
    </>
  );
}

ユーザー エクスペリエンス: サードパーティ ライブラリの読み込みを高速化

理想としては、広く採用されているサードパーティ ライブラリはすべて完全に最適化され、パフォーマンスを向上させる抽象化は不要です。ただし、それが現実になるまで、Next.js などの一般的なフレームワークを介して統合することで、ユーザー エクスペリエンスを改善できます。さまざまな読み込み手法をテストし、スクリプトが適切に順序付けられていることを確認できます。最終的には、サードパーティ プロバイダとフィードバックを共有して、アップストリームの変更を促進できます。

YouTube の埋め込みを例にとりましょう。ただし、一部の代替実装では、ネイティブ埋め込みよりもパフォーマンスが大幅に向上します。現在、@next/third-parties によってエクスポートされた <YouTubeEmbed> コンポーネントは lite-youtube-embed を使用しています。これは、Next.js の「Hello, World」の比較で実証されているように、読み込みが大幅に速くなります。

YouTube Embed コンポーネントと通常の YouTube iframe でのページ読み込みの比較を示す GIF
WebPageTest(モバイル 4G - 米国バージニア)

同様に、Google マップでは、埋め込みのデフォルト属性として loading="lazy" が含まれており、ビューポートから一定の距離にある場合にのみ地図が読み込まれるようになっています。Google マップのドキュメントのコードサンプル スニペットに含まれているため、この属性は当然のように含まれるように思えますが、Google マップを埋め込む Next.js サイトの 45% のみが loading="lazy" を使用しています。

ウェブワーカーでサードパーティ スクリプトを実行する

@next/third-parties で検討している高度な手法の一つは、サードパーティ スクリプトをウェブワーカーに簡単にオフロードできるようにすることです。これは、Partytown などのライブラリで広く普及している機能です。サードパーティ スクリプトをメインスレッドから完全に移動することで、ページ パフォーマンスに対する影響を大幅に軽減できます。

次のアニメーション GIF は、Next.js サイト内の GTM コンテナにさまざまな <Script> 戦略を適用した場合の、長いタスクとメインスレッドのブロック時間の変化を示しています。戦略オプションを切り替えると、これらのスクリプトの実行タイミングが遅れるだけですが、ウェブワーカーに移動すると、メインスレッドでの時間が完全になくなります。

さまざまなスクリプト戦略におけるメインスレッドのブロック時間の違いを示す GIF
WebPageTest(モバイル 4G - 米国バージニア)

この例では、GTM コンテナとそれに関連するタグ スクリプトの実行をウェブワーカーに移行することで、TBT を 92% 削減できました。

注意すべき点として、この手法は慎重に管理しないと、多くのサードパーティ スクリプトがサイレントで破損し、デバッグが困難になる可能性があります。今後数か月以内に、@next/third-parties が提供するサードパーティ コンポーネントがウェブワーカーで実行されたときに正しく機能するかどうかを検証します。そのような場合は、デベロッパーがこの手法を簡単に使用できるオプションの方法を提供できるよう取り組んでまいります。

次のステップ

このパッケージの開発過程で、他のフレームワークも使用されている同じ手法の恩恵を受けられるように、サードパーティの読み込みに関する推奨事項を一元化する必要があることが明らかになりました。そこで Third Party Capital を構築しました。これは JSON を使用してサードパーティの読み込み手法を記述するライブラリで、現在は @next/third-parties の基盤となっています。

次のステップとして、Next.js 用に提供されているコンポーネントの改善に引き続き注力するとともに、他の一般的なフレームワークや CMS プラットフォームにも同様のユーティリティを追加する取り組みを拡大していきます。現在、Google は Nuxt のメンテナンス担当者と連携しており、近い将来、そのエコシステムに合わせて調整された同様のサードパーティ ユーティリティをリリースする予定です。

Next.js アプリで使用しているサードパーティのいずれかが @next/third-parties でサポートされている場合は、パッケージをインストールして試してみてください。GitHub でフィードバックをお寄せください。