このブログはHugoで生成した静的webサイトである。 静的ページなので当然ながら読み込みは早い。Github Pagesで配布しているのでGithubのコンテンツキャッシュも効いている。 また一応アクセス解析のためにGoogle Analyticsを入れていて、大してアクセス数があるわけではないがモチベーションにつながっている。 ただしせっかく静的ページで読み込みを早くしているのにGoogle Analyticsのためにページロードの時間が割かれることにちょっと釈然としないものを感じていた。 GA一つでそこまで遅くなるわけではないけれど、頑張ってチューニングしたのにサードパーティスクリプトに律速されるのはなんとなく面白くない。

そこでpartytownを導入することにした。

https://partytown.builder.io/

partytownというのはDOM操作をするJavaScriptをWebWorkerで動かすためのライブラリである。 名前の通りサードパーティスクリプトを動かすことを想定しており、Worker側で遅延読み込みすることでメインスレッドでのページ読み込みを阻害しないようにすることが出来る。 WebWorkerでサードパーティスクリプトを動かすときの問題点として、Workerは別スレッドで動くためメインスレッドへのアクセスが非同期APIによる呼び出しになる。このためDOMアクセスなどの同期的なプロパティ呼び出しをエミュレートすることが難しくなるが、partytownはXMLHttpRequestのブロッキング呼び出しを流用することでこの問題を解決している。

参考: https://zenn.dev/stomita/articles/2c16a53223f3c9

導入については簡単でHTMLヘッダにスニペットとサードパーティスクリプトの呼び出しを書いておくだけである。

しかし公式での説明がちょっと不足していると感じたので簡単に手順を共有する。

まず、静的ページのアセットディレクトリに@builder.io/partytown/libに含まれる以下のファイルをコピーしておく。

@builder.io/partytown/lib/
├── partytown-atomics.js
├── partytown-media.js
├── partytown-sw.js
└── partytown.js

AstroやNext.jsなどではnpmで入れて設定やスニペットを書けばそれで終わりけど、 静的ページの場合はこれらのファイルを入手することから始めないといけない。

まず、@builder.io/partytownを任意のディレクトリに展開しておく。 このディレクトリは作業のためのものなので最終的な静的サイトには含めなくてもよい。 以下はそのディレクトリを作業ディレクトリとする。

最初に以下のコマンドで@builder.io/partytown/lib以下のソースをアセットディレクトリにコピーする。

1npx @builder.io/partytown copylib --no-debug {展開先のパス}

次に以下のコマンドでスニペットを生成して静的ページのHeadタグ内のscriptタグに入れておく(外部ファイルからロードしない理由は謎だけど公式での案内に従っておく)。

1node -e "import('@builder.io/partytown/integration').then(({ partytownSnippet }) => console.log(partytownSnippet({forward:['dataLayer.push'],lib:'ライブラリのパス'})))" 

出力されたスニペットをコピーしておく。 partytownSnippet関数の引数はpartytownに渡す設定値である。今回はGA用に以下のように設定した。

1{
2    forward: ['dataLayer.push'],
3    lib: '/js/partytown',
4}

forwardに入れるパラメータは以下を参考にGA用のものをコピーした。

https://partytown.builder.io/common-services

libに入れるパスは@builder.io/partytown/libを展開したディレクトリのパスをWebサイトのルートからの絶対パスで入れる。 例えばこのブログの場合はhttps://tanstaafl.0pt.jp/js/partytown/というパス以下にライブラリを配置したので/js/partytown/と入れた。 最後の/も忘れずに入れること。

ちなみに上記のコマンドで生成したスニペットは、以下の二つを結合したものと同じである。

  1. window.partytownに上記設定値のオブジェクトを代入するコード
  2. copylibコマンドで展開したライブラリのうちpartytown.jsの中身

そのため直接そのようなコードを書いてもよい。

最後にHTMLのHeadに以下のようにscriptタグを入れる。

 1<head>
 2    <script>
 3        // コピーしたスニペットをここに貼り付ける
 4    </script>
 5    <script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=GタグのID"></script>
 6    <script type="text/partytown">
 7          window.dataLayer = window.dataLayer || [];
 8          function gtag(){dataLayer.push(arguments);}
 9          gtag('js', new Date());
10          gtag('config', 'GタグのID');
11    </script>
12</head>

最初のスニペット以外は、GAの設定例からコピーしたHTMLのうちscriptタグのtype属性にtext/partytownを入れたものを貼り付ける。GタグのIDには自分のものを入れておく。

基本的にはこれだけでGAがWebWorkerで動作する。他のサードパーティスクリプトも同様に設定すればよい。 対応状況などは公式で確認するとよいだろう。

これで早くなったかというとあまり実感はないのだけれど、気分的にすっきりしたので追加してよかったと思う。