ナビゲーションをスキップ
部 I 章 2

JavaScript

序章

ここ数年のJavaScript言語の進化のスピードと一貫性には目を見張るものがあります。以前は主にクライアントサイドで使用されていましたが、今ではサービスやサーバーサイドのツールを構築する世界において、非常に重要で尊敬すべき場所となっています。JavaScriptは、より高速なアプリケーションを作成できるだけでなく、ブラウザ内でサーバを実行可能なほどに進化しています。

アプリケーションをレンダリングする際、ブラウザの中では、JavaScriptのダウンロードから解析、コンパイル、実行まで、さまざまなことが行われています。まずはその最初のステップとして、実際にページから要求されるJavaScriptの量を把握してみましょう。

JavaScriptをどれだけ読み込むか?

「測定することは改善への鍵である」と言われています。アプリケーションでのJavaScriptの使用を改善するためには、検出されているJavaScriptのうち、実際に必要とされるものがどれくらいあるかを測定する必要があります。ここでは、Web設定においてJavaScriptが果たす重要な役割を考慮して、ページあたりのJavaScriptバイト数の分布を理解することにしましょう。

ページあたりのJavaScriptバイト数の分布を示す棒グラフ。デスクトップページの中央値は463キロバイトのJavaScriptをロードします。デスクトップの10、25、50、75、90パーセンタイルは、94キロバイト、220キロバイト、463キロバイト、852キロバイト、1,354キロバイトです。
図2.1. ページごとに読み込まれるJavaScriptの量の分布。

50パーセンタイル(中央値)のモバイルページでは427KBのJavaScriptがロードされるのに対し、デスクトップデバイスでロードされるページの中央値では463KBが送信されます。

2019年の結果と比較すると、デスクトップではJavaScriptの使用率が18.4%増加し、モバイルでは18.9%増加していることがわかります。長期的な傾向として、より多くのJavaScriptを使用するようになっていますが、CPUの作業が増えることで、アプリケーションのレンダリング速度を低下する可能性があります。なお、これらの統計は、圧縮応答が可能な転送バイト数を表しているため、実際のCPUコストはかなり高くなる可能性があることをご了承ください。

では、実際にどの程度のJavaScriptがページに読み込まれる必要があるのかを見てみましょう。

ページあたりの未使用JavaScriptバイト数の分布を示す棒グラフ。モバイルの中央値では、155KBの未使用のJavaScriptが読み込まれています。モバイルの10、25、50、75、90パーセンタイルは次のとおりです。20kb、64kb、155kb、329kb、598kb。
図2.2. モバイルにおけるJavaScriptの未使用バイト量の分布。

Lighthouseによると、モバイルページの中央値では、155KBの未使用のJavaScriptがロードされています。また、90パーセンタイルでは、598KBのJavaScriptが使われていません。

読み込まれたJavaScriptと、読み込まれなかったJavaScriptの差を示す棒グラフ。モバイルページの中央値では、読み込まれた427KBのJavaScriptのうち、155KBが未使用です。読み込まれたJavaScript全体の36.2%が未使用となり、CPUコストが増加しています。
図2.3. モバイルページにおける未使用および総JavaScriptバイト数の分布。
図2.4. 読み込まれたJavaScriptのうち未使用の割合。

言い換えれば、中央値のモバイルページでは、36.2%のJavaScriptバイトが使用されていません。JavaScriptがページの最大コンテンツの描画(LCP)に与える影響を考えると、とくにデバイスの性能やデータプランが限られているモバイルユーザーにとっては、CPUサイクルや他の重要なリソースがムダに消費されていることを考えると、これは非常に大きな数字です。このようなムダは、大規模なフレームワークやライブラリに同梱されている、使用されていない多くの定型的なコードの結果である可能性があります。

サイトオーナーは、Lighthouseを使って使われていないJavaScriptをチェックし、ベストプラクティスにしたがって使われていないコードを削除することで、ムダなJavaScriptバイトの割合を減らすことができます。

ページあたりのJavaScriptリクエスト数

Webページのレンダリングが遅くなる要因のひとつとして、ページ上で行われるリクエスト、とくにリクエストをブロックしている場合が考えられます。そこで、デスクトップとモバイルの両方で、1ページあたりのJavaScriptリクエスト数を調べてみることにしました。

デスクトップページとモバイルページにおけるJavaScriptリクエストの分布を示す棒グラフ。モバイルページの中央値では20個のJavaScriptリソースがロードされるのに対し、デスクトップでは21個のJavaScriptリソースがロードされます。モバイルでのリクエストの10、25、50、75、90パーセンタイルは次のとおりです。4、10、20、35、56。
図2.5. ページあたりのJavaScriptリクエスト数の分布。

