GatsbyJS: Google AdSenseを導入するとIE11でscriptが動かない問題を解決する

GatsbyJS: v2.23.3

Google AdSenseを導入する場合は↓のscriptを取り込むわけだが……、

<script async src="http://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>

GatsbyJSでやるとなぜかIE11だけエラー吐いてscriptが壊死する。ページは表示できるがscriptが全部動かなくなる、IEまたお前か。ピュアなReact Appでは起きなかったのでGatsbyJS固有の問題と思われる。

↓こんな感じで取り込んでいるとダメだった。

<Helmet
  script={[
    {src: "//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js", async: "async"},
  ]}
/>

どうやらPolyfillが足りていないらしい。GatsbyJSはデフォルトでBabelしてるからIEもたいていは大丈夫なんだけど、完全ではないようだ。

足りないPolyfillについてはこの記事を参考にさせて頂いた。神なのか?
参考:GatsbyJSのIE 11対処方法

記事にある.babelrcは必須じゃないので私は作らなかった。デフォルトで↓の設定だからIEの需要がある限りは大丈夫かと。0.25%以下になったIEなど切り捨てる。

{
  "browserslist": [">0.25%", "not dead"]
}

参考:Browser Support | GatsbyJS

ただしこの対応だけでは本件は解決しない。

ウザいことにたまに正常に動くようになった。三回に一回くらいだろうか、まぁたまにでも成功するならアプローチはあっているのだろう。ぶっちゃけPolyfill事情はさっぱりわかっていないし、恥ずかしながら告白させてもらえばPolyfillという言葉自体はじめて知ったわけだが。

まぁおそらく追加したPolyfillの取り込みがdeferで、AdSenseがasyncなのが問題なのだろう。Polyfillを取り込む前にAdSenseの問題コードが実行されたらおじゃんになると推測、かんぺき勘だが私はフォースと共にあるので大丈夫。

async、deferについてはこの記事がわかりやすかった。Qiitaってすごいね。
参考:<script> タグに async / defer を付けた場合のタイミング - Qiita

ためしにAdSenseをasyncからdeferにしてみたら治った。100%大丈夫な対応ではない気がするとフォースがささやいているが、少なくとも私の環境では一度もエラーになっていないのでよしとする。私はフォースと共にあるが服従はしない。

<Helmet
  script={[
    {src: "//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js", defer: "defer"},
  ]}
/>

でもさすがにdefer固定にするのはイヤだ。IEのためにまっとうなブラウザまで性能落としたくないので、ひと手間くわえる。

  • IEの場合:Polyfill取り込み&AdSenseをdefer
  • IE以外:Polyfill取り込まない&AdSenseをasync

IE判定してscript取り込む方法はコチラを参考にした。そう、Qiita。
参考:IEのために|IE判定とバベルとポリフィル - Qiita

これやるってなるとHelmetじゃ手に負えないのでhtml.jsをつくる。間違ってたらHelmetさん、すんません。

cp .cache/default-html.js src/html.js

で、よきところにこれを埋め込む。

<script type="text/javascript" dangerouslySetInnerHTML={{ __html: `
  function addScript(path, sync) {
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = path;
    script[sync] = sync;
    document.getElementsByTagName("head")[0].appendChild(script);
  }
  var userAgent = window.navigator.userAgent.toLowerCase();
  if (userAgent.indexOf("msie") !== -1 || userAgent.indexOf("trident") !== -1) {
    addScript("https://polyfill.io/v3/polyfill.min.js?features=fetch%2CPromise", "defer");
    addScript("//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js", "defer");
  } else {
    addScript("//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js", "async");
  }
` }} />

これで動いた。もっとまともな方法があったら教えて頂きたい。