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

@butterjs/router

v0.0.8

Published

This is the built-in router for Forecastr apps. It takes inspiration from Ruby on Rails, React Router, and Reach Router, but is very opinionated in its own way.

Downloads

7

Readme

Forecastr Router

This is the built-in router for Forecastr apps. It takes inspiration from Ruby on Rails, React Router, and Reach Router, but is very opinionated in its own way.

WARNING: This software is in alpha and should not be considered suitable for production use. In the "make it work; make it right; make it fast" paradigm, RR is in the later stages of the "make it work" phase.

Forecastr Router (RR from now on) is designed to list all routes in a single file, without any nesting. We prefer this design, as it makes it very easy to track which routes map to which pages.

Installation and use outside of a Forecastr app

RR was designed for use in Forecastr apps, and the rest of the documentation here will use examples that are appropriate in that context. That said, you can use RR outside of Forecastr apps too! If you do, there are a few things to note:

  1. Forecastr auto-imports every Page component in the Routes.js file, so if you use it outside of that context, you will need to import your Pages manually.

Router and Route

The first thing you need is a Router. It will contain all of your routes. RR will attempt to match the current URL to each route in turn, stopping when it finds a match, and rendering that route only. The only exception to this is the notfound route, which can be placed anywhere in the list and only matches when no other routes do.

Each route is specified with a Route. Our first route will tell RR what to render when no other route matches:

// Routes.js
import { Router, Route } from '@forecastr/router'

const Routes = () => (
  <Router>
    <Route notfound page={NotFoundPage} />
  </Router>
)

export default Routes

RR expects a single Route with a notfound prop. When no other route is found to match, the component in the page prop will be rendered.

To create a route to a normal Page, you'll pass three props: path, page, and name:

// Routes.js
<Route path="/" page={HomePage} name="home" />

The path prop specifies the URL path to match, starting with the beginning slash. The page prop specifies the Page component to render when the path is matched. The name prop is used to specify the name of the named route function.

Link and named route functions

When it comes to routing, matching URLs to Pages is only half the equation. The other half is generating links to your pages. RR makes this really simple without having to hardcode URL paths. In a Page component, you can do this (only relevant bits are shown in code samples from now on):

// SomePage.js
import { Link, routes } from '@forecastr/router'

// Given the route in the last section, this produces: <a href="/">
const SomePage = () => <Link to={routes.home()} />

You use a Link to generate a link to one of your routes and can access URL generators for any of your routes from the routes object. We call the functions on the routes object named route functions and they are named after whatever you specify in the name prop of the Route.

Named route functions simply return a string, so you can still pass in hardcoded strings to the to prop of the Link component, but using the proper named route function is easier and safer. Plus, if you ever decide to change the path of a route, you don't need to change any of the Links to it (as long as you keep the name the same)!

Route parameters

To match variable data in a path, you can use route parameters, which are specified by a parameter name surrounded by curly braces:

// Routes.js
<Route path="/user/{id}>" page={UserPage} name="user" />

This route will match URLs like /user/7 or /user/mojombo. You can have as many route parameters as you like:

// Routes.js
<Route path="/blog/{year}/{month}/{day}/{slug}" page={PostPage} name="post" />

By default, route parameters will match up to the next slash or end-of-string. Once extracted, the route parameters are sent as props to the Page component. In the 2nd example above, you can receive them like so:

// PostPage.js
const PostPage = ({ year, month, day, slug }) => { ... }

Named route functions with parameters

If a route has route parameters, then its named route function will take an object of those same parameters as an argument:

// SomePage.js
<Link to={routes.user({ id: 7 })} />

All parameters will be converted to strings before being inserted into the generated URL. If you don't like the default JavaScript behavior of how this conversion happens, make sure to convert to a string before passing it into the named route function.

Route parameter types

Route parameters are extracted as strings by default, but they will often represent typed data. RR offers a convenient way to auto-convert certain types right in the path specification:

// Routes.js
<Route path="/user/{id:Int}" page={UserPage} name="user" />

By adding :Int onto the route parameter, you are telling RR to only match /\d+/ and then use Number() to convert the parameter into a number. Now, instead of a string being sent to the Page, a number will be sent! This means you could have both a route that matches numeric user IDs and a route that matches string IDs:

// Routes.js
<Route path="/user/{id:Int}" page={UserIntPage} name="userInt" />
<Route path="/user/{id}" page={UserStringPage} name="userString" />

Now, if a request for /user/mojombo comes in, it will fail to match the first route, but will succeed in matching the second.

Core route parameter types

We call built-in parameter types core parameter types. All core parameter types begin with a capital letter. Here are the types:

  • Int - Matches and converts an integer.

User route parameter types

RR goes even further, allowing you to define your own route parameter types. Your custom types must begin with a lowercase letter. You can specify them like so:

// Routes.js
const userRouteParamTypes = {
  slug: {
    constraint: /\w+-\w+/,
    transform: (param) => param.split('-'),
  }
}

<Router paramTypes={userRouteParamTypes}>
  <Route path="/post/{name:slug}" page={PostPage} name={post} />
</Router>

Here we've created a custom slug route parameter type. It is defined by a constraint and a transform. Both are optional; the default constraint is /[^/]+/ and the default transform is (param) => param.

In the route we've specified a route parameter of {name:slug} which will invoke our custom route parameter type and if we have a requst for /post/forecastr-router, the resulting name prop delivered to PostPage will be ['forecastr', 'router'].

useParams

Sometimes it's convenient to receive route parameters as the props to the Page, but in the case where a deeply nested component needs access to the route parameters, it quickly becomes tedious to pass those props through every intervening component. RR solves this with the useParams hook:

// SomeDeeplyNestedComponent.js
import { useParams } from '@forecastr/router'

const SomeDeeplyNestedComponent = () => {
  const { id } = useParams()
  ...
}

In the above example, we've pulled in the id route parameter without needing to have it passed in to us from anywhere.

navigate

If you'd like to programmatically navigate to a different page, you can simply use the navigate function:

// SomePage.js
import { navigate, routes } from '@forecastr/router'

const SomePage = () => {
  const onSomeAction = () => {
    navigate(routes.home())
  }
  ...
}