デスクトップページの中央値では、21個のJavaScriptリソース(.jsおよび.mjsのリクエスト)がロードされ、90パーセンタイルでは59個のリソースがロードされます。

デスクトップおよびモバイルデバイス上で読み込まれるJavaScriptリソースの分布を年ごとに示した棒グラフ。2020年には、1ページで行われたJSリクエストの中央値は19で、これが2021年には20に増加しています。
図2.6. 1ページあたりのJavaScriptリクエスト数の年別分布。

昨年の結果と比較すると、2021年に要求されたJavaScriptリソースの数はわずかに増加しており、ロードされたJavaScriptリソースの数の中央値はデスクトップページで20、モバイルで19でした。

傾向としては、1ページに読み込まれるJavaScriptリソースの数が徐々に増えています。これはJavaScriptのリクエスト数が少ないとパフォーマンスが向上する場合もあれば、そうでない場合もあることを考えると、実際に数値を上げるべきか、下げるべきか悩むところです。

ここで、最近のHTTPプロトコルの進歩により、JavaScriptのリクエスト数を減らしてパフォーマンスを向上させようという考えが不正確になってきました。HTTP/2とHTTP/3の導入により、HTTPリクエストのオーバーヘッドが大幅に削減されたため、同じリソースをより多くのリクエストで要求することは、必ずしも悪いことではなくなりました。これらのプロトコルの詳細については、HTTPの章を参照してください。

JavaScriptはどのように要求されるのですか?

JavaScriptはさまざまな方法でページに読み込まれますが、そのリクエスト方法はページのパフォーマンスに影響を与えます。

modulenomodule

Webサイトを読み込む際、ブラウザはHTMLをレンダリングし、適切なリソースを要求します。ブラウザは、ページを効果的にレンダリングして機能させるために、コード内で参照されるポリフィルを消費します。アロー関数式非同期関数のような新しい構文をサポートしているモダンブラウザは、動作させるために大量のポリフィルを必要としませんし、その必要もありません。

この時、differential loadingが活躍します。type="module"属性を指定すると、モダンブラウザにはモダンな構文のバンドルが提供され、ポリフィルがあったとしても少なくなります。同様に、モジュールをサポートしていない古いブラウザには、type="nomodule"属性を指定することで、必要なポリフィルとトランスパイルされたコード構文を持つバンドルが提供されます。HTMLにモジュールを適用するの続きを読んでください。

これらの属性の採用状況をデータで見てみましょう。

属性 デスクトップ モバイル
module 4.6% 4.3%
nomodule 3.9% 3.9%
図2.7. デスクトップとモバイルのクライアントでの負荷のかかり方の違いの分布。

デスクトップページの4.6%がtype="module"属性を使用しているのに対し、モバイルページでは3.9%しかtype="nomodule"を使用していません。これは、モバイルのデータセットの方がはるかに大きいため、最新の機能を使っていない可能性のある「ロングテール」のウェブサイトが多く含まれていることが原因と考えられます。

なお、IE 11ブラウザのサポート終了に伴い、エバーグリーンブラウザは最新のJavaScript構文をサポートしているため、ディファレンシャルローディングは適用しにくくなっています。たとえば、Angularフレームワークでは、Angular v13でレガシーブラウザのサポートの削除を2021年11月に発表しました。

asyncdefer

JavaScriptの読み込みは、非同期または遅延の指定がない限り、レンダリングの妨げになる可能性があります。多くの場合、最初のレンダリングにJavaScript(もしくはその一部)が必要となるため、これがパフォーマンス低下の一因となっています。

しかし、JavaScriptを非同期に、あるいは遅延して読み込むことで、このような体験を改善できる場合があります。asyncdeferの両属性は、非同期的にスクリプトをロードします。async属性を持つスクリプトは定義された順番に関係なく実行されますが、deferはドキュメントが完全に解析された後にのみスクリプトを実行するので、指定された順番で実行されることが保証されます。実際に、ブラウザで要求されたJavaScriptにこれらの属性を指定しているページがどれだけあるかを見てみましょう。

属性 デスクトップ モバイル
async 89.3% 89.1%
defer 48.1% 47.8%
両方 35.7% 35.6%
どちらでもない 10.3% 10.4%
図2.8. asyncdeferを使用しているページの割合。

昨年の結果では、同じスクリプトに asyncdefer の両方の属性を使用しているウェブサイトがあるというアンチパターンが観察されました。これは、ブラウザがサポートしている場合は async にフォールバックし、IE8とIE9のブラウザでは defer を使用するというものです。しかし、ほとんどのサイトでは、サポートされているすべてのブラウザでasyncが優先されるため、現在ではこの方法は必要ありません。このパターンでは、ページが読み込まれるまで待つのではなく、HTMLの解析が中断されます。この使用頻度は非常に高く、モバイルページの 11.4% には、asyncdefer 属性を持つスクリプトが少なくとも1つ使用されていました。根本原因が判明し、今後このような使い方をしないというアクションアイテムも降ろされたのです。

