Vivaldi: A Universal JS Router Library for React

One of the problems faced when developing more complex universal applications is how to manage routing requests to UI output. React Router does this by taking in a URI and returning a React component structure. And it's excellent at doing that, but doing so means there's only the front end being returned. If you want metadata to go along with it, you have to munge that data in with the UI. Workable, but hardly elegant.

Now, given as that we, as good programmers, prefer composition over inheritance, I thought I'd take a stab at creating something a little different. The result is Vivaldi, a router for any universal JS project really, but designed with React in mind.

An Old-Fashioned Concept of Routing

When writing Vivaldi, I had three goals in mind:

  1. It should return an object with information about what to render, rather than a rendered component
  2. Returned information should include what to render, metadata about the route, and data about the match itself
  3. Routes should allow for parameters, which would be returned as key > value object data

The final code supports all these, giving a routing system that tells you what to render, as well as giving all the information you want about a page for SEO purposes, and supports its routing universally with full history.js support.

Using It

Server-side, using node and express, create an instance of express router, and set it as a catch-all:

const expressRouter = express.Router()
expressRouter.all('*', (req, res) => {
    const sysRouter = new Router(req)
    const route = new Mappings(sysRouter)
    // render using res.render() here

The Router is the Router class from the package, found here. Mappings is a separate class, which defines routes to be matched again, using the instantiated router.

Note that you can create many versions of Mappings, for different areas of your project, should it get big enough that you want to break it out into different areas. Just check for route.regex === null or route.components[0].area === '_404'.

Once you've got your returned object, you can render items based on the contents of route.components, and write into the page template metadata based on route.metaData. Any relevant data for the route based on the URL GET object will be in route.params.


If you've got any suggestions or recommendations, or ways to take the project further, feel free to submit a pull request. Feedback and help are always welcome.

If you've enjoyed this post, you might want to follow our founder, Pete Watson-Wailes on Twitter