余白

https://blog.lacolaco.net/ に移転しました

Custom ElementsとEventTargetの話

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


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

slides.com

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

イベントの話

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

f:id:lacolaco:20180425101709p:plain

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

f:id:lacolaco:20180425101949p:plain

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

CustomElementRegistry

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

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.

I think I can understand what problem you are trying to solve, but it is unclear to me how EventTargetRegistry works.

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);

f:id:lacolaco:20180425104452p:plain

これには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() できるようになってた。知らなかった。

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

DOM Standard

github.com

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

EventTarget() - Web APIs | MDN

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

f:id:lacolaco:20180425103928p:plain

まとめ

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