タイトルで言い切ったやつなんですけど、詳細を書いていきます。
Salesforce上の Lightning Web Components(以下LWC)で、FullCalendar を使ったものを作ろうとしていて詰まった&あんまりドキュメント見つけられなかったのでやったことを忘れないようにまとめておきます。
起きたこと
現状の結論としては、LWCの this.template.querySelector は Element じゃないっぽいのでpollyfillでこんな感じに書いていると Illegal invocation
が出るぽい
const matchesMethod = Element.prototype.matches || (Element.prototype as any).matchesSelector || (Element.prototype as any).msMatchesSelector const closestMethod = Element.prototype.closest || function (selector) { // polyfill let el = this if (!document.documentElement.contains(el)) { return null } do { if (elementMatches(el, selector)) { return el } el = el.parentElement || el.parentNode } while (el !== null && el.nodeType === 1) return null }
細かく検証出来ていないのですが、LWC側でこういった感じでFullCalendarを使おうと思った時に私の環境では発生しました
let calendarEl = this.template.querySelector('[data-id="ScheduleAdjustmentCalendar"]'); new FullCalendar.Calendar(calendarEl, { plugins: ['dayGrid'] }).render();
こうやって対策してみた
私の場合は元ライブラリをforkしてブランチを切ってそこから静的リソースに持ってくるようにしてしまいました。 compareこんな感じです
if (typeof el.matches === 'function') { return el.matches(selector) }
みたいに回避しちゃいました。もっといい解決策ありそうだけど。。。誰か教えて!
細かく見ていないけどきっとこうなんじゃないか仮設
Illegal invocation
が出る時って「不正な呼び出し」なので違うクラスの同じメソッドをcallで呼ぼうとした時とかに出るぽいので、
今回の場合 Element.prototype.closest
とか Element
クラスのメソッドだと思って呼んでいるけど、呼んだクラスが Element
じゃない時に発生するんじゃないかなと。
事象の項にも書きましたが、おそらくですが、普通にWebサイト作ってJS呼んだときの document.querySelector
は Element
とか HTMLElement
が返ってくるけど、LWCの this.template.querySelector
はLWC独自のなにかしらのProxy的なクラスが返ってくる(HTMLElementと同等のAPIを持っているか移譲しているかはわからない)から、今回のような pollyfillで書いたコードでエラーが発生してしまうのではないかなと思っております。(これ参考文献探したけど見つけられなかったので、あくまでも推測です。)
とはいえ直接呼べるなら呼んじゃえばいいじゃん。と思って typeof el.closest
が function
だったらそれをそのまま呼んじゃえって書いてます。
いくつもの環境で試すとかはまだ出来ていないのですが今回はSalesforce上のLightningWebComponent上に限った話なのでこのまま行こうかなって気持ちです。