これは何
先日自分のブログにGoogleAdSenseを導入しました。
申請してから承認されるまで待たされたり、承認された後もGoogleからサイトが認識されるまで時間がかかったりともどかしい日々が続きましたが、一週間程度で問題なく広告が表示されるようになっていました。
今回は、GatsbyサイトにGoogleAdSenseを導入する方法、特にGatsbyのSSRに対応する方法や、表示される画面のサイズに応じて広告の表示非表示を切り替える方法などをまとめていきます。
なお、GoogleAdSenseに自身のサイトを登録する方法などは検索すればいろんなサイトで紹介されていると思いますので今回は省略させて頂きます。
gatsby-plugin-google-adsense
GoogleAdSenseをサイトに導入するためには、適当なscriptタグをヘッダに追加する必要があります。
それをしてくれるのがgatsby-plugin-google-adsense | GatsbyJSというプラグインです。
npmやyarnでインストールして、gatsby-config.jsに以下の設定を書き加えます。
plugins: [
{
resolve: `gatsby-plugin-google-adsense`,
options: {
publisherId: `ca-pub-xxxxxxxxxx`
},
},
]
プラグインの代わりにreact-helmetを用いても、ヘッダにscriptタグを挿入できるのですが、react-helmetではdata-react-helemt="true"というプロパティが自動的に付与されてしまい、AdSenseのスクリプトで「なんかよく分かんないプロパティが追加されているぞ」と怒られてしまったので、最終的にプラグインを用いることにしました。
AdSenseコンポーネント
あとは広告を表示したい部分に適当なdom要素を追加していきます。
AdSenseでは適当なプロパティが設定されたins要素を配置することで広告が表示される場所を指定できます。
しかし、ただins要素を配置しただけでは広告は表示されません。ins要素がdomツリーに追加されたことをAdSenseスクリプトに知らせるため以下のjavascirptコードを実行する必要があります。
window.adsbygoogle = window.adsbygoogle || []
window.adsbygoogle.push({})
windowオブジェクトに新しく追加されたadsbygoogleプロパティとinsタグの関係については以下のサイトが参考になります。
Fix Google AdSense loading issues with React - M@0_T55 - Medium
要するに追加されたins要素と同じ数だけadsbygoogleに空のオブジェクトをpushしなければならないようです。
これらの規則を加味するとReactコンポーネントは以下のようになります。
const AdSense = ({ format = "auto" }) => {
useEffect(() => {
if (window) {
window.adsbygoogle = window.adsbygoogle || []
window.adsbygoogle.push({})
}
})
return (
<div>
<Ins
className="adsbygoogle"
data-ad-client="ca-pub-xxxxxxxxxxxxxxx"
data-ad-slot="xxxxxxxx"
data-ad-format={format}
/>
</div>
)
}
const Ins = styled.ins`
display: block
`
GatsbyではSSRにより、javascriptコードがサーバー側でhtmlをビルドする時とブラウザに読み込まれた時の二回実行されます。
クライアントがサイトにアクセスした際は、事前にビルドしたhtmlを表示させて初回読み込み時間を短縮させつつ、React要素ツリーが構築できたらそれを実DOMツリーにhydrateするという仕組みになっているそうです。
サーバー側でhtmlをレンダリングするときは、windowやdocumentなどのオブジェクトにアクセス出来ないので、if文を使ってブラウザ側でのみコードが実行されるようにします。
また、userEffect hookを用いてDOMツリーが構築された後にコードが実行されるようにしています。(クラスコンポーネントを使用している場合はuseEffect内の中身をcomponentDidMountに移せば問題なく作動します。)
レスポンシブ対応
画面サイズによって広告の表示非表示を切り替えたかったので以下のResponsiveAdSenseを作成しました。
一回目のマウント時にwindowから画面の幅を取得し、setStaetを呼び出すことでコンポーネントの再構築を行い、広告を表示させるようにしています。
AdSense.Responsive = ({ format = "auto" }) => {
const [state, setState] = useState({ showAds: false })
useEffect(() => {
if (state.showAds) {
window.adsbygoogle = window.adsbygoogle || []
window.adsbygoogle.push({})
}
if (window) {
const minWidth = responsive.tablet.minWidth // 769
const shouldShowAds = window.innerWidth >= minWidth
if (shouldShowAds) {
setState({ showAds: true })
}
}
}, [state.showAds])
if (!state.showAds) return null
return (
<div>
<Ins
className="adsbygoogle"
data-ad-client="ca-pub-xxxxxxxxxxxxxxxxxxx"
data-ad-slot="xxxxxxxxxx"
data-ad-format={format}
/>
</div>
)
}
const Ins = styled.ins({
display: "block"
})