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