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 🙏

© 2025 – Pkg Stats / Ryan Hefner

van-router

v0.6.5

Published

A small router middleware for vanillajs.

Downloads

47

Readme

Van Router

ci npm version License download-url minzip

A small router middleware for vanilla-js.

Features

  • Easy to use. you can use pure js everywhere or combine with other framework like Alpinejs, React etc.
  • Middleware. does your application have authentication? you can use middleware.
  • Lazy-Load. this router support laze-load js/controller.
  • SSR. support SSR / Deno / Nodejs.

Installation

Browser

<!-- non module -->
<script src="//unpkg.com/van-router"></script>

<!-- es module -->
<script type="module">
  import { createRouter } from "https://esm.sh/van-router";
  // code here
</script>

This library transpile to ES3.

Nodejs

npm i van-router
const { createRouter } = require("van-router");

Deno

import { createRouter } from "https://deno.land/x/[email protected]/mod.ts";

Usage

Example in the browser

...
<body>
  <nav>
    <a href="/home" van-link>Home</a>
    <a href="/about" van-link>About</a>
  </nav>
  <div id="app"></div>
  <script>

    const { createRouter } = Van;

    const router = createRouter({ 
      render: (elem) => {
        document.getElementById("app").innerHTML = elem;
      }
    });

    router.add("/", () => {
      return `<h1>Hello Home</h1>`;
    });

    router.add("/about", () => {
      return `<h1>Hello About</h1>`;
    });

    addEventListener("load", () => {
      router.resolve();
    });
  </script>
</body>
...

note : extension vscode for literal html lit-html.

router.add("/", ({ html }) => {
  return html`<h1>Hello Home</h1>`;
});

With hash

...
// html
<nav>
  <a href="#/home" van-link>Home</a>
  <a href="#/about" van-link>About</a>
</nav>
...

// js
const router = createRouter({ 
  // set hash to true
  hash: true,
  render: (elem) => {...}
});
...

Middleware

...

const foo_midd = (ctx, next) => {
  ctx.foo = "foo";
  return next();
}
const bar_midd = (ctx, next) => {
  ctx.bar = "bar";
  return next();
}

// global middleware
router.use(foo_midd);

// inline middleware
router.add("/", bar_midd, ({ foo, bar }) => {
  return `<h1>${foo}${bar}</h1>`;
  // => foobar
});

...

Lazy-load

/router.js

...
router.add("/", ({ lazy }) => {
  return lazy("/controller/home.js");
});
...

/controller/home.js

function home() {
  return `<h1>Hello Home</h1>`;
}

Route Paths

Route

router.add("/", (ctx) => {...});
// or
router.on("GET", "/", (ctx) => {...});

Example

// simple path
router.add("/", (ctx) => {...});

// with parameter
router.add("/user/:id/:name", (ctx) => {...});

// with optional parameter
router.add("/user/:id/:name?", (ctx) => {...});

// with ext
router.add("/image/:filename.(jpg|png)", (ctx) => {...});

// wildcard
router.add("*", (ctx) => {...});
router.add("/user/*", (ctx) => {...});

// with regex
router.add(/.*noop$/, (ctx) => {...});

Config

Config for VanRouter

// types
type Config = {
  render?: (elem: any) => any;
  base?: string;
  hash?: boolean;
}

const router = createRouter(config);

Config.render

Render configs.

const render = (elem) => {
  document.getElementById("app").innerHTML = elem;
  // or with React
  // ReactDOM.render(elem, document.getElementById("app"));
};
const router = createRouter({ render });

Config.base

Base path/url like <base href="/myapp" />. default to undefined.

Config.hash

optional hash true/false. default to false.

Context (ctx)

Is an utility based on object.

router.add("/", (context) => {...})

Context.route

type CtxRoute = {
  url: string;
  path: string | RegExp;
  pathname: string;
  params: Record<string, any>;
  go(url: string, type?: string): void;
};

Context.route.params

Object query parameter from path.

router.add("/user/:userId", ({ route }) => {
  console.log(route.params);
  // => { userId: "123" }
  return ``;
});

Context.route.pathname

router.add("/user", ({ route }) => {
  console.log(route.pathname);
  // url => /user?name=john
  // pathname => /user
  return ``;
});

Context.route.url

router.add("/user", ({ route }) => {
  console.log(route.url);
  return ``;
});

Context.route.go

Go to pathname (client only).

router.add("/user", ({ route }) => {
  route.go("/home");
  return ``;
});

Context.route.path