図2.9. 同一スクリプト上で asyncdefer 属性が設定されているモバイルページの割合。

今年は、モバイルページの35.6%が asyncdefer 属性を併用していることがわかりました。昨年との大きな違いは、初期のHTMLの静的なコンテンツを解析するのではなく、実行時に属性の使用状況を測定するように方法を改善したことによるものです。この差は、多くのページが、ドキュメントがすでに読み込まれた後に、これらの属性を動的に更新していることを示しています。たとえば、あるウェブサイトでは、次のようなスクリプトが含まれていることが判明しました。

<!-- Piwik -->
<script type="text/javascript">
   (function() {
      var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
      g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
   })();
</script>
<!-- End Piwik Code -->

さて、Piwikとは何でしょうか?そのWikipediaの項目によると。

Matomo(旧Piwik)は、国際的な開発者チームによって開発されたフリーでオープンソースのウェブ解析アプリケーションで、PHP/MySQLのウェブサーバー上で動作します。1つまたは複数のウェブサイトへのオンライン訪問を追跡し、分析のためにこれらの訪問に関するレポートを表示します。2018年6月現在、Matomoは145万5千以上のウェブサイトで使用されており、これは既知のトラフィック分析ツールを持つすべてのウェブサイトの1.3%にあたります…
ウィキペディアのMatomo (ソフトウェア)

この情報は、我々が観測した増加の多くは、類似のマーケティングおよび分析プロバイダーが、これらのasyncおよびdeferスクリプトを以前に検出されたよりも遅くページに動的に注入することによるものである可能性を強く示唆しています。

図2.10. asyncdefer属性を併用しているスクリプトの割合。

多くのページがこのアンチパターンを使用しているにもかかわらず、同じscript要素でasyncdeferの両方を使用しているスクリプトは全体の2.6%しかないことがわかりました。

ファーストパーティとサードパーティ

How much JavaScript do we loadのセクションで、モバイルページのJavaScriptリクエスト数の中央値が20であることを思い出してください。このセクションでは、ファーストおよびサードパーティのJavaScriptリクエストの内訳を見てみましょう。

モバイルページあたりのJavaScriptリクエストのホスト別分布を示す棒グラフ。中央値のモバイルページでは、ファーストパーティからのリクエストが9回、サードパーティからのリクエストが10回となっています。
図2.11. モバイルページ1ページあたりのJavaScriptリクエスト数のホスト別分布。

モバイルページの中央値では、サードパーティ製リソースへのリクエストが10件、ファーストパーティ製リクエストが9件となっています。この差は、90パーセンタイルになるほど大きくなります。モバイルページのファーストパーティリソースへのリクエストは33件ですが、モバイルページのサードパーティリソースへのリクエストは34件に上ります。明らかに、サードパーティ製リソースのリクエスト数は、ファーストパーティ製リソースのリクエスト数よりも常に一歩リードしています。

デスクトップページあたりのJavaScriptリクエストのホスト別分布を示す棒グラフ。モバイルページの中央値では、ファーストパーティのリクエストが10件、サードパーティのリクエストが11件となっています。デスクトップでのファーストパーティへのリクエストの10、25、50、75、90パーセンタイルは次のとおりです。2、4、10、19、33。
図2.12. デスクトップページあたりのJavaScriptリクエスト数のホスト別分布。

デスクトップページの中央値では、サードパーティ製リソースを11個要求しているのに対し、ファーストパーティ製は10個です。サードパーティ製リソースがもたらすパフォーマンスと信頼性のリスクにかかわらず、デスクトップページとモバイルページの両方で、サードパーティ製スクリプトが一貫して好まれているようです。この効果は、サードパーティのスクリプトがウェブに与える便利なインタラクティビティ機能によるものと考えられます。

とはいえ、サイトオーナーは、サードパーティ製のスクリプトがパフォーマンス良くロードされていることを確認する必要がありますHarry Robertsは、さらに一歩進んで、サードパーティのパフォーマンスとレジリエンスをストレステストすることを提唱しています

preloadprefetch

ページがレンダリングされると、ブラウザは与えられたリソースをダウンロードしますが、リソースヒントを使って、ブラウザが使用するいくつかのリソースのダウンロードを他のリソースよりも優先させます。preloadヒントは、現在のページで必要となる、より高い優先順位のリソースをダウンロードするようブラウザに指示します。しかしprefetchヒントは、リソースがしばらくしてから必要になる可能性があり(将来のナビゲーションに役立つ)、ブラウザにその能力があるときにリソースを取得し、必要になった時すぐに利用できるようにしたほうがよいということをブラウザに伝えます。これらの機能がどのように使われるかについては、リソースヒントの章で詳しく説明しています。

