
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Fast, unopinionated, minimalist client-side routing library inspired by the simplicity and flexibility of express middlewares
Fast, unopinionated, minimalist client-side routing library inspired by the simplicity and flexibility of express middlewares.
Essentially, give prouter a list of path expressions (routes) and a callback function (handler) for each one, and prouter will automatically invoke these callbacks according to the active path in the URL.
express for parsing routes path-to-regexp (so it allows the same flexibility to declare routes). Read more about the concept of middlewares here.Do you like Prouter? please give it a 🌟
# With NPM
npm install prouter --save
# Or with Yarn
yarn prouter --save
# Or just include it using a 'script' tag in your HTML file
<script src="https://cdn.jsdelivr.net/npm/prouter/prouter.min.js"></script>
// Using es6 modules
import { browserRouter } from 'prouter';
// Instantiate the router
const router = browserRouter();
// Declare the paths and its respective handlers
router
.use('/', async (req, resp) => {
const people = await personService.find();
const html = PersonListCmp(people);
document.querySelector('.router-outlet') = html;
// end the request-response cycle
resp.end();
})
.use('/about', (req, resp) => {
document.querySelector('.router-outlet') =
`<h1>Some static content for the About page.</h1>`;
// end the request-response cycle
resp.end();
});
// start listening for navigation events
router.listen();
// Using commonJs modules
const prouter = require('prouter');
// Instantiate the router
const router = prouter.browserRouter({
processHashChange: true // this allows to process 'hash' changes in the URL.
});
// Declare the paths and its respective handlers
router
.use('*', (req, resp, next) => {
// this handler will run for any routing event, before any other handlers
const isAllowed = authService.validateHasAccessToUrl(req.path);
if (!isAllowed) {
showAlert("You haven't rights to access the page: " + destPath);
// end the request-response cycle, avoid executing other handlers
// and prevent changing the path in the URL.
resp.preventNavigation = true;
resp.end();
return;
}
// pass control to the next handler
next();
})
.use('/', (req, resp) => {
// do some stuff...
// and end the request-response cycle
resp.end();
})
.use('/admin', (req, resp) => {
// do some stuff...
// and end the request-response cycle
resp.end();
});
// start listening for navigation events
router.listen();
// programmatically try to navigate to any route in your router
router.push('/admin');
import { browserRouter } from 'prouter';
// Instantiate the router
const router = browserRouter();
// Declare the paths and its respective handlers
router
.use('/', async (req, resp, next) => {
const people = await personService.find();
const html = PersonListCmp(people);
document.querySelector('.router-outlet') = html;
// pass control to the next handler
next();
})
.use('*', (req, resp) => {
// do some (generic) stuff...
// and end the request-response cycle
resp.end();
});
// start listening for navigation events
router.listen();
import { browserRouter, routerGroup } from 'prouter';
// this can be in a different file for modularization of the routes,
// and then import it in your main routes file and mount it.
const productRouterGroup = routerGroup();
productRouterGroup
.use('/', (req, resp) => {
// do some stuff...
// and end the request-response cycle
resp.end();
})
.use('/create', (req, resp) => {
// do some stuff...
// and end the request-response cycle
resp.end();
})
.use('/:id(\\d+)', (req, resp) => {
const id = req.params.id;
// do some stuff with the 'id'...
// and end the request-response cycle
resp.end();
});
// Instantiate the router
const router = browserRouter();
// Declare the paths and its respective handlers
router
.use('*', (req, resp, next) => {
// this handler will run for any routing event, before any other handlers
console.log('request info', req);
// pass control to the next handler
next();
})
.use('/', (req, resp) => {
// do some stuff...
// and end the request-response cycle
resp.end();
})
// mount the product's group of handlers using this base path
.use('/product', productRouterGroup);
// start listening for the routing
router.listen();
// programmatically navigate to the detail of the product with this ID
router.push('/product/123');
import { browserRouter, routerGroup } from 'prouter';
// this can be in a different file for modularization of the routes,
// and then import it in your main routes file and mount it.
const productRouterGroup = routerGroup();
productRouterGroup
.use('/', (req, resp, next) => {
// do some stuff...
// and pass control to the next handler
next();
})
.use('/create', (req, resp, next) => {
// do some stuff...
// and pass control to the next handler
next();
})
.use('/:id(\\d+)', (req, resp, next) => {
const id = req.params.id;
// do some stuff with the 'id'...
// and pass control to the next handler
next();
});
// Instantiate the router
const router = browserRouter();
// Declare the paths and its respective handlers
router
.use('*', (req, resp, next) => {
// this handler will run for any routing event, before any other handlers
const isAllowed = authService.validateHasAccessToUrl(req.path);
if (!isAllowed) {
showAlert("You haven't rights to access the page: " + destPath);
// end the request-response cycle, avoid executing next handlers
// and prevent changing the path in the URL.
resp.preventNavigation = true;
resp.end();
return;
}
// pass control to the next handler
next();
})
.use('/', (req, resp, next) => {
const doInfiniteScroll = () => {
// do infinite scroll ...
};
const onNavigation = (navigationEvt) => {
console.log('new path', navigationEvt.oldPath);
console.log('old path', navigationEvt.newPath);
// if navigating, then remove the listener for the window.scroll.
router.off('navigation', onNavigation);
window.removeEventListener('scroll', doInfiniteScroll);
};
window.addEventListener('scroll', doInfiniteScroll);
// subscribe to the navigation event
router.on('navigation', onNavigation);
// and pass control to the next handler
next();
})
.use('/login', () => {
openLoginModal();
// as this route opens a modal, we would want to prevent navigation in this handler,
// so end the request-response cycle, avoid executing next handlers
// and prevent changing the path in the URL.
resp.preventNavigation = true;
resp.end();
})
.use('/admin', (req, resp, next) => {
// do some stuff...
// and pass control to the next handler
next();
})
// mount the product's group of handlers using this base path
.use('/product', productRouterGroup)
.use('*', (req, res, next) => {
// this handler will run for any routing event, after the other handlers
// req.listening will be true when this callback was called due to a
// client-side navigation (useful to differentiate client-side vs
// server-side rendering - when using a mix of both SSR and CSR)
if (req.listening) {
const title = inferTitleFromPath(req.path, APP_TITLE);
updatePageTitle(title);
}
// end the request-response cycle
resp.end();
});
// start listening for the routing
router.listen();
// the below code is an example about how you could capture clicks on links,
// and accordingly, trigger routing navigation in your app
// (typically, you would put it in a separated file)
export function isNavigationPath(path: string) {
return !!path && !path.startsWith('javascript:void');
}
export function isExternalPath(path: string) {
return /^https?:\/\//.test(path);
}
export function isApplicationPath(path: string) {
return isNavigationPath(path) && !isExternalPath(path);
}
document.body.addEventListener('click', (evt) => {
const target = evt.target as Element;
let link: Element;
if (target.nodeName === 'A') {
link = target;
} else {
link = target.closest('a');
if (!link) {
return;
}
}
const url = link.getAttribute('href');
// do nothing if it is not an app's internal link
if (!isApplicationPath(url)) {
return;
}
// avoid the default browser's behaviour when clicking on a link
// (i.e. do not reload the page).
evt.preventDefault();
// it is a normal app's link, so trigger the routing navigation
router.push(url);
});
FAQs
Fast, unopinionated, minimalist client-side routing library inspired by the simplicity and flexibility of express middlewares
The npm package prouter receives a total of 21 weekly downloads. As such, prouter popularity was classified as not popular.
We found that prouter demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.