Universal Middleware Router
raw JSON →middle-router is a universal routing library designed for both client-side and server-side JavaScript applications, allowing URL changes to be processed through a series of asynchronous middleware functions. As of version 2.2.0, it provides a consistent API for managing routing logic across different environments. It distinguishes itself by integrating Koa-style `await next()` patterns for middleware execution, enabling control to flow downstream and then back upstream. This allows for complex lifecycle management around route changes, such as measuring execution time, handling exit conditions, or even prompting before navigation. The library leverages `path-to-regexp` for flexible path matching, similar to Express 4.x, and utilizes `middle-run` for robust middleware orchestration. While the provided examples often showcase integration with frameworks like Express and React, `middle-router` itself is entirely framework-agnostic, offering core routing functionality without imposing external dependencies. It focuses on providing a flexible and powerful middleware-based approach to handling application state changes tied to URLs. Its release cadence is stable, with new features and bug fixes rolled out incrementally.
Common errors
error TypeError: Router is not a function ↓
import Router from 'middle-router' to correctly access the default exported constructor. error Middleware did not call resolve() or throw an error, leading to a hang or timeout. ↓
resolve(viewData), call await next() (if passing control to subsequent middleware), or explicitly throw an error to prevent the routing process from hanging indefinitely. error Invariant Violation: You should not use <Router> outside a <BrowserRouter> ↓
middle-router provides core routing logic. If integrating with React, it supplies the 'view' (e.g., a React element) that you then render with ReactDOM, but it does not replace or depend on react-router-dom. Warnings
gotcha Misunderstanding 'await exiting' lifecycle ↓
breaking Potential changes to middleware signature between major versions ↓
gotcha Client-side routing requires explicit initialization and event handling ↓
Install
npm install middle-router yarn add middle-router pnpm add middle-router Imports
- Router Constructor (ESM) wrong
import { Router } from 'middle-router'correctimport Router from 'middle-router' - Router Constructor (CommonJS) wrong
const { Router } = require('middle-router')correctconst Router = require('middle-router') - Router Instance Creation wrong
import Router from 'middle-router'; const myRouter = new Router();correctimport Router from 'middle-router'; const myRouter = Router();
Quickstart
import Router from 'middle-router';
const appRouter = Router()
.use(async ({ context, next }) => {
const start = Date.now();
console.log(`[Middleware 1] Entering: ${context.url}`);
await next(); // Pass control to the next middleware
const duration = Date.now() - start;
context.totalTime = duration;
console.log(`[Middleware 1] Exiting: ${context.url} (took ${duration}ms)`);
})
.use('/users/:id', async ({ params, resolve, context }) => {
console.log(`[Middleware 2] Matched /users/${params.id}`);
// Simulate async data fetching
await new Promise(res => setTimeout(res, 50));
const userData = { id: params.id, name: `User ${params.id}`, fetchedAt: Date.now() };
resolve(`<h1>User Profile</h1><p>ID: ${userData.id}</p><p>Name: ${userData.name}</p><p>Fetched at: ${userData.fetchedAt}</p>`);
console.log(`[Middleware 2] Resolved for /users/${params.id}`);
})
.use(async ({ resolve, context }) => {
console.log(`[Middleware 3] Default catch-all for: ${context.url}`);
resolve(`<h1>Welcome</h1><p>No specific route matched for ${context.url}.</p>`);
});
async function runExample() {
console.log('--- Routing /users/123 ---');
const userView = await appRouter.route('/users/123', { initialData: '...' });
console.log('Resolved View:', userView);
console.log('\n--- Routing /about ---');
const aboutView = await appRouter.route('/about');
console.log('Resolved View:', aboutView);
console.log('\n--- Routing / ---');
const homeView = await appRouter.route('/');
console.log('Resolved View:', homeView);
}
runExample();