router.add("/user/:userId/book/:bookId", ({ route }) => {
  console.log(route.path);
  // => /user/:userId/book/:bookId
  return ``;
});

Context.useAfter

Turn on client-side effect with useAfter.

why useAfter ? because execute code after rendering element/view.

...
useAfter(() => {
  // code here
  return () => {
    // cleanup here
  }
})
...

Example useAfter

router.add("/", ({ useAfter }) => {
  useAfter(() => {
    window.myClick = () => {
      alert("Hello World");
    };
    return () => {
      delete window.myClick;
    };
  });

  return `<button onclick="myClick()">Click Me</button>`;
});

Context.lazy

Lazy load js/controller

/router.js

...
router.add("/", ({ lazy }) => {
  return lazy("/controller/home.js");
});
...

/controller/home.js

function home() {
  return `<h1>Hello Home</h1>`;
}

Context.html

for vscode literal html syntax highlight lit-html.

router.add("/", ({ html }) => {
  return html`<h1>Hello World</h1>`;
});

Context.useData

support client-side and server-side.

router.add("/", ({ html, useData }) => {
  const data = useData(() => {
    return { name: "john" };
  });
  return html`<h1>${data.name}</h1>`;
});

Context.setHead

set head support client-side and server-side.

router.add("/", ({ html, setHead }) => {
  setHead(html`<title>Name John</title>`);

  return html`<h1>Name John</h1>`;
});

Context.getHandler

Call handler in handler. (server-side only). getHandler(url: string, method?: string) => Promise<any>.

note : requires return object directly on handler.

router.add("/api/user/:name", ({ html, route }) => {
  return { name: route.params.name };
});

router.add("/", ({ html, getHandler }) => {
  const data = await getHandler("/api/user/john");
  return html`<h1>${data.name}</h1>`;
  // => <h1>john</h1>
});

Other context

  • Context.isServer
  • Context.isHydrate
  • Context.request (SSR only)
  • Context.response (SSR only)

Handle error & not found

Handle 404 not found

router.add("*", () => {
  return `<h1>404 not found</h1>`;
});

Handle error

router.add("/", (ctx) => {
  ctx.noop();
  return `<h1>Noop</h1>`;
});
router.onError((err, ctx) => {
  console.log(err);
  return `<h1>${err.message}</h1>`;
  // message => ctx.noop is not a function
});

With React (jsx)

import React from "react";
import ReactDOM from "react-dom";
import { createRouter } from "van-router";

// example components
import Home from "./components/home";
import About from "./components/about";

const render = (component) => {
  ReactDOM.render(component, document.getElementById("app"));
};

const router = createRouter({ render });

router.add("/", () => {
  return <Home />;
});

router.add("/about", () => {
  return <About />;
});

router.resolve();

Server-Rendered

// resolve in the server.
const res = router.resolve({ request, response });

// body / elem
const body = await res.out();

// initial data from useData.
const data = await res.data();

// head for seo from setHead.
const head = res.head();

With Nodejs (Server-Rendered)

const { createRouter } = require("van-router");
const http = require("http");

const port = 8080;

const router = createRouter();

router.add("/", ({ html, setHead }) => {
  setHead(html`<title>Hello from node</title>`);
  return html`<h1>Hello From Node</h1>`;
});

http.createServer(async (request, response) => {
  const res = router.resolve({ request, response });
  const body = await res.out();
  const head = res.head();
  if (typeof body === "string") {
    response.setHeader("Content-Type", "text/html");
    response.end(`
      <html>
        <head>
          <link rel="icon" href="data:,">
          ${head}
        </head>
        <body>
          ${body}
        </body>
      </html>
    `);
  }
}).listen(port);

With Deno (Server-Rendered)

import { createRouter } from "https://deno.land/x/[email protected]/mod.ts";
import { serve } from "https://deno.land/[email protected]/http/server.ts";

const port = 8080;

const router = createRouter();

router.add("/", ({ html, setHead }) => {
  setHead(html`<title>Hello from deno</title>`);
  return html`<h1>Hello From Deno</h1>`;
});

await serve(async (request: Request) => {
  const res = router.resolve({ request });
  const body = await res.out();
  const head = res.head();
  if (body instanceof Response) return body;
  return new Response(
    `
    <html>
      <head>
        <link rel="icon" href="data:,">
        ${head}
      </head>
      <body>
        ${body}
      </body>
    </html>
  `,
    {
      headers: { "Content-Type": "text/html" },
    },
  );
}, { port });

It's Fun Project :).