デスクトップページの1.1%とモバイルページの1.0%が、1つ以上のJavaScriptリソースにリソースヒントprefetchを使用し、デスクトップリソースの15.8%とモバイルページの15.4%が、1つ以上のJavaScriptリソースにpreloadを使用していることを示す棒グラフです。
図2.13. JavaScriptリソースでのリソースヒントの使用

preloadヒントは、15.4%のモバイルページでJavaScriptのロードに使用されていますが、prefetchヒントは1.0%のモバイルページでしか使用されていません。デスクトップページでは、それぞれ15.8%と1.1%がJavaScriptリソースの読み込みにこれらのリソースヒントを使用しています。

また、ページごとに何個の preloadprefetch ヒントが使用されているかを確認することも、ヒントの影響に影響を与えるので便利です。たとえば、レンダリング時に読み込まれるリソースが5つあり、その5つすべてが preload ヒントを使用している場合、ブラウザはすべてのリソースを優先しようとしますが、これでは preload ヒントがまったく使用されていないのと同じように機能してしまいます。

ページごとのプリフェッチヒントの分布を示す棒グラフ。デスクトップページの中央値は、プリロードヒントで1つのJavaScriptリソースをロードします。
図2.14. ページごとのJavaScriptリソースのpreloadヒントの分布。
ページごとのprefetchヒントの分布を示す棒グラフ。デスクトップページの中央値は、2つのJavaScriptリソースをprefetchヒントでロードします。
図2.15. ページごとのJavaScriptリソースのprefetchヒントの分布。

中央値のデスクトップページは、1つのJavaScriptリソースを preload ヒントでロードし、2つのJavaScriptリソースを prefetch ヒントでロードします。

ヒント 2020 2021
preload 1 1
prefetch 3 2
図2.16. モバイルページあたりのJavaScriptリソースに対するpreloadおよびprefetchヒントの数の中央値の前年比比較。

モバイルページあたりのpreloadヒントの数の中央値は変わりませんが、prefetchヒントの数は1ページあたり3つから2つに減りました。中央値では、これらの結果はモバイルページとデスクトップページの両方で同じであることに注意してください。

JavaScriptはどのように配信されるのですか?

JavaScriptのリソースは、圧縮と最小化によってネットワーク上でより効率的に読み込むことができます。このセクションでは、両技術がどの程度効果的に利用されているかを理解するために、両技術の使用方法を探っていきます。

圧縮

圧縮とは、ネットワーク上で転送されるリソースのファイルサイズを小さくするプロセスです。圧縮率の高いJavaScriptリソースのダウンロード時間を短縮するには、この方法が有効です。たとえば、このページで読み込まれている almanac.js スクリプトは28KBですが、圧縮のおかげで転送時間はわずか9KBとなりました。ウェブ上でリソースが圧縮される方法については、圧縮の章で詳しく説明しています。

圧縮方法の使用率を示す棒グラフ。モバイルでは、JavaScriptリクエストの55%がgzip圧縮を適用し、31%がbr圧縮を適用し、14%がどの圧縮方法も適用していません。
図2.17. JavaScriptリソースの圧縮方法の採用。

ほとんどのJavaScriptリソースは、GzipBrotli (br) を使って圧縮されているか、あるいはまったく圧縮されていない(設定されていない)かのいずれかです。モバイルのJavaScriptリソースの55.4%がGzipで圧縮されているのに対し、30.8%がBrotliで圧縮されています。

興味深いことに、2019年のJavaScript圧縮の状況と比較すると、Gzipは10ポイント近く下がり、Brotliは16ポイント上がっています。この傾向は、Gzipと比較してBrotliが提供する圧縮レベルは高く、より小さいサイズのファイルを重視するようになったことを示しています。

この変化を説明するために、私たちはファーストリソースとサードパーティリソースの圧縮方法を分析しました。

ファーストパーティとサードパーティの圧縮方法の使用率を示す棒グラフ。サードパーティのJSリクエストの59%がモバイルでgzip圧縮を適用し、サードパーティのリクエストの30%がbr圧縮を適用し、サードパーティのスクリプトの11%がどの圧縮方法も適用していません。
図2.18. モバイルページにおけるファーストおよびサードパーティのJavaScriptリソースを圧縮する方法の採用。

モバイルページ上のサードパーティスクリプトの59.1%がGzip圧縮、29.6%がBrotliで圧縮されています。ファーストパーティースクリプトを見ると、Gzip圧縮は51.7%ですが、Brotliでは32.0%にとどまります。また、圧縮方法が定義されていないサードパーティスクリプトが11.3%存在します。

