rou3

🌳 Lightweight and fast rou(ter) for JavaScript

0
0
0
TypeScript

🌳 rou3

npm version
npm downloads
bundle size
codecov

Lightweight and fast router for JavaScript.

Usage

undefinedInstall:undefined

# ✨ Auto-detect
npx nypm install rou3

undefinedImport:undefined

undefinedESM (Node.js, Bun, Deno)

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

undefinedCDN (Deno and Browsers)

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

undefinedCreate a router instance and insert routes:undefined

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",
});

undefinedMatch route to access matched data:undefined

// 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" }
  • undefinedNamed params (:name) match a single segment.
  • undefinedSingle-segment wildcards (*) capture unnamed params (0, 1, …) and can be used as full or mid-segment tokens (for example /* or /*.png).
  • undefinedWildcards (**) match zero or more segments. Use **:name to capture.
  • undefinedRegex constraints (:name(regex)) restrict matching. Constrained and unconstrained params can coexist on the same node (constrained checked first).
  • undefinedUnnamed groups ((regex)) capture into auto-indexed keys 0, 1, etc.
  • undefinedModifiers: :name? (optional), :name+ (one or more), :name* (zero or more). Can combine with regex: :id(\d+)?.
  • undefinedNon-capturing groups ({...}): supported with inline (/foo{bar}) and optional (/foo{bar}?) forms.
  • undefinedCurrent limitation: repeating non-capturing groups ({...}+, {...}*) are supported only within a single segment (no / inside the group body).
  • undefinedBackslash 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.

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

undefinedExample:undefined

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.

undefinedIMPORTANT: 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.

undefinedExample:undefined

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

[beta]v0.14.0