npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

rou3

v0.8.1

Published

Lightweight and fast router for JavaScript.

Readme

🌳 rou3

npm version npm downloads bundle size codecov

Lightweight and fast router for JavaScript.

Usage

Install:

# ✨ Auto-detect
npx nypm install rou3

Import:

ESM (Node.js, Bun, Deno)

import {
  createRouter,
  addRoute,
  findRoute,
  removeRoute,
  findAllRoutes,
  routeToRegExp,
  NullProtoObj,
} from "rou3";

CDN (Deno and Browsers)

import {
  createRouter,
  addRoute,
  findRoute,
  removeRoute,
  findAllRoutes,
  routeToRegExp,
  NullProtoObj,
} from "https://esm.sh/rou3";

Create a router instance and insert routes:

import { createRouter, addRoute } from "rou3";

const router = createRouter(/* options */);

addRoute(router, "GET", "/path", { payload: "this path" });
addRoute(router, "POST", "/path/:name", { payload: "named route" });
addRoute(router, "GET", "/path/foo/**", { payload: "wildcard route" });
addRoute(router, "GET", "/path/foo/**:name", {
  payload: "named wildcard route",
});

Match route to access matched data:

// Returns { payload: 'this path' }
findRoute(router, "GET", "/path");

// Returns { payload: 'named route', params: { name: 'fooval' } }
findRoute(router, "POST", "/path/fooval");

// Returns { payload: 'wildcard route' }
findRoute(router, "GET", "/path/foo/bar/baz");

// Returns undefined (no route matched for/)
findRoute(router, "GET", "/");

[!IMPORTANT] Paths should always begin with /.

[!IMPORTANT] Method should always be UPPERCASE.

[!TIP] If you need to register a pattern containing literal : or *, you can escape them with \\. For example, /static\\:path/\\*\\* matches only the static /static:path/** route.

Route Patterns

rou3 supports URLPattern-compatible syntax.

| Pattern | Example Match | Params | | --------------------------- | ---------------------------------- | ---------------------------------------------------- | | /path/to/resource | /path/to/resource | {} | | /users/:name | /users/foo | { name: "foo" } | | /path/** | /path/foo/bar | {} | | /path/**:rest | /path/foo/bar | { rest: "foo/bar" } | | /files/*.png | /files/icon.png | { "0": "icon" } | | /files/file-*-*.png | /files/file-a-b.png | { "0": "a", "1": "b" } | | /users/:id(\\d+) | /users/123 | { id: "123" } | | /files/:ext(png\|jpg) | /files/png | { ext: "png" } | | /path/(\\d+) | /path/123 | { "0": "123" } | | /users/:id? | /users or /users/123 | {} or { id: "123" } | | /files/:path+ | /files/a/b/c | { path: "a/b/c" } | | /files/:path* | /files or /files/a/b | {} or { path: "a/b" } | | /book{s}? | /book or /books | {} | | /blog/:id(\\d+){-:title}? | /blog/123 or /blog/123-my-post | { id: "123" } or { id: "123", title: "my-post" } |

  • Named params (:name) match a single segment.
  • Single-segment wildcards (*) capture unnamed params (0, 1, ...) and can be used as full or mid-segment tokens (for example /* or /*.png).
  • Wildcards (**) match zero or more segments. Use **:name to capture.
  • Regex constraints (:name(regex)) restrict matching. Constrained and unconstrained params can coexist on the same node (constrained checked first).
  • Unnamed groups ((regex)) capture into auto-indexed keys 0, 1, etc.
  • Modifiers: :name? (optional), :name+ (one or more), :name* (zero or more). Can combine with regex: :id(\d+)?.
  • Non-capturing groups ({...}): supported with inline (/foo{bar}) and optional (/foo{bar}?) forms.
  • Current limitation: repeating non-capturing groups ({...}+, {...}*) are supported only within a single segment (no / inside the group body).
  • Backslash escaping (\): escape special characters like :, *, (, ), {, } with a backslash (e.g., /static\:path matches literal /static:path).

Differences from URLPattern

rou3 aims for URLPattern-compatible syntax but has intentional differences due to its radix-tree design:

| Feature | URLPattern | rou3 | | ----------------------------- | ---------------------------------- | ------------------------------------------------------------- | | * (single star) | Greedy catch-all (.*) across / | Single-segment unnamed param ([^/]*) | | ** (double star) | Literal ** | Catch-all wildcard (zero or more segments) | | (.*) in segment | Greedy match across / | Segment-scoped (does not cross /) | | {...}+ / {...}* groups | Cross-segment group repetition | Only supported within a single segment (no / in group body) | | Path normalization (./..) | Resolves ./.. in input paths | Not done by default (opt-in with { normalize: true }) | | Case sensitivity | Can be case-insensitive | Always case-sensitive | | Non-/-prefixed paths | Supported | Paths must start with / | | Unicode param names | Supports Unicode identifiers | Params use \w (ASCII word chars only) | | Percent-encoding | Normalizes %xx sequences | Does not decode percent-encoded input |

Path normalization

By default, findRoute and findAllRoutes do not resolve ./.. segments in input paths. If your input paths may contain relative segments, enable normalization:

findRoute(router, "GET", "/foo/bar/../baz", { normalize: true });
// Matches "/foo/baz"

findAllRoutes(router, "GET", "/foo/./bar", { normalize: true });
// Matches "/foo/bar"

The compiled router also supports this via the normalize option:

const match = compileRouter(router, { normalize: true });
match("GET", "/foo/bar/../baz"); // Matches "/foo/baz"

Compiler

compileRouter(router, opts?)

Compiles the router instance into a faster route-matching function.

IMPORTANT: compileRouter requires eval support with new Function() in the runtime for JIT compilation.

Example:

import { createRouter, addRoute } from "rou3";
import { compileRouter } from "rou3/compiler";
const router = createRouter();
// [add some routes]
const findRoute = compileRouter(router);
const matchAll = compileRouter(router, { matchAll: true });
findRoute("GET", "/path/foo/bar");

compileRouterToString(router, functionName?, opts?)

Compile the router instance into a compact runnable code.

IMPORTANT: Route data must be serializable to JSON (i.e., no functions or classes) or implement the toJSON() method to render custom code or you can pass custom serialize function in options.

Example:

import { createRouter, addRoute } from "rou3";
import { compileRouterToString } from "rou3/compiler";
const router = createRouter();
// [add some routes with serializable data]
const compilerCode = compileRouterToString(router, "findRoute");
// "const findRoute=(m, p) => {}"

License

Published under the MIT license. Made by @pi0 and community 💛


🤖 auto updated with automd