Event Emitting and Middleware Hooks
Features
- Simple replacement for EventEmitter
- Async / Sync Middleware Hooks for Your Methods
- ESM / CJS with Types and Nodejs 20+
- Browser Support and Delivered via CDN
- Maintained on a regular basis!
Installation
npm install hookified --save
Usage
This was built because we constantly wanted hooks and events extended on libraires we are building such as Keyv and Cacheable. This is a simple way to add hooks and events to your classes.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodEmittingEvent() {
this.emit('message', 'Hello World'); //using Emittery
}
//with hooks you can pass data in and if they are subscribed via onHook they can modify the data
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
// do something
await this.hook('before:myMethod2', data);
return data;
}
}
You can even pass in multiple arguments to the hooks:
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
let data2 = { some: 'data2' };
// do something
await this.hook('before:myMethod2', data, data2);
return data;
}
}
Using it in the Browser
<script type="module">
import { Hookified } from 'https://cdn.jsdelivr.net/npm/hookified/dist/browser/index.js';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodEmittingEvent() {
this.emit('message', 'Hello World'); //using Emittery
}
//with hooks you can pass data in and if they are subscribed via onHook they can modify the data
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
// do something
await this.hook('before:myMethod2', data);
return data;
}
}
</script>
if you are not using ESM modules, you can use the following:
<script src="https://cdn.jsdelivr.net/npm/hookified/dist/browser/index.global.js"></script>
<script>
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodEmittingEvent() {
this.emit('message', 'Hello World'); //using Emittery
}
//with hooks you can pass data in and if they are subscribed via onHook they can modify the data
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
// do something
await this.hook('before:myMethod2', data);
return data;
}
}
</script>
API - Hooks
.onHook(eventName, handler)
Subscribe to a hook event.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
// do something
await this.hook('before:myMethod2', data);
return data;
}
}
const myClass = new MyClass();
myClass.onHook('before:myMethod2', async (data) => {
data.some = 'new data';
});
.onceHook(eventName, handler)
Subscribe to a hook event once.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
// do something
await this.hook('before:myMethod2', data);
return data;
}
}
const myClass = new MyClass();
myClass.onHookOnce('before:myMethod2', async (data) => {
data.some = 'new data';
});
myClass.myMethodWithHooks();
console.log(myClass.hooks.length); // 0
.removeHook(eventName)
Unsubscribe from a hook event.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
// do something
await this.hook('before:myMethod2', data);
return data;
}
}
const myClass = new MyClass();
const handler = async (data) => {
data.some = 'new data';
};
myClass.onHook('before:myMethod2', handler);
myClass.removeHook('before:myMethod2', handler);
.hook(eventName, ...args)
Run a hook event.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
// do something
await this.hook('before:myMethod2', data);
return data;
}
}
in this example we are passing multiple arguments to the hook:
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
let data2 = { some: 'data2' };
// do something
await this.hook('before:myMethod2', data, data2);
return data;
}
}
const myClass = new MyClass();
myClass.onHook('before:myMethod2', async (data, data2) => {
data.some = 'new data';
data2.some = 'new data2';
});
await myClass.myMethodWithHooks();
.hooks
Get all hooks.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
// do something
await this.hook('before:myMethod2', data);
return data;
}
}
const myClass = new MyClass();
myClass.onHook('before:myMethod2', async (data) => {
data.some = 'new data';
});
console.log(myClass.hooks);
.getHooks(eventName)
Get all hooks for an event.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
// do something
await this.hook('before:myMethod2', data);
return data;
}
}
const myClass = new MyClass();
myClass.onHook('before:myMethod2', async (data) => {
data.some = 'new data';
});
console.log(myClass.getHooks('before:myMethod2'));
.clearHooks(eventName)
Clear all hooks for an event.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodWithHooks() Promise<any> {
let data = { some: 'data' };
// do something
await this.hook('before:myMethod2', data);
return data;
}
}
const myClass = new MyClass();
myClass.onHook('before:myMethod2', async (data) => {
data.some = 'new data';
});
myClass.clearHooks('before:myMethod2');
API - Events
.on(eventName, handler)
Subscribe to an event.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodEmittingEvent() {
this.emit('message', 'Hello World');
}
}
const myClass = new MyClass();
myClass.on('message', (message) => {
console.log(message);
});
.off(eventName, handler)
Unsubscribe from an event.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodEmittingEvent() {
this.emit('message', 'Hello World');
}
}
const myClass = new MyClass();
myClass.on('message', (message) => {
console.log(message);
});
myClass.off('message', (message) => {
console.log(message);
});
.emit(eventName, ...args)
Emit an event.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodEmittingEvent() {
this.emit('message', 'Hello World');
}
}
.listeners(eventName)
Get all listeners for an event.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodEmittingEvent() {
this.emit('message', 'Hello World');
}
}
const myClass = new MyClass();
myClass.on('message', (message) => {
console.log(message);
});
console.log(myClass.listeners('message'));
.removeAllListeners(eventName)
Remove all listeners for an event.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodEmittingEvent() {
this.emit('message', 'Hello World');
}
}
const myClass = new MyClass();
myClass.on('message', (message) => {
console.log(message);
});
myClass.removeAllListeners('message');
.setMaxListeners(maxListeners: number)
Set the maximum number of listeners and will truncate if there are already too many.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
async myMethodEmittingEvent() {
this.emit('message', 'Hello World');
}
}
const myClass = new MyClass();
myClass.setMaxListeners(1);
myClass.on('message', (message) => {
console.log(message);
});
myClass.on('message', (message) => {
console.log(message);
}); // this will not be added and console warning
console.log(myClass.listenerCount('message')); // 1
.once(eventName, handler)
Subscribe to an event once.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
}
const myClass = new MyClass();
myClass.once('message', (message) => {
console.log(message);
});
myClass.emit('message', 'Hello World');
myClass.emit('message', 'Hello World'); // this will not be called
.prependListener(eventName, handler)
Prepend a listener to an event. This will be called before any other listeners.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
}
const myClass = new MyClass();
myClass.prependListener('message', (message) => {
console.log(message);
});
.prependOnceListener(eventName, handler)
Prepend a listener to an event once. This will be called before any other listeners.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
}
const myClass = new MyClass();
myClass.prependOnceListener('message', (message) => {
console.log(message);
});
myClass.emit('message', 'Hello World');
.eventNames()
Get all event names.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
}
const myClass = new MyClass();
myClass.on('message', (message) => {
console.log(message);
});
console.log(myClass.eventNames());
.listenerCount(eventName?)
Get the count of listeners for an event or all events if evenName not provided.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
}
const myClass = new MyClass();
myClass.on('message', (message) => {
console.log(message);
});
console.log(myClass.listenerCount('message')); // 1
.rawListeners(eventName?)
Get all listeners for an event or all events if evenName not provided.
import { Hookified } from 'hookified';
class MyClass extends Hookified {
constructor() {
super();
}
}
const myClass = new MyClass();
myClass.on('message', (message) => {
console.log(message);
});
console.log(myClass.rawListeners('message'));
Development and Testing
Hookified is written in TypeScript and tests are written in vitest
. To run the tests, use the following command:
To setup the environment and run the tests:
npm i && npm test
To contribute follow the Contributing Guidelines and Code of Conduct.
License
Latest's Releases
What's Changed
- adding in jsdelivr url to stats by @jaredwray in https://github.com/jaredwray/hookified/pull/24
- upgrading vitest to 2.1.5 by @jaredwray in https://github.com/jaredwray/hookified/pull/25
- upgrading docula to 0.9.5 by @jaredwray in https://github.com/jaredwray/hookified/pull/26
- migrating IEventEmitter to the same file as eventified by @jaredwray in https://github.com/jaredwray/hookified/pull/27
- Updating gitignore for pnpm and version bump to 1.5.1 by @jaredwray in https://github.com/jaredwray/hookified/pull/28
Full Changelog: https://github.com/jaredwray/hookified/compare/v1.5.0...v1.5.1
What's Changed
- adding in jsdoc by @jaredwray in https://github.com/jaredwray/hookified/pull/18
- adding in sync handler for hooks by @jaredwray in https://github.com/jaredwray/hookified/pull/19
- upgrading vitest to 2.1.4 by @jaredwray in https://github.com/jaredwray/hookified/pull/20
- upgrading docula to 0.9.4 by @jaredwray in https://github.com/jaredwray/hookified/pull/21
- upgrading tsup to 8.3.5 by @jaredwray in https://github.com/jaredwray/hookified/pull/22
- adding in onceHook by @jaredwray in https://github.com/jaredwray/hookified/pull/23
Full Changelog: https://github.com/jaredwray/hookified/compare/v1.4.0...v1.5.0
What's Changed
- Adding in IEventEmitter by @jaredwray in https://github.com/jaredwray/hookified/pull/17
Full Changelog: https://github.com/jaredwray/hookified/compare/v1.3.0...v1.4.0