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

next-route-resolver

v0.0.7

Published

Declarative route definition for Next.js

Downloads

6

Readme

next-route-resolver

Declarative route definition for Next.js

Allows you to define the routes for your Next.js website, to decouple them from the pages folder convention. The API is partly inspired by Django's URL configuration.

Motivation

  1. The default Next.js convention of mapping folder structures to URLs didn't fit our mental model of how websites should be structured.
  2. The facility for "masking" routes to bypass the pages convention is functional, but is lacking in the necessary abstractions to make it ergonomic.
  3. Existing solutions such as next-routes partially solve the problem, but use a chainable API that can be hard to compose and enable more advanced functionality.

Drawbacks

  1. Requires defining your own server (eg using Express.js) rather using the scripts Next.js gives you out of the box.
  2. Centralised routing needs to be in the core bundle, which could present a filesize issue for larger websites.

Installation

npm install next-route-resolver

or

yarn add next-route-resolver

Basic usage

Define some routes

import { compileRoutes } from "next-route-resolver";

const routes = compileRoutes([
  {
    path: "/",
    name: "homepage",
    page: "Homepage",
  },
  {
    path: "/posts/",
    name: "blog-index",
    page: "BlogIndex",
  },
  {
    path: "/posts/:slug/",
    name: "blog-post",
    page: "BlogPost",
  },
]);

Resolving URLs to a page and query

The returned object from the resolve function can be used to tell Next.js what page to render. You'll most likely use this as part of a request handler in your server code.

import { resolve } from "next-route-resolver";

import routes from "./routes";

resolve(routes, "/posts/my-first-blog-post/");
// { page: "./BlogPost", query: { slug: "my-first-blog-post"}}

Creating Link configuration

You'll also want to be able to create links to pages within your app. We've provided a function that will return necessary parameters for use with the Link component as well as the imperative API.

import { reverse } from "next-route-resolver";

import routes from "./routes";

reverse(routes, "blog-post", { slug: "my-first-blog-post" });
// { as: "/posts/my-first-blog-post/", href: { pathname: "/BlogPost", query: { slug: "my-first-blog-post" }}}

Includes

If your routes are getting too long and unweirdly, you can split them up.

import { compileRoutes, include } from "next-route-resolver";

const blogRoutes = [
  {
    path: "/posts/",
    name: "blog-index",
    page: "BlogIndex",
  },
  {
    path: "/posts/:slug/",
    name: "blog-post",
    page: "BlogPost",
  },
];

const routes = compileRoutes([
  include({ routes: blogRoutes }),
  {
    path: "/",
    name: "homepage",
    page: "Homepage",
  },
]);

You can also add a prefix to paths to make included routes more portable.

import { compileRoutes, include } from "next-route-resolver";

const blogRoutes = [
  {
    path: "/",
    name: "blog-index",
    page: "BlogIndex",
  },
  {
    path: "/:slug/",
    name: "blog-post",
    page: "BlogPost",
  },
];

const routes = compileRoutes([
  include({ routes: blogRoutes, prefix: "/posts/" }),
  {
    path: "/",
    name: "homepage",
    page: "Homepage",
  },
]);

Contextual includes

Let's say you want to make regional variants of your website. Perhaps under path prefixes such as /us/ and /es/. It's likely that you'll have some pages that are unique to each country, and some that are shared (but translated).

You could configure your routes as follows:

import { compileRoutes, include } from "next-route-resolver";

const usRoutes = [
  {
    path: "/contact-us/",
    name: "contact-us",
    page: "Contact",
  },
  {
    path: "/",
    name: "homepage",
    page: "HomepageUs",
  },
];

const esRoutes = [
  {
    path: "/contacto/",
    name: "contact-us",
    page: "Contact",
  },
  {
    path: "/",
    name: "homepage",
    page: "HomepageEs",
  },
];

const routes = compileRoutes([
  include({ routes: usRoutes, prefix: "/us/", params: { country: "us" } }),
  include({ routes: esRoutes, prefix: "/es/", params: { country: "es" } }),
]);

Now resolving and reversing are aware of the country parameter.

resolve(routes, "/us/");
// { page: "./HomepageUs", query: { country: "us"}}

reverse(routes, "homepage", { country: "us" });
// { as: "/us/", href: { pathname: "/HomepageUs", query: { country: "us" }}}

resolve(routes, "/es/contacto/");
// { page: "./Contact", query: { country: "es"}}

reverse(routes, "contact-us", { country: "es" });
// { as: "/es/contacto/", href: { pathname: "/Contact", query: { country: "es" }}}

Nesting parameters

Perhaps with the previous example, you want the US website to be the default rather than be scoped under a /us/ path. This is possible, because any parameters defined with include will override the same name parameters from higher up. So you could define your routes like this:

import { compileRoutes, include } from "next-route-resolver";

const usRoutes = [
  {
    path: "/contact-us/",
    name: "contact-us",
    page: "Contact",
  },
  {
    path: "/",
    name: "homepage",
    page: "HomepageUs",
  },
];

const esRoutes = [
  {
    path: "/contacto/",
    name: "contact-us",
    page: "Contact",
  },
  {
    path: "/",
    name: "homepage",
    page: "HomepageEs",
  },
];

const routes = compileRoutes(
  include({
    routes: [
      include({ routes: usRoutes }),
      include({ routes: esRoutes, prefix: "/es/", params: { country: "es" } }),
    ],
    params: { country: "us" },
  }),
);

You'd now be able to resolve and reverse like this:

resolve(routes, "/");
// { page: "./HomepageUs", query: { country: "us"}}

reverse(routes, "homepage", { country: "us" });
// { as: "/", href: { pathname: "/HomepageUs", query: { country: "us" }}}

resolve(routes, "/es/contacto/");
// { page: "./Contact", query: { country: "es"}}

reverse(routes, "contact-us", { country: "es" });
// { as: "/es/contacto/", href: { pathname: "/Contact", query: { country: "es" }}}