Redux Replaceable Middleware

raw JSON →
1.1.0 verified Thu Apr 23 auth: no javascript abandoned

Redux Replaceable Middleware is a utility that provides a mechanism to dynamically replace active Redux middleware instances at runtime. Published approximately 8 years ago, its current stable version is 1.1.0, and it appears to be abandoned, with no recent updates or active maintenance. This package was designed for earlier versions of Redux (specifically peer-depending on Redux v2, v3, or v4), and its core differentiation lies in enabling modification of the middleware chain after the Redux store has been created. In contrast, standard Redux practice involves defining the middleware chain once during store creation. Modern Redux applications, especially those using Redux Toolkit, typically manage asynchronous logic and side effects through patterns like Redux Thunk, Redux Saga, or Redux Toolkit's `createAsyncThunk` and listeners, rather than dynamic middleware replacement.

error TypeError: ReplaceableMiddleware is not a function
cause The imported `ReplaceableMiddleware` is a factory function, not the middleware itself. It must be called to create the middleware instance.
fix
Ensure you call the imported function to get the middleware: const replaceableMiddleware = ReplaceableMiddleware();
error Error [ERR_REQUIRE_ESM]: require() of ES Module ... Not supported in ES module scope
cause Attempting to `require()` this CommonJS-only package within an ES module file, or trying to `import` it when the package only offers CommonJS exports.
fix
If your project is ESM, you might need to run it in a CommonJS context, or use a dynamic import() statement if supported, though the package itself does not provide ESM exports. It's generally recommended to use actively maintained alternatives that support modern module systems.
error TypeError: Cannot read properties of undefined (reading 'dispatch')
cause The `replaceableMiddleware.options` property might not be set or accessed correctly, or the middleware was not properly applied to a Redux store.
fix
Ensure the middleware is correctly passed to Redux.applyMiddleware during store creation. The options object is populated by Redux and available within the middleware's replaceBy function or through replaceableMiddleware.options after the store is created.
breaking This package is designed for Redux versions 2.x, 3.x, and 4.x. It may not be compatible with Redux v5 or later, especially when used with Redux Toolkit's `configureStore`, which has different middleware handling.
fix Consider migrating to Redux Toolkit and using alternative patterns for dynamic logic, such as `createAsyncThunk`, `createListenerMiddleware`, or dynamically combining reducers/slices, rather than dynamically replacing middleware. If you must use dynamic middleware, explore modern alternatives like `@reduxjs/toolkit/query`'s listener middleware or `redux-dynamic-middlewares` (though also check its maintenance status).
gotcha This package is CommonJS-only and does not provide ES module exports. Attempting to use `import` statements will result in runtime errors in environments that enforce ESM.
fix Always use `const ReplaceableMiddleware = require('redux-replaceable-middleware');` to import this package. If your project is ESM-only, you may need to use a CommonJS wrapper or reconsider using this abandoned package.
deprecated The package is effectively abandoned, with its last update being 8 years ago. It lacks maintenance, security updates, and compatibility with modern JavaScript features or contemporary Redux practices (e.g., Redux Toolkit, TypeScript).
fix Avoid using this package in new projects. For existing projects, evaluate the necessity of dynamic middleware replacement and consider migrating to actively maintained Redux patterns or libraries that achieve similar results in a more robust and supported manner.
gotcha This package does not ship with TypeScript type definitions. Using it in a TypeScript project will require manually declaring types or ignoring type errors, reducing type safety.
fix If integrating into a TypeScript project, you will need to create a declaration file (e.g., `redux-replaceable-middleware.d.ts`) to provide types for `ReplaceableMiddleware` and its methods, or use `@ts-ignore` at import sites.
npm install redux-replaceable-middleware
yarn add redux-replaceable-middleware
pnpm add redux-replaceable-middleware

This quickstart demonstrates how to initialize the Redux store with `redux-replaceable-middleware` and then dynamically swap out an active middleware at runtime. It shows an initial logging middleware being replaced by one that modifies action types. This example uses CommonJS syntax consistent with the package's age.

const Redux = require('redux');
const ReplaceableMiddleware = require('redux-replaceable-middleware');

// A dummy reducer
const reducer = (state = { value: 0 }, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, value: state.value + 1 };
    case 'DECREMENT':
      return { ...state, value: state.value - 1 };
    default:
      return state;
  }
};

// Initial middleware (logs actions)
const loggingMiddleware = store => next => action => {
  console.log('OLD Middleware: Dispatching', action.type, 'payload:', action.payload);
  const result = next(action);
  console.log('OLD Middleware: Next state', store.getState());
  return result;
};

// Create the replaceable middleware instance
const replaceableMiddleware = ReplaceableMiddleware(loggingMiddleware);

// Create the store with the replaceable middleware
const store = Redux.createStore(
  reducer,
  Redux.applyMiddleware(replaceableMiddleware)
);

console.log('Initial state:', store.getState());
store.dispatch({ type: 'INCREMENT' });

// New middleware (adds a prefix to action type)
const newMiddleware = store => next => action => {
  console.log('NEW Middleware: Pre-processing action', action.type);
  const newAction = { ...action, type: `PREFIX_${action.type}` };
  const result = next(newAction);
  console.log('NEW Middleware: Post-processing action', newAction.type);
  return result;
};

console.log('\nReplacing middleware in 1 second...');
setTimeout(() => {
  replaceableMiddleware.replaceBy(newMiddleware);
  console.log('Middleware replaced! Dispatching again...');
  store.dispatch({ type: 'DECREMENT' });
  store.dispatch({ type: 'INCREMENT' });
  console.log('Final state:', store.getState());
}, 1000);