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 🙏

© 2024 – Pkg Stats / Ryan Hefner

bbgm-router

v2.0.2

Published

It has been said that writing a router is a rite of passage for a JavaScript programmer. So, here's my router.

Downloads

10

Readme

bbgm-router

It has been said that writing a router is a rite of passage for a JavaScript programmer. So, here's my router.

Why? Because other routers were pissing me off. In Basketball GM, originally I used Davis.js as the router. But eventually that became unmaintained and some bugs were left unfixed. I switched to Page.js, which was fairly similar. But it too caused me problems, sometimes it would produce mysterious error messages that I never was able to figure out. So I went looking for another router. There's a lot of them. Since I use React, probably I should use Reach Router or React Router, but I don't like coupling my router to my UI library and I don't want to use special Link components instead of normal links. router5 is popular, but its API seems both confusing and a little bit different than my current code, and I didn't want to deal with changing things around. router.js is another option, but the API seems dated.

So I did the only sensible thing and wrote my own. Here it is.

Advantages:

  • No coupling to any UI library
  • Use normal links
  • Nice, clean, modern API (IMHO)
  • TypeScript

Disadvantages:

  • No support for very old browsers
  • Limited options
  • You might not like the API

Surely this is a worse library than any of the libraries I complained above above, so I encourage you to use one of those instead. But it's routing hundreds of thousands of requests over at https://play.basketball-gm.com/ every day, so it can't be that bad!

Installation

$ yarn add bbgm-router

Usage

import router from "bbgm-router";

// Start handling some routes
router.start({
  "/": () => console.log("Index page"),
  "/other": () => console.log("Other page")
});

// Imperative navigation
router.navigate("/other").then(() => console.log("Navigation to other page is complete"));

API

router.start

router.start(
  routes: {
    [key: string]: (Context) => Promise<void>
  }
);

Define your routes and start listening for clicks. The keys of the routes object are paths, and the values are callback functions that will be run when the user navigates to that path.

The Context object passed to the callback function looks like this:

interface Context {
  params: {
    [key: string]: string;
  };
  path: string;
  state: {
    [key: string]: any;
  };
}

params are parameters parsed from the URL. For example, if your route is defined with a path of "/whatever/:foo/:bar" and the user navigates to "/whatever/whats/up", then params will be { "foo": "whats", "bar: "up" }. If your route has no parameters, then params will be an empty object.

path just contains the path of the request like "/whatever/whats/up" in the example above.

state is an empty object by default, unless some other value is supplied to router.navigate.

router.navigate

router.navigate(
  path: string,
  {
    replace = false,
    state = {}
  }: { replace?: boolean; state?: { [key: string]: any } } = {}
): Promise<void>;

Imperatively navigate to a path. The only required parameter is the path, like router.navigate("/my/path.html").

The optional second argument is an object with two optional properties. First, replace. If you set replace to true, then it will replace the latest history entry rather than creating a new one. This is useful when you're doing a redirect and you don't want to add an extra useless entry in the user's history, because that can break the browser's back button.

The other optional property is state. Whatever you put here will appear in the Context of callbacks and events associated with this navigation request. Use this if you need to pass some data along with the navigation request for later use.

router.navigate returns a promise that resolves when the navigation is complete (i.e. when the route callback function is complete and the events are dispatched).

router.addEventListener and router.removeEventListener

Because the Router class is a subclass of EventTarget, these behave just like the standard methods. Events triggered by bbgm-router are CustomEvent objects, with the event.detail property containing both the context of the request (defined earlier) and an error object, if any error occurred:

{
  context: Context,
  error: Error | null,
}

There are two events in bbgm-router:

"routematched" event

This event fires after the user clicks a link and after a matching route is found, but before the route callback function is run. This gives you an opportunity to start any route-related asynchronous activity (such as triggering an analytics tracker, or loading an ad) as early as possible.

router.addEventListener("routematched", (event) => {
  console.log("Route matched for path:", event.detail.context.path);
});

event.detail.error will always be null in this event.

"navigationend" event

This event fires after the navigation is complete. Any error that happens during navigation (such as during the execution of the route callback function) will appear in event.detail.error, giving you the opportunity to show an error page. This event will also fire even if no matching route is found, which you can use to show a 404 page.

router.addEventListener("navigationend", (event) => {
  if (event.detail.error) {
    if (event.detail.error.message === "Matching route not found") {
      console.log("404 error");
    } else {
      console.log("Some other error");
    }
  }
});