EventEmitterのようにPub/Subを行うeventmitという小さなライブラリを書きました。

eventmitは、TypeScriptで書かれています。 また、Node.jsのEventEmitterなどとは違って、イベント一つに対してeventmitのオブジェクトを一つ作成して使います。

import { eventmit } from "eventmit";
const event = eventmit<{ key: string }>();
// Register handler
event.on((value) => {
    console.log(1, value);
});
event.on((value) => {
    console.log(2, value);
});
// Invoke handler
event.emit({
    key: "value"
});
// Unregister handler
event.offAll();

サイズもだいたい200Byteぐらいなので、たいして気になるサイズではないと思います。

bundle size 200Byte

インストール

npmなどからインストールできます。

npm install eventmit

ES Modulesとかも公開してあるのでDenoとかからでも使えると思います。(READMEに使い方を追加するPR待っています)

また、eventmitはES2015のSetを使っているので、ES2015をサポートしている実行環境が必要です。

背景

今までNode.jsのeventsを使うことが多かったです。

しかし、最近はwebpack 5でNode.jsのコアモジュールのpolyfillはされなくなる点やReact Nativeのビルドでも同様に設定しないとeventsなどは利用できません。

また、webpackなどはeventsのpolyfillとしてGozala/eventsを利用するのですが、Node.js側の実装とのズレがしばしば起きているという問題があります。

そのためNode.jsのeventsモジュールはUniversalなモジュールではなくなっていると思います。

一方で、ブラウザのEventEmitter的なものであるEventTargetをNode.jsへ実装する動きもあります。これはAbortControllerEventTargetに依存するためです。

そのため、EventTargetがブラウザとNode.jsどちらでも動くAPIとして将来使える可能性はあります。

この辺を考えるのが面倒になってしまったので、eventmitという小さなライブラリを作ることしました。

eventemitのソースコードは、全部貼り付けると次のような感じです。

var n = function () {var n = new Set();return { on: function (t) {n.add(t);}, off: function (t) {n.delete(t);}, offAll: function () {n.clear();}, emit: function (t) {n.forEach(function (n) {return n(t);});} };};export { n as eventmit };

React Hooksから使うもいつの間にか作られていました。

複数のイベントtypeを取りたい場合はmittというライブラリがそれを提供してるので、こちらを使うといいかもしれません。

mittを使わなかったのは、型定義がゆるい感じだったためです。 一応Conditional Typesを使えば強めの型も書けますが、一つのEventEmitterで複数のイベントを扱いたい理由もなかったので、もっと単純で型安全なeventmitを作ったという感じです。