ファーストパーティとサードパーティの圧縮されていないリソースの割合を示す棒グラフ。非圧縮のサードパーティ製JavaScriptリソースの90%が5KB未満であり、10KB未満のファーストパーティ製リソースの非圧縮はわずか8%です。
図2.19. ファーストパーティとサードパーティの非圧縮のリソース。

圧縮されていないサードパーティのJavaScriptリソースの90%は5KB未満ですが、ファーストパーティからのリクエストは少し遅れています。このことは、多くのJavaScriptリソースが圧縮されない理由を説明するのに役立つかもしれません。小さなリソースを圧縮することで得られる利益は減少するため、小さなスクリプトはネットワーク上で数バイトを節約することによるパフォーマンス上のメリットよりも、サーバー側での圧縮とクライアント側での解凍によるリソース消費の方が、大きくなる可能性があります。

最小化

圧縮はネットワーク上のJavaScriptリソースの転送サイズを変更するだけですが、ミニフィケーションは実際にコード自体を小さくし、より効率的にします。これにより、スクリプトの読み込み時間が短縮されるだけでなく、クライアントがスクリプトを解析するのに費やす時間も短縮されます。

unminified JavaScriptのLighthouse監査では、最小化の機会を強調しています。

未処理JSの監査スコアの分布の割合を示す棒グラフです。モバイルページの67%が「未処理のJavaScript」のスコアが0.9~1.0の間にあります。
図2.20. 終了していないJavaScriptの監査スコアの分布

ここで、0.00は最悪のスコアを表し、1.00は最高のスコアを表します。モバイルページの67.1%は、オーディットスコアが0.9から1.0の間にあります。つまり、JavaScriptの未最適化のスコアが0.9よりも悪く、コードの最小化をより有効に活用できるページがまだ30%以上あるということです。2020年版の結果と比較すると、「未処理のJS」のスコアが0.9から1.0の間にあるモバイルページの割合は10ポイント減少しました。

今年のスコアが悪化した理由を理解するために、より深く掘り下げて、1ページあたり何バイトが未処理であるかを見てみましょう。

ページあたりの未処理のJSバイトの割合分布を示す棒グラフ。モバイルページの57%は0キロバイトの未確定JSを持ち、18%は0~10キロバイトの未確定JSを持ちます。
図2.21. ページごとの未処理のJavaScriptの量の分布(単位:KB)。

57.4%のモバイルページでは、Lighthouse監査で報告されたように、0KBの未処理のJavaScriptが使用されています。17.9%のモバイルページでは、0~10KBの未完成のJavaScriptが使用されています。残りのページでは、未処理のJavaScriptのバイト数が増加しており、前のグラフで「未処理のJavaScript」の監査スコアが低いページに対応しています。

未処理のJavaScriptバイトの平均分布を示す円グラフ。平均的なモバイルページの未消化のJavaScriptバイトの82%は、実際にはファーストパーティのスクリプトから来ています。
図2.22. 未処理のJavaScriptバイトの平均的な分布。

ホスト別に未処理のJavaScriptリソースを分類したところ、平均的なモバイルページの未処理のJavaScriptバイトの82.0%は、実際にはファーストパーティのスクリプトから来ていることがわかりました。

ソースマップ

ソースマップとは、JavaScriptのリソースと一緒に送信されるヒントで、ブラウザがそのリソースを最小化してソースコードにマッピングできます。ウェブ開発者にとっては、本番環境でのデバッグにとくに役立ちます。

図2.23. SourceMapヘッダーを使用しているモバイルページの割合。

スクリプトリソースにソースマップレスポンスヘッダーを使用しているモバイルページは、わずか0.1%です。この極端に少ない割合の理由としては、ソースマップを使ってオリジナルのソースコードを本番に出すことを選択するサイトは少ないことが考えられます。

図2.24. SourceMapヘッダーを使用するモバイルページのJavaScriptリソースのうち、ファーストパーティリソースの割合。

JavaScriptリソースのSourceMap使用率の98.0%がファーストパーティに起因しています。モバイルページでヘッダーを持つスクリプトのうち、サードパーティのリソースはわずか2.0%です。

ライブラリーとフレームワーク

多くの新しいライブラリやフレームワークが採用され、開発者とユーザーの体験をそれぞれ独自に改善することが期待されているため、JavaScriptの使用量は年々増加しているようです。あまりにも広く普及しているため、開発者が追いつくのに苦労している様子を表すframework fatigueという言葉が作られました。このセクションでは、現在ウェブ上で使用されているJavaScriptライブラリやフレームワークの人気度を見てみましょう。

ライブラリーの利用

ライブラリやフレームワークの使用状況を把握するために、HTTP ArchiveはWappalyzerを使用して、ページで使用されている技術を検出しています。

