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

@malectro/rerouter

v0.0.0

Published

a thin routing library designed as an easy replacement for react-router

Downloads

2

Readme

Rerouter

Rerouter is a standalone routing library written for React and similar to react-router.

Philosophy

Rerouter intends to be a router for React Fiber and Suspense.

Historically, routing libraries written for web UI would resolve a set of routes (declarative or procedural) all at once, eventually resulting in a view or set of components. Sometimes this process would involve transitions or async dependencies to determine whether or not a piece of UI could be seen.

Here's how I might describe Express's routing system at its most simplistic. Notice that this system would work in most environments and ignores the existence of React.

async function route(pathname) {
    for (const route of routes) {
        if (matches(route, pathname)) {
            const view = await route.callback();
            if (view) {
                return view;
            }
        }
    }
}

React 17 officially introduces the concept of prerendering. This means that when state changes, React will start to render the next tree before it replaces the old one. If the next tree indicates an async dependency, React will wait for that resource before it transitions to the next tree. React also allows for aborting the transition -- essentially throwing out the prerendered tree in favor of a new state change.

All of this behavior is very similar to that of a routing library -- to the point where it would seem silly to include code that accomplishes a nearly identical goal. Within a React application, it makes sense for React to handle state management, subscriptions, and rendering.

And using React to handle routing provides a few more unique benefits:

  • Async dependencies can exist anywhere in the component tree, not just at the routing level.
  • Components can opt in to pending transitions between pages. In other words, routing can be instant or async, depending on the link that triggers it.
  • Resources can be preloaded, which can make route transitions even faster. In very high-performance web apps, preloading is often triggered on hover of a link or button.
  • Code splitting is built in using React.lazy.

Usage

Rerouter takes full advantage of React's state management and subscription systems but still uses the History and Location APIs as a source of truth. In practice, this means a few things:

A Router provider must be rendered near the top of the application tree. This provides subscription access to the location and history anywhere in the application, but it importantly does not care how routing is accomplished – making it a fairly simple component.

A useRoutes hook provides the basis for actual routing. It takes a list of routes and returns a React subtree based on how they match the current location pathname. There are a few important aspects of this:

  • Routing is always synchronous. (Things like onEnter and getComponent from RR3 do not exist.)
  • Because routing is done at render time, the routes themselves can change on the fly. This means we can determine the available routes using things like user roles and privileges.
  • Routes are given JSX elements -- not components. This means that props can be easily passed to them.
  • Params are extracted by useRoutes -- not the Router provider. This means that params are only available to children produced by useRoutes. In practice this only affects components like ModalRoot that will never have access to the route tree.
  • useRoutes can be called multiple times by different subtrees, which allows collections of routes to be moved to different subpaths and namespaces at will. It also means we can code split at the route level using React.lazy.

Here is some JSX pseudocode that outlines the way a Rerouter application might look.

function App() {
    return (
        <RerouterProvider>
            <AppRoutes />
        </RerouterProvider>
    );
}

function AppRoutes() {
    return useRoutes([
        {path: '', exact: true, element: <Dashboard />},
        {path: 'posts', element: <PostsRoutes />},
        {path: '*', element: <NotFound />},
    ]);
}

function PostsRoutes() {
    const isAdmin = useIsAdmin();
    return useRoutes([
        {
            path: ':postId',
            children: [
                {path: '', exact: true, element: ({params: {postId}}) => <PostView postId={postId} />},
                isAdmin && {path: 'edit', element: ({params: {postId}}) => <PostEdit postId={postId} />},
            ],
        },
    ]);
}

Notice a few things:

  • PostRoutes and Dashboard are both components, and the router makes no distinctions. The only difference is that PostRoutes calls useRoutes.
  • The ability to edit posts is restricted to admins, and PostRoutes handles this at render time. If the user is not an admin, the route effectively does not exist.
  • Any element passed to useRoutes could be "lazy". Rerouter does not care (or really know the difference).