Skip to main content

Van Router

ci npm version License download-url

A small (1kb gzipped) router middleware for vanilla-js.

Features

  • Easy to use. you can use pure js everywhere or combine with other framework like Alpinejs, React etc.
  • Small. this library is small (just 1kb gzipped).
  • Middleware. does your application have authentication? you can use middleware.
  • Lazy-Load. this router support laze-load js/controller.

Installation

Browser

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

<!-- es module -->
<script type="module">
  import { VanRouter } from "https://unpkg.com/van-router@0.5.1/index.esm.js";
  // code here
</script>

Nodejs

npm i van-router

Deno

import { VanRouter } from "https://deno.land/x/van_router@0.5.1/mod.ts";

Usage

Example

...
<body>
  <nav>
    <a href="#/home" van-link>Home</a>
    <a href="#/about" van-link>About</a>
  </nav>
  <div id="app"></div>
  <script>
    const render = (elem) => {
      document.getElementById("app").innerHTML = elem;
    }
    const router = new VanRouter({ render });

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

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

    router.resolve();
  </script>
</body>
...

note : extension vscode for literal html lit-html.

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

Without hash

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

// js (hash set to false)
const router = new VanRouter({ render, hash: false });
...

Middleware

...

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

// global middleware
router.use(foo_midd);

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

...

Interaction

useVanilla for javascript to document interaction or DOM manipulation.

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

  useVanilla(() => {
    const btn = document.getElementById("btn");
    btn.onclick = () => {
      alert("Hello from button");
    };
  });

  return `<button id="btn">Click Me</button>`;
});
...

Lazy-load

/router.js

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

/controller/home.js

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

Route Paths

// 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) => void;
  base?: string;
  hash?: boolean;
}

const router = new VanRouter(config);

Config.render

Render configs.

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

Config.base

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

Config.hash

optional hash true/false. default to true.

Context (ctx)

Is an utility based on object.

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

Context.params

Object query parameter from path.

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

Context.useVanilla

useVanilla for javascript to document interaction or DOM manipulation.

router.add("/", ({ useVanilla }) => {
  useVanilla(() => {
    const btn = document.getElementById("btn");
    btn.onclick = () => {
      alert("Hello from button");
    };
  });

  return `<button id="btn">Click Me</button>`;
});

Context.cleanup

use cleanup for clear listener or global variable.

router.add("/", ({ useVanilla, cleanup }) => {
  useVanilla(() => {
    window.myClick = () => {
      alert("hello from global window");
    };
  });

  cleanup(() => {
    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.go

go to state/path.

router.add("/", (ctx) => {
  ctx.go("#/home");
  // or without hash
  ctx.go("/home");
});

Context.html

for vscode literal html syntax highlight lit-html.

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

Other context

  • Context.pathname
  • Context.url

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 { VanRouter } 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 = new VanRouter({ render });

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

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

router.resolve();

It’s Fun Project :).