JavaScriptライブラリとフレームワークの使用状況を示す棒グラフ。モバイルページの84%がjQueryを使用しており、依然としてトップです。
図2.25. JavaScriptのライブラリやフレームワークの使用方法。

jQueryは依然としてもっとも人気のあるライブラリで、モバイルページの84%という驚異的な割合で使用されています。Reactの使用率は、昨年の4%から8%に急上昇しています。Reactの増加は、最近のWappalyzerの検出力向上による部分的なものであり、実際の採用状況の変化を必ずしも反映していない可能性があります。また、jQueryを使用したIsotopeが7%のページで見られ、RequireJSはわずか2%のページで上位から脱落していることも注目に値します。

2021年になっても、なぜjQueryが主流なのか不思議に思うかもしれません。これには主に2つの理由があります。まず、前年よりも強調されているように、ほとんどのWordPressサイトがjQueryを使用しています。CMSの章によると、WordPressはすべてのWebサイトの約3分の1で使用されているため、これがjQuery採用の大きな割合を占めています。また、他の主要なJavaScriptライブラリの中にも、何らかの形でjQueryを利用しているものがあり、間接的にjQueryが採用されていると考えられます。

図2.26. もっとも普及しているjQueryのバージョンです。

もっともよく使われているjQueryのバージョンは3.5.1で、モバイルページの21.3%で使用されています。次によく使われているjQueryのバージョンは1.12.4で、モバイルページの14.4%で使われています。バージョン3.0への飛躍は、2020年に行われたWordPress coreへの変更により、jQueryのデフォルトバージョンが1.12.4から3.5.1にアップグレードされたことで説明できます。

併用するライブラリ

では、人気のフレームワークやライブラリが、同じページでどのように併用されているかを見てみましょう。

フレームワークとライブラリ デスクトップ モバイル
jQuery 16.8% 17.4%
jQuery, jQuery Migrate 8.4% 8.7%
jQuery, jQuery UI 4.0% 3.7%
jQuery, jQuery Migrate, jQuery UI 2.6% 2.5%
Modernizr, jQuery 1.6% 1.6%
FancyBox, jQuery 1.1% 1.1%
Slick, jQuery 1.2% 1.1%
Lightbox, jQuery 1.1% 0.8%
React, jQuery, jQuery Migrate 0.9% 0.9%
Modernizr, jQuery, jQuery Migrate 0.8% 0.9%
図2.27. 併用されているJavaScriptフレームワークとライブラリの上位の組み合わせ。

もっとも広く使われているJavaScriptのライブラリとフレームワークの組み合わせは、実際には複数のライブラリで構成されているわけではありません!jQueryを単独で使用した場合、モバイルページの17.4%に使用されています。次に多い組み合わせは「jQuery」と「jQuery Migrate」で、モバイルページの8.7%で使用されている。実際、ライブラリとフレームワークの組み合わせのトップ10には、すべてjQueryが含まれている。

セキュリティの脆弱性

JavaScriptライブラリを使用するには、それなりのメリットとデメリットがあります。これらのライブラリを使用する際の欠点として、古いバージョンにはCross Site Scripting(XSS)のようなセキュリティリスクが含まれている可能性があります。Lighthouseは、ページで使用されているJavaScriptライブラリを検出し、そのバージョンがオープンソースのSnyk脆弱性データベースで既知の脆弱性を持っていた場合、監査に失敗します。

図2.28. セキュリティ上の脆弱性があるライブラリを持つモバイルページの割合。

モバイルページの63.9%が、既知のセキュリティ脆弱性を持つJavaScriptライブラリまたはフレームワークを使用しています。この数字は、昨年の83.5%から減少しています。

ライブラリやフレームワーク ページ数の割合
jQuery 57.6%
Bootstrap 12.2%
jQuery UI 10.5%
Underscore 6.4%
Lo-Dash 3.1%
Moment.js 2.3%
GreenSock JS 1.8%
Handlebars 1.3%
AngularJS 1.0%
Mustache 0.7%
jQuery Mobile 0.5%
Dojo 0.5%
Angular 0.4%
Vue 0.2%
Knockout 0.2%
Highcharts 0.1%
Next.js 0.0%
React 0.0%
図2.29. 脆弱なバージョンのJavaScriptライブラリまたはフレームワークを含むことが判明したモバイルページの割合。

モバイルページの割合をライブラリとフレームワーク別に分けてみると、脆弱性の減少にはjQueryが大きく関わっていることがわかります。今年のJavaScriptの脆弱性は、jQueryを使用しているページの57.6%で発見されたのに対し、昨年は80.9%でした。本章の2020年版でTim Kadlec予測したように、「もし人々がそれらの古くて脆弱なバージョンのjQueryから移行できれば、既知の脆弱性を持つサイトの数は激減するでしょう」。WordPressは、jQueryのバージョン1.12.4からより安全なバージョン3.5.1に移行したことで、JavaScriptの脆弱性が確認されたページの割合が20ポイント減少しました。

