JavaScript Middleware Pattern Implementation
raw JSON →js-middleware is a versatile JavaScript library designed to implement a powerful middleware pattern, allowing developers to inject custom logic into the execution flow of any object's methods. It aims to bring the scalability and maintainability benefits seen in frameworks like ReduxJS and ExpressJS to general-purpose JavaScript objects. The package is currently at version 0.3.1, with a recent patch 0.3.2, indicating it's actively maintained, though possibly with a slower release cadence. Its primary differentiator is the ability to apply middleware to arbitrary methods of any class or object instance, providing a flexible mechanism to modify arguments, perform side effects, or control method execution. This approach fosters highly modular and testable code by separating cross-cutting concerns from core business logic, making it suitable for extending existing objects without direct modification.
Common errors
error TypeError: next is not a function ↓
target => next => (...args) => { /* ... */ return next(...args); } signature. Double-check that next is correctly passed and invoked. error Target function 'myMethod' not called / Process hangs indefinitely ↓
next(...args) is called in each middleware unless an explicit termination of the chain is intended (e.g., for short-circuiting). error Middleware not applying to 'my_internal_method' ↓
middlewareMethods property in a middleware object/class passed to use(). Warnings
gotcha Failing to call `next()` within a middleware function will halt the middleware chain and prevent the original target function from executing. This can lead to silent failures or processes hanging indefinitely. ↓
gotcha By default, methods on the target object that start or end with an underscore (`_method` or `method_`) are excluded from middleware application. This is a design choice to prevent unintended interception of internal methods. ↓
gotcha Middleware functions can directly mutate the arguments passed to them, which can lead to unexpected side effects if not handled carefully. The pattern allows for modification, but consumers should be aware of this potential for state changes. ↓
gotcha The current implementation examples primarily demonstrate synchronous middleware. While it might be possible to integrate asynchronous operations, the provided `next()` mechanism is synchronous. Expecting `await next()` without specific async handling by the library could lead to issues. ↓
gotcha When using the library in a browser environment by including `dist/middleware.min.js`, the `MiddlewareManager` constructor is exposed as `window.MiddlewareManager`. This global variable could potentially clash with other libraries that also define `MiddlewareManager` globally. ↓
Install
npm install js-middleware yarn add js-middleware pnpm add js-middleware Imports
- MiddlewareManager wrong
import MiddlewareManager from 'js-middleware';correctimport { MiddlewareManager } from 'js-middleware'; - MiddlewareManager (CommonJS) wrong
const MiddlewareManager = require('js-middleware');correctconst { MiddlewareManager } = require('js-middleware'); - MiddlewareManager (Browser Global)
const manager = new window.MiddlewareManager(targetObject);
Quickstart
class Person {
walk(step) {
this.step = step;
console.log(`Person walked ${step} steps.`);
}
speak(word) {
this.word = word;
console.log(`Person spoke: ${word}`);
}
}
const logger = target => next => (...args) => {
console.log(`[Logger Middleware] Calling ${target.constructor.name}'s method with args: ${JSON.stringify(args)}.`);
const result = next(...args);
console.log(`[Logger Middleware] Method finished.`);
return result;
};
const argModifier = target => next => (step) => {
if (typeof step === 'number') {
step = step * 2; // Double the steps
console.log(`[ArgModifier Middleware] Doubling steps to: ${step}`);
}
return next(step);
};
const p = new Person();
const middlewareManager = new MiddlewareManager(p);
middlewareManager.use('walk', logger);
middlewareManager.use('walk', argModifier);
console.log('--- Calling walk (with middleware) ---');
p.walk(5); // Will log 'walk start, steps: 5.', 'Doubling steps to: 10', 'Person walked 10 steps.', 'walk end.'
middlewareManager.use('speak', logger);
console.log('\n--- Calling speak (with middleware) ---');
p.speak('Hello World');