Hookified: Event Emitting and Middleware Hooks

2.1.1 · active · verified Wed Apr 22

Hookified provides a robust solution for integrating event emitting and middleware-style hooks into JavaScript and TypeScript applications. Currently at version 2.1.1, the library maintains an active release cadence, with frequent updates addressing performance, type improvements, and feature enhancements. Key differentiators include its dual support for asynchronous and synchronous middleware hooks, serving as a simple yet powerful EventEmitter replacement. It offers comprehensive support for ESM and CJS module systems, along with TypeScript types and compatibility with Node.js 20+ environments, including browser support via CDN. The library boasts a lean footprint with no external package dependencies and a small size (around 250KB), focusing on fast and efficient execution, as evidenced by its benchmarks. Features like WaterfallHook for data transformation, robust error handling, options for enforcing hook naming conventions (enforceBeforeAfter), and built-in mechanisms for managing deprecated hooks (deprecatedHooks, allowDeprecated) further distinguish its capabilities.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates instantiating Hookified, registering standard and WaterfallHooks, emitting and listening to events, and processing data through the hook lifecycle.

import { Hookified, Hook, WaterfallHook } from 'hookified';

class MyService extends Hookified {
  constructor() {
    super();
    this.data = { count: 0, items: [] };
  }

  async processData(input: string) {
    await this.hook('beforeProcess', input);
    this.data.count++;
    this.data.items.push(input.toUpperCase());
    await this.hook('afterProcess', this.data);
    return this.data;
  }

  async saveData(initialData: any) {
    const processedData = await this.hook('saveData', initialData);
    console.log('Final data saved:', processedData); 
    this.emit('dataSaved', processedData); 
  }
}

const service = new MyService();

// Register a standard hook handler for 'beforeProcess'
service.onHook({ 
  event: 'beforeProcess',
  handler: async (input: string) => {
    console.log(`[Hook: beforeProcess] Input received: ${input}`);
  }
});

// Register another hook for 'afterProcess'
service.onHook('afterProcess', (data: { count: number }) => {
  console.log(`[Hook: afterProcess] Current count: ${data.count}`);
});

// Register a WaterfallHook for 'saveData' to transform data sequentially
const transformHook = new WaterfallHook('saveData', ({ args, results }) => {
  const currentResult = results.length > 0 ? results[results.length - 1].result : args[0];
  const transformed = { ...currentResult, timestamp: Date.now(), processedBy: 'transformHook' };
  console.log('[WaterfallHook: saveData] Data transformed.');
  return transformed;
});
service.onHook(transformHook);

// Register an event listener
service.on('dataSaved', (data) => {
  console.log(`[Event: dataSaved] Event emitted with data: ${JSON.stringify(data)}`);
});

// Run the service
(async () => {
  console.log('--- Starting processData ---');
  await service.processData('hello world');
  await service.processData('hookified');
  console.log('--- Finished processData ---\n');

  console.log('--- Starting saveData ---');
  await service.saveData({ id: 1, value: 'initial' });
  console.log('--- Finished saveData ---');

  // Example of using a hook programmatically (equivalent to onHook but for single use)
  await service.onceHook(new Hook('afterProcess', (data) => {
    console.log(`[Hook: onceHook] Special one-time afterProcess hook triggered with count: ${data.count}`);
  }));
  await service.processData('one-time-hook-test');
})();

view raw JSON →