Marginalia

Custom ElementsとEventTargetの話

Shadow DOM の Hayato Ito さんと、Custom Elements と EventTarget についてちょっと議論できた話。(ありがとうございました!)


先日、Web Components Cafe で登壇しました。

最近自分の中で Custom Elements の盛り上がりが強くて、 単純な Presentational なコンポーネントだけじゃなく、 ある程度の機能を備えたマイクロアプリケーションとしての Custom Elements をどう設計・運用するか、みたいなところを考えてる。

イベントの話

Custom Elements で分断されたマイクロアプリケーション間でコミュニケーションしようとすると、当然それらの外側にある何かを介するしかなくて、 現実的には何かしらのイベントバスが必要になる。パッと思いつくのは window をイベントバスとして使うケース。

これには問題があって、イベントは文字列で識別されるので、未知のタグやスクリプトから同じ名前のイベントが通知されるおそれがある。

これを解決するためには、そのドメインに閉じた scoped なイベントバスが欲しいという話。

CustomElementRegistry

で、そのスコープって今仕様が議論されている CustomElementRegistry と同じ粒度なんじゃないかと思い、 GitHub にEventTargetRegistryみたいなものがあると良いのでは!?というコメントを書いてみた。

I think scoped root EventTarget also will be needed. Separated elements can only communicate each other via its outer event bus, window. Events are identified by its name as well as elements. So, as the same idea, I guess something like EventTargetRegistry will be important.

https://github.com/w3c/webcomponents/issues/716#issuecomment-383540589

今思うとかなりふわふわしてるコメントだけど、ありがたいことに Shadow DOM の Hayato Ito さんが返信してくれた

@lacolaco Could you kindly give us an example how scoped root EventTarget works? Pseudo-code snippet might be helpful to understand the basic idea.

https://github.com/w3c/webcomponents/issues/716#issuecomment-383780403

改めてユースケースを考えてみると、新しい Registry が必要なことはなくて、CustomElementRegistry そのものが EventTarget になってくれたらよさそうだった。

@hayatoito Just an idea, for example, I think CustomEelementRegistry can be an EventTarget.
const xRegistry = new CustomElementRegistry();class XFoo extends HTMLElement {  constructor() {    super();    this.addEventListener("click", () => {      // dispatch a scoped event      xRegistry.dispatchEvent(new CustomEvent("xEvent"));    });  }}class XBar extends HTMLElement {  constructor() {    super();    // subscribe scoped events    xRegistry.addEventListener("xEvent", () => {      // ...    });  }}xRegistry.define("x-foo", XFoo);xRegistry.define("x-bar", XBar);

これには Hayato Ito さんも同意してくれたんだけど、実は EventTarget って普通に new できることを教えてくれた。

Thanks. Just in case, EventTarget is now constructible. Users can create their own EventTarget and use it for any purpose.

これ知らなかったのですべてひっくり返って「これでいいじゃん(いいじゃん)」になった。ありがとうございます。

new EventTarget()

window や document、Element など addEventListenerできるオブジェクトはみんなEventTargetインターフェースを実装しているんだけど、 実は去年の whatwg DOM Standard のアップデートで、開発者が自由にnew EventTarget() できるようになってた。知らなかった。

ついでにいえば、サブクラスを作ることもできるようになってた。知らなかった。

https://dom.spec.whatwg.org/#dom-eventtarget-eventtarget

MDN にも項目があった。知らなかった。

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/EventTarget

ただ、ブラウザの実装状況はまだそれほどよくない。まだ使いづらい。

まとめ

  • CustomElementRegistry が EventTarget になったら直感的な気がする
  • EventTarget は new できる
  • 現状は自前で EventBus 作る感じになりそう。