@collidor/event

中文文档
4.7.2发布于 2026/10/09MITTypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 7900

A small library to create, register and listen to events.

原始使用文档
文档目录14 节
  1. Installation
  2. Core Features
  3. Basic Usage
  4. Using Class Inheritance
  5. Using createEvent (Bundler / Minification Safe)
  6. Cross-Context Patterns
  7. 1. BroadcastChannel (Tab-to-Tab)
  8. 2. SharedWorker (Multi-Context)
  9. Advanced Patterns
  10. Context Propagation
  11. API Overview
  12. EventBus
  13. PortChannel
  14. Development

@collidor/event

Codecov npm version License: MIT

A lightweight event system with cross-context communication. Perfect for modern web apps, workers, and distributed systems.


Installation

npm install @collidor/event

Core Features

  • Class-based event system with strict typing
  • Cross-context communication (Window ↔ Worker ↔ Tab)
  • Built-in support for BroadcastChannel/SharedWorker
  • Context propagation & AbortController integration

Basic Usage

Using Class Inheritance

import { Event } from "@collidor/event";

class UserUpdate extends Event<{ id: string }> {}
class SystemAlert extends Event<string> {}
import { EventBus } from "@collidor/event";

const bus = new EventBus();

// Subscribe
bus.on(UserUpdate, (data) => {
  console.log(`User ${data.id} updated`);
});

// Publish
bus.emit(new UserUpdate({ id: "123" }));

Using createEvent (Bundler / Minification Safe)

When bundling for production, JavaScript minifiers often mangle class names (e.g. class UserUpdate becomes class a). Since the event bus and channels (PortChannel, WindowCustomEventPort) route and serialize events using their constructor name, createEvent provides a type-safe way to define events with a fixed, unminifiable name:

import { createEvent, EventBus } from "@collidor/event";

// Define event with explicit payload type and name: createEvent<PayloadType>("EventName")
export const UserUpdate = createEvent<{ id: string }>("UserUpdate");

// Void events (no arguments required):
export const UserLoggedOut = createEvent<void>("UserLoggedOut");

const bus = new EventBus();

bus.on(UserUpdate, (data) => {
  console.log(`User ${data.id} updated`);
});

bus.on(UserLoggedOut, () => {
  console.log("User logged out");
});

bus.emit(new UserUpdate({ id: "123" }));
bus.emit(new UserLoggedOut());

Cross-Context Patterns

The PortChannel is the main exported channel, it accepts MessagePortLike ports, which have a postMessage method, and can set and use a onmessage property callback. This means that the browsers APIs like BroadcastChannel, Worker and SharedWorker will work by default.

My plan is to add adapters later so other things can behave like ports, like Websockets, WebRTC, Http+SEE and Datagrams.

The PortChannel will not emit events to ports that didn't send a message first telling that it has a subscriber for such event.

1. BroadcastChannel (Tab-to-Tab)

import { PortChannel, EventBus } from "@collidor/event";

const channel = new PortChannel();
const bus = new EventBus({ channel });
channel.addPort(new BroadcastChannel("app-channel"));

class TabMessage extends Event<string> {}
bus.emit(new TabMessage("Hello from Tab A!"));
import { PortChannel, EventBus } from "@collidor/event";

const channel = new PortChannel();
const bus = new EventBus({ channel });
channel.addPort(new BroadcastChannel("app-channel"));

bus.on(TabMessage, (msg) => {
  console.log("Received:", msg); // "Hello from Tab A!"
});

2. SharedWorker (Multi-Context)

import { PortChannel, EventBus } from "@collidor/event";

const channel = new PortChannel();
const bus = new EventBus({ channel });
const worker = new SharedWorker("worker.js");

channel.addPort(worker.port);

class TaskEvent extends Event<{ id: string }> {}
bus.emit(new TaskEvent({ id: "shared-task" }));
import { PortChannel, EventBus } from "@collidor/event";

const channel = new PortChannel();
const bus = new EventBus({ channel });

// Handle new connections
self.onconnect = (event) => {
  const port = event.ports[0];
  channel.addPort(port);
};

self.start();

bus.on(TaskEvent, ({ id }) => {
  console.log("Processing shared task:", id);
});

Advanced Patterns

Context Propagation

const bus = new EventBus({
  context: { requestId: "123" }
});

bus.on(DataEvent, (data, ctx) => {
  console.log(ctx.requestId); // "123"
});

// Override per emission
bus.emit(new DataEvent(), { requestId: "temp" });

API Overview

EventBus

  • on(event, handler, signal?)
  • off(event, handler)
  • emit(event, context?)
  • emitByName(name, data, context?)

PortChannel

  • addPort(port)
  • removePort(port)
  • publish(event)
  • subscribe(name, callback)
  • unsubscribe(name, callback)

PortChannel sequence diagram

sequenceDiagram
    participant S as Server PortChannel
    participant MP as MessagePort
    participant C as Client PortChannel

    %% Server adds a MessagePort (acts as connecting port)
    S->>MP: addPort(port)
    Note over S,MP: Server attaches MessagePort

    %% MessagePort forwards startEvent to the Client
    MP->>C: onmessage({type: "startEvent"})
    Note over C: Client receives startEvent and sets up message handlers

    %% Client subscribes to "TestEvent"
    C->>MP: postMessage({type:"subscribeEvent", name:"TestEvent"})
    Note over C: Client tells that it has a subscription for "TestEvent"

    %% MessagePort delivers subscribeEvent to Server
    MP->>S: onmessage({type:"subscribeEvent", name:"TestEvent"})
    Note over S: Server calls addPortSubscription("TestEvent")

    %% If the Server had buffered events for "TestEvent", flush them:
    alt Buffered events exist for "TestEvent"
      S->>MP: postMessage(buffered dataEvent for "TestEvent")
      MP->>C: onmessage(buffered dataEvent for "TestEvent")
    else
      Note over S: No buffered events to flush
    end

    %% Now, the Server publishes a new event "TestEvent"
    S->>S: publish("TestEvent", data)
    alt Subscriber exists
      S->>MP: postMessage({type:"dataEvent", name:"TestEvent", data})
      MP->>C: onmessage({type:"dataEvent", name:"TestEvent", data})
      Note over C: Client processes the dataEvent
    else
      S->>S: Buffer event "TestEvent" with timeout
      Note over S: Event buffered until a subscriber appears
    end


Development

# Install dependencies
npm install

# Run tests (requires Deno)
npm test

# Build project
npm run build

MIT License | © 2024 Alykam Burdzaki Report Issues

版本与发布记录

@collidor/event 共发布 56 个版本,首次发布于 2025/02/10;过去 12 个月发布了 9 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
4.7.2latest2026/10/091 个月前
4.7.12026/10/091 个月前
4.7.02026/10/021 个月前
4.6.02026/10/021 个月前
4.5.02026/09/261 个月前
4.4.02026/09/251 个月前

关于 @collidor/event 的常见问题

@collidor/event 是什么?

A small library to create, register and listen to events.

如何安装 @collidor/event?

在项目目录运行 npm install @collidor/event,或使用 pnpm add / yarn add / bun add。

@collidor/event 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@collidor/event 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@collidor/event 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@collidor/event 可以商用吗?

@collidor/event 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@collidor/event 的下载量有多少?

根据 npm 官方下载统计,@collidor/event 在 2026/10/11 – 2026/11/09 这 30 天内被下载 7,900 次,日均约 263 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@collidor/event 还在维护吗?

最新版本 4.7.2 发布于 2026/10/09(1 个月前);至今共发布 56 个版本,其中过去 12 个月发布了 9 个;首次发布于 2025/02/10。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。