ZendeskウェブウィジェットをTurbolinksで使う方法
Posted by Kohei Hayashi onZendeskのオンラインチャットやFAQをウェブサイト上に表示したい時、Zendeskが提供しているウェブウィジェットが非常に便利なのですが、Ruby on RailsのサイトでTurbolinksを使用している場合、そのままでは使えません。最終的には表示することが出来たのですが、解決に至るまでに様々な方法を試したので備忘もかねて記載してみました。解決方法のみ知りたい方は文章の一番下までスクロールください。
Zendesk公式サイトの方法: head内にスクリプトを記述
Turbolinksを使用していない通常のウェブサイトですと、Zendeskの説明にあるようにdocumentのhead部分にスクリプトタグを埋め込むだけで動作します。
<head>
<!-- Start of Zendesk Widget script -->
<script id='ze-snippet' src='https://static.zdassets.com/ekr/snippet.js?key=your_api_key'></script>
<!-- End of Zendesk Widget script -->
</head>
但し、turbolinksが有効になっているサイトの場合、最初のページには表示されますが、2ページ目以降では表示されなくなります。turbolinksはページ遷移の際にDOMのbodyのみを上書きし、headは最初のページロード以降は変化しないので、ここまではturbolinksの特性上、予想可能な事象かと思います。実際、turbolinksを導入すると、Zendeskだけではなくほぼ全てのスクリプトが同じ問題に直面します。この問題は大抵はスクリプトの位置の変更で解決することが出来るので、試してみました。
スクリプトをheadからbody内に移動
Turbolinksはページ遷移するごとにbodyの内容を入れ替えるので、スクリプトロード時に実行されるスクリプトであれば、body内に記述することでページ遷移ごとに毎回実行され問題解決となります。
ZendeskのスクリプトもIIFE(即時実行関数)の形となっておりロードごとに実行されるのでこの方法で解決するかと思いましたが、試したところZendeskの場合はこの方法でもウィジェットが表示されませんでした。
<!-- Start of Zendesk Widget script -->
<script id='ze-snippet' src='https://static.zdassets.com/ekr/snippet.js?key=your_api_key'></script>
<!-- End of Zendesk Widget script -->
</body>
動的にスクリプトをロード
Google tag managerなどで使われている方法です。 turbolinks:loadイベント内で、スクリプトタグを動的に生成すれば良いのではないかと思い、以下のようなコードも試してみましたが、この方法でも2ページ目以降はうまく表示出来ませんでした。
(function(w,d,s,i) {
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s);
j.id = 'ze-snippet';
j.src = 'https://static.zdassets.com/ekr/snippet.js?key=' + i;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'your_api_key');
スクリプトが行っている処理を全てカスタム開発
エンジニアチームからこのような提案もあり、実際にネットで検索するとそのようなソリューションもあるようですが、多大な開発コストがかかる上に、将来的に仕様が変わった際に動く保証がどこにもないので、この案はボツになりました。
Zendeskのドキュメンテーションに記載されている関数を使用してみる
ZendeskのAPI関数を呼び出せば表示出来るのではと思い、ドキュメンテーションに記載されている以下のような関数を試してみました。
/* Open */
zE('webWidget', 'open');
/* Show */
zE('webWidget', 'show');
/* Toggle */
zE('webWidget', 'toggle');
ただ、上記3つの関数でも、結局2ページ目以降では表示されませんでした。
iframe内でウィジェットを表示
あまり美しい方法ではありませんが、bodyのウィジェットを表示したい箇所にiframeを使い、iframe中のhtmlのheadにウィジェットスクリプトを記述する方法はどうかと思い、以下のようなコードも試してみました。
<iframe>
<html>
<head>
<script id='ze-snippet' src='https://static.zdassets.com/ekr/snippet.js?key=your_api_key'></script>
</head>
<body>
</body>
</html>
</iframe>
この方法だと2ページ目以降に遷移しても表示することが出来ましたが、既存のページのレイアウトと整合性を取るのが非常に困難なため、結局この案もボツとなりました。
最終的な解決方法
実際にデバッガーを動かしてスクリプトが行っている処理を一行一行解析してみると、以下のような条件分岐があることに気が付きました。
if (window.zEACLoaded)
return;
このグローバル変数が悪さをしているのではないかと思い、以下のようなコードを書いてみたところ、2ページ目以降もZendeskウィジェットが表示されるようになりました。
*stimulus.jsを使い、disconnect()
でページ遷移直前に処理を行っています。
disconnect() {
window.zEACLoaded = false;
}
要はグローバル変数がスクリプトによって設定されていたため、通常のウェブサイトならページ遷移ごとに全てリセットされますが、turbolinksではページ遷移後も値がtrueのままで保持されてしまっており、処理が中断保持されていたのが原因です。
コーディングをしていて行き詰まった時は、結局のところソースコードを読むのが遠回りなようなようで実は一番速くて確実だという良い例かと思います。