JavaScriptはどのように使用されていますか?

さて、JavaScriptの取得方法を見てきましたが、何のために使うのでしょうか?

AJAX

JavaScriptは、サーバーと通信してさまざまな形式の情報を非同期的に受け取るために使用されます。Asynchronous JavaScript and XML (AJAX)は、一般的にデータの送受信に使用され、XML以外にもJSON、HTML、テキスト形式などをサポートしています。

ウェブ上でデータを送受信する方法が複数ある中で、1ページあたりに送信される非同期リクエストの数を見てみましょう。

ページあたりの非同期リクエストの数を示す棒グラフ。デスクトップのページでは、非同期リクエスト数の10、25、50、75、90パーセンタイルの割合は次のとおりです。2、3、4、8、15。
図2.30. ページあたりの非同期リクエスト数の分布。

モバイルページの中央値は4つの非同期リクエストを行っています。ロングテールを見ると、デスクトップページの非同期リクエストの最大数は623で、最大のモバイルページの867の非同期リクエストに抜かれています!

非同期型のAJAXリクエストの代わりに、同期型のリクエストがあります。リクエストをコールバックに渡すのではなく、リクエストが完了するまでメインスレッドをブロックします。

しかし、パフォーマンスやユーザー体験が、低下する可能性があるため、このような行為は推奨されません。また、多くのブラウザでは、このような使用方法についてすでに警告を発しています。今でも同期型のAJAXリクエストを使用しているページがどれだけあるのか、興味をそそられますね。

モバイルページにおける同期および非同期のAJAXリクエストの使用状況を示す棒グラフ。モバイルページにおける同期型リクエストの割合は2.5%、非同期型リクエストの割合は77.6%となっている。
図2.31. 同期および非同期のAJAXリクエストの使用法

モバイルページの2.5%が、非推奨の同期型AJAXリクエストを使用しています。これを踏まえて、過去2年間の結果と比較して、その傾向を見てみましょう。

過去数年間の同期および非同期のAJAXリクエストの使用状況を示す棒グラフ。2019年にモバイルで行われた非同期リクエストの割合は54.9%で、2020年には61.8%、2021年は77.6%と増加しています。
図2.32. 長年にわたる同期および非同期AJAXリクエストの使用状況。

非同期型のAJAXリクエストの使用率が明らかに増加していることがわかります。しかし、同期型のAJAXリクエストの使用率には大きな減少は見られません。

現在、ページあたりのAJAXリクエストの数を知っているので、サーバーからデータを要求するためにもっとも一般的に使用されているAPIについても知りたいと思います。

これらのAJAXリクエストを大まかに3つの異なるAPIに分類し、それらがどのように使用されているかを調べてみましょう。コアAPIであるXMLHttpRequest (XHR)、FetchBeaconは、Webサイト全体で一般的に使用されており主にXHRが使用されていますが、Fetchは人気が高く急成長しており、Beaconは使用率が低いです。

デスクトップとモバイルの両方のページで、ページあたりのXMLHttpRequestの使用率を示す棒グラフ。モバイルページの中央値では2回のXHRリクエストが行われていますが、90パーセンタイルでは6回のXHRリクエストが行われています。デスクトップでのXMLHttpRequestの使用率の10、25、50、75、90パーセンタイルは次のとおりです。0、1、2、3、6。
図2.33. ページあたりのXMLHttpRequestリクエスト数の分布。

モバイルページの中央値は2回のXHRリクエストを行いますが、90パーセンタイルの割合では6回のXHRリクエストを行います。

デスクトップとモバイルの両ページにおける、ページあたりのFetchの使用状況を示す棒グラフ。モバイル・ページの中央値は2回のFetch要求ですが、90パーセンタイルでは3回のFetch要求です。モバイルにおけるFetchの使用率の10、25、50、75、90パーセンタイルは次のとおりです。0、2、2、2、3。
図2.34. ページあたりの Fetch リクエスト数の分布。

Fetch APIを使用した場合、モバイルページの中央値では2回のリクエスト、ロングテールでは3回のリクエストに達します。このAPIはXHRの標準的なリクエスト方法になりつつありますが、その理由の1つは、よりクリーンなアプローチと、定型的なコードが少ないことです。また、Fetchは従来のXHRアプローチよりもパフォーマンス上のメリットがあるかもしれません。これは、ブラウザがメインスレッドから大きなJSONペイロードをデコードする方法によるものです。

デスクトップとモバイルの両方のページで、1ページあたりのBeaconの使用状況を示す棒グラフです。モバイルページの中央値ではBeaconのリクエストはありませんが、90パーセンタイルでは1つのBeaconのリクエストがあります。
図2.35. 1ページあたりの Beacon リクエストの数の分布。

Beaconの使用率はほとんどなく、1ページあたりのリクエスト数は0で、90パーセンタイルまでは1ページあたり1つのリクエストしかありませんでした。この普及率の低さを説明する1つの可能性として、Beaconは一般的に分析データの送信に使用され、とくに、すぐにページをアンロードされる可能性があっても確実にリクエストを送信したい場合に使用されることが挙げられます。しかし、XHRを使用している場合、これは保証されていません。将来的には、分析データやセッションデータなどのために、XHRを使用しているページの統計情報を収集できるかどうかを試してみるとよいでしょう。

XHRとFetchの採用状況を時系列で比較するのもおもしろいかもしれません。

モバイルページにおけるページごとのXHRとFetchリクエストの採用状況を示す棒グラフ。XHRの使用率は、2019年に58%、2020年に62%、2021年に78%と増加しています。
図2.36. 年別のAJAX APIの採用状況。

FetchXHRの両方において、ここ数年で使用量が大幅に増加しています。モバイルページでの Fetch の使用率は4ポイント、XHRは19ポイント上昇しています。Fetchの採用が徐々に増加していることは、よりクリーンなリクエストと優れたレスポンス処理の傾向を示しているように思われます。

Web ComponentsとシャドウDOM

ウェブがコンポーネント化されていく中で、シングルページアプリケーションを構築する開発者は、ユーザービューをコンポーネントのセットとして考えることができます。これは、開発者が各機能ごとに専用のコンポーネントを構築するためだけでなく、コンポーネントの再利用性を最大限に高めるためでもあります。それは、同じアプリの別のビューにあったり、まったく別のアプリにあったりします。このようなユースケースでは、アプリケーションにカスタムエレメントやウェブコンポーネントが使用されます。

多くのJavaScriptフレームワークが普及したことで、再利用性や専用の機能ベースのコンポーネントを構築するという考え方がより広く採用されるようになったと言ってもいいでしょう。このことは、カスタム要素、シャドウDOM、テンプレート要素の採用を検討する上で、私たちの好奇心を刺激します。

カスタムエレメントは、HTMLElementのAPIの上に構築されたカスタマイズされたエレメントです。ブラウザはcustomElementsというAPIを提供しており、開発者は要素を定義し、それをカスタム要素としてブラウザに登録できます。

図2.37. カスタムエレメントを使用しているデスクトップページの割合。

3.0%のモバイルページでは、ウェブページの1つ以上の部分にカスタム要素を使用しています。

図2.38. シャドウDOMを使用しているページの割合。

シャドウDOMでは、ブラウザに導入されたカスタム要素のために、DOM内に専用のサブツリーを作成できます。これにより、要素内のスタイルやノードが要素の外からアクセスできないようになります。

0.4%のモバイルページでは、ウェブコンポーネントのシャドウDOM仕様を利用して、要素のスコープ付きサブツリーを確保しています。

図2.39. template要素を使用しているページの割合。

マークアップに再利用可能なパターンがある場合には、template要素が非常に便利です。template要素のコンテンツは、JavaScriptで参照されたときにのみレンダリングされます。

テンプレートは、JavaScriptでまだ参照されていないコンテンツが、シャドウDOMを使ってシャドウルートに追加されるため、ウェブコンポーネントを扱う際に有効です。

テンプレートを採用しているWebページは全体の0.1%にも満たない。テンプレートはブラウザでよくサポートされていますが、テンプレートを使用しているページの割合はまだ非常に低いです。

結論

この章で見てきた数字は、JavaScriptの使用がいかに膨大であるか、また時間の経過とともにどのように進化しているかを理解させてくれました。JavaScriptのエコシステムはウェブのパフォーマンスを向上させ、ユーザーの安全性を高めることに重点を置き、開発者の作業を容易にし、生産性を向上させる新しい機能やAPIを備えて成長してきました。

レンダリングやリソースローディングのパフォーマンスを向上させる多くの機能が、ユーザーに高速な体験を提供するために、より広く活用されていることがわかりました。開発者の皆様は、これらの新しいWebプラットフォームの機能を採用することから始めることができます。しかし、これらの機能を賢く利用し、実際にパフォーマンスが向上することを確認してください。というのも、同じスクリプトで async 属性と defer 属性を使用した場合のように、APIの中には誤用によって害を及ぼすものがあるからです。

今、私たちが利用できる強力なAPIを適切に活用することが、この数字を今後さらに向上させるために必要です。これからもそうしていきましょう。

著者