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 🙏

© 2026 – Pkg Stats / Ryan Hefner

modules-page-routing

v0.1.22

Published

Utility library for React Router v7 - helpers for routing, navigation, and page management

Readme

modules-page-routing

Utility library for React Router v7 - Automatically build routes from file-system with support for modules and API handlers.

Features

  • 🎯 Type-safe - Full TypeScript support with comprehensive type definitions
  • 📁 File-based routing - Automatically build routes from directory structure
  • 🧩 Module-based - Organize code by independent modules
  • 🔌 API routes - Support for building API handlers (global and module-scoped)
  • 📦 ESM & CommonJS - Dual module support for maximum compatibility
  • Zero dependencies - Only peer dependencies on React and React Router v7

Installation

npm install modules-page-routing

Peer Dependencies:

npm install react react-router

Usage

1. Directory Structure

Organize your code using a module-based structure:

app/
├── modules/
│   ├── __root.tsx          # Shared layout for all modules
│   ├── __homepage.tsx      # Homepage (index route)
│   ├── auth/
│   │   └── pages/
│   │       ├── _layout.tsx       # Layout for auth module
│   │       ├── sign-in.tsx       # /auth/sign-in
│   │       ├── sign-up.tsx       # /auth/sign-up
│   │       └── forgot-password.tsx
│   ├── admin/
│   │   └── pages/
│   │       ├── _layout.tsx       # Layout for admin module
│   │       ├── index.tsx         # /admin (index route)
│   │       ├── users/
│   │       │   ├── index.tsx     # /admin/users
│   │       │   └── [id].tsx      # /admin/users/:id
│   │       └── settings.tsx      # /admin/settings
│   └── shop/
│       ├── api/
│       │   ├── products.ts            # API: /api/shop/products
│       │   └── products.$id.ts        # API: /api/shop/products/:id
│       └── pages/
│           ├── index.tsx          # /shop
│           ├── products/
│           │   ├── index.tsx      # /shop/products
│           │   └── [id].tsx       # /shop/products/:id
│           └── cart.tsx           # /shop/cart
├── api/
│   └── v1/
│       ├── users.ts               # API: /api/v1/users
│       ├── users.$id.ts           # API: /api/v1/users/:id
│       └── products.search.ts     # API: /api/v1/products/search
└── routes.ts

2. routes.ts File

import {
  index,
  layout,
  prefix,
  type RouteConfig,
} from '@react-router/dev/routes';
import { flatRoutes } from '@react-router/fs-routes';
import {
  buildApiRouteConfig,
  buildApiModuleRouteConfig,
  buildGlobRouteConfig,
  type GlobModules,
} from 'modules-page-routing';

// Import all files in modules/*/pages/*, modules/*/api/*, and api/**/*
const globTree = import.meta.glob('./modules/**/pages/**/*.{tsx,ts}');
const apiTree = import.meta.glob('./api/**/*.ts');
const apiModuleTree = import.meta.glob('./modules/**/api/**/*.ts');

// Build React Router v7 RouteConfig from glob
const moduleRoutes = buildGlobRouteConfig(globTree as GlobModules);
const apiRoutes = buildApiRouteConfig(apiTree);
const apiModuleRoutes = buildApiModuleRouteConfig(apiModuleTree);

const routes = [
  // All module pages are nested under a shared layout
  layout('modules/__root.tsx', [
    index('modules/__homepage.tsx'),
    ...moduleRoutes,
  ]),

  // API routes: global (/api/v1/...) + module-scoped (/api/<module>/...)
  ...prefix('api', [...apiRoutes, ...apiModuleRoutes]),

  // Routes from app/routes/** (optional - if you still want traditional file-based routing)
  ...(await flatRoutes({
    rootDirectory: 'routes',
  })),
];

export default routes satisfies RouteConfig;

3. File Naming Conventions

Module Pages

  • index.tsx → Index route of the module/folder

    • modules/admin/pages/index.tsx/admin
    • modules/admin/pages/users/index.tsx/admin/users
  • _layout.tsx → Layout wrapper for child routes

    • modules/admin/pages/_layout.tsx → Layout for all routes in /admin/*
    • modules/admin/pages/users/_layout.tsx → Layout for /admin/users/*
  • [param].tsx → Dynamic route parameter

    • modules/admin/pages/users/[id].tsx/admin/users/:id
    • modules/shop/pages/products/[slug].tsx/shop/products/:slug
  • [...rest].tsx → Catch-all/splat route

    • modules/docs/pages/[...path].tsx/docs/*
  • _not-found.tsx → 404 page for the module

    • modules/admin/pages/_not-found.tsx → 404 for /admin/*
  • _error.tsx → Error boundary for the module (used by buildGlobRoutes runtime)

    • modules/admin/pages/_error.tsx → Error boundary for /admin/*
    • modules/admin/pages/users/_error.tsx → Error boundary for /admin/users/*
  • _loading.tsx → Loading fallback for the module (replaces default Suspense fallback)

    • modules/admin/pages/_loading.tsx → Loading UI for /admin/*
    • modules/admin/pages/users/_loading.tsx → Loading UI for /admin/users/*
  • _<folder> or _<file>.tsx → Parentless route (escapes parent layout)

    • modules/auth/pages/_login/index.tsx/auth/login (without auth layout)
    • modules/admin/pages/_fullscreen-editor.tsx/admin/fullscreen-editor (without admin layout)
    • Useful for modal pages, login overlays, or pages that need a different layout
  • (group) → Route group (organizational only, no URL segment)

    • modules/admin/pages/(dashboard)/overview.tsx/admin/overview
    • modules/admin/pages/(settings)/profile.tsx/admin/profile
    • Supports _layout.tsx inside route groups for shared layouts within the group
    • Example structure:
      admin/pages/
      ├── (dashboard)/
      │   ├── _layout.tsx    # Layout for dashboard group
      │   ├── index.tsx      # /admin
      │   └── analytics.tsx  # /admin/analytics
      └── (settings)/
          ├── _layout.tsx    # Layout for settings group
          ├── profile.tsx    # /admin/profile
          └── security.tsx   # /admin/security

API Routes

API routes use a different convention:

  • filename.ts → Single segment

    • api/v1/users.ts/api/v1/users
  • filename.segment.ts → Multiple segments (using .)

    • api/v1/products.search.ts/api/v1/products/search
    • api/v1/orders.export.csv.ts/api/v1/orders/export/csv
  • filename.$param.ts → Dynamic parameter (using $ prefix)

    • api/v1/users.$id.ts/api/v1/users/:id
    • api/v1/posts.$slug.comments.ts/api/v1/posts/:slug/comments

Module-scoped API Routes

API handlers can also live inside each module's api/ directory, co-located with pages:

  • modules/auth/api/login.ts/api/auth/login
  • modules/shop/api/products.ts/api/shop/products
  • modules/shop/api/products.$id.ts/api/shop/products/:id
  • modules/admin/api/v1/users.ts/api/admin/v1/users

Same naming conventions apply (. for segments, $ for params, _ for parentless, (group) for groups).

4. Component Examples

Module Layout (modules/admin/pages/_layout.tsx)

import { Outlet } from 'react-router';

export default function AdminLayout() {
  return (
    <div className='admin-layout'>
      <aside>
        <nav>
          <a href='/admin'>Dashboard</a>
          <a href='/admin/users'>Users</a>
          <a href='/admin/settings'>Settings</a>
        </nav>
      </aside>
      <main>
        <Outlet /> {/* Render nested routes */}
      </main>
    </div>
  );
}

Module Page (modules/admin/pages/users/[id].tsx)

import { useParams } from 'react-router';

export default function UserDetail() {
  const { id } = useParams();

  return (
    <div>
      <h1>User Detail: {id}</h1>
      {/* Your component code */}
    </div>
  );
}

API Handler (api/v1/users.$id.ts)

import type { LoaderFunctionArgs } from 'react-router';

export async function loader({ params }: LoaderFunctionArgs) {
  const userId = params.id;

  // Fetch user data
  const user = await fetchUser(userId);

  return Response.json(user);
}

export async function action({ request, params }: LoaderFunctionArgs) {
  const userId = params.id;
  const data = await request.json();

  // Update user
  await updateUser(userId, data);

  return Response.json({ success: true });
}

API Reference

buildGlobRouteConfig(globModules: GlobModules): RouteConfigNode[]

Builds React Router v7 RouteConfig from Vite import.meta.glob().

Parameters:

  • globModules: Object returned from import.meta.glob('./modules/**/pages/**/*.{tsx,ts}')

Returns: Array of RouteConfigNode to use with React Router v7 config

Conventions:

  • Files in modules/<module>/pages/**/* → URL /<module>/**/*
  • _layout.tsx → Layout wrapper with <Outlet />
  • index.tsx → Index route
  • [param] → Dynamic parameter
  • [...rest] → Catch-all route
  • _not-found.tsx → 404 handler
  • _<folder> or _<file>.tsx → Parentless route (escapes parent layout)

buildApiRouteConfig(globModules: Record<string, unknown>): RouteConfigNode[]

Builds API route config from a global api/ directory.

Parameters:

  • globModules: Object returned from import.meta.glob('./api/**/*.ts')

Returns: Array of RouteConfigNode to use with prefix('api', ...)

Conventions:

  • api/v1/users.ts/api/v1/users
  • api/v1/users.$id.ts/api/v1/users/:id
  • api/v1/products.search.ts/api/v1/products/search
  • . in filename → additional path segment
  • $ prefix → dynamic parameter
  • _ prefix in folder/filename → Parentless route (stripped from URL)

buildApiModuleRouteConfig(globModules: Record<string, unknown>): RouteConfigNode[]

Builds API route config from module-scoped api/ directories. Each module can co-locate its API handlers alongside its pages.

Parameters:

  • globModules: Object returned from import.meta.glob('./modules/**/api/**/*.ts')

Returns: Array of RouteConfigNode to use with prefix('api', ...)

Mapping: modules/<module>/api/<rest>/api/<module>/<rest>

Examples:

  • modules/auth/api/login.ts/api/auth/login
  • modules/admin/api/users.$id.ts/api/admin/users/:id
  • modules/shop/api/orders.export.ts/api/shop/orders/export

Conventions: Same as buildApiRouteConfig. for segments, $ for params, _ for parentless, (group) for route groups.

CLI

Visualize and validate your route tree from the terminal.

Route Tree

npx modules-page-routing routes --dir ./app
Page Routes

  /admin                             modules/admin/pages/_layout.tsx
  ├── (index)                        modules/admin/pages/index.tsx
  ├── /users                         modules/admin/pages/users/index.tsx
  ├── /users/:id                     modules/admin/pages/users/[id].tsx
  ├── /settings                      modules/admin/pages/settings.tsx
  └── /*                             modules/admin/pages/_not-found.tsx
  /auth                              modules/auth/pages/_layout.tsx
  ├── /sign-in                       modules/auth/pages/sign-in.tsx
  └── /sign-up                       modules/auth/pages/sign-up.tsx

API Routes

  /api/shop/products                 modules/shop/api/products.ts
  /api/shop/products/:id             modules/shop/api/products.$id.ts

Use --json for machine-readable output.

Validate

npx modules-page-routing validate --dir ./app

Checks for:

| Rule | Severity | Description | |------|----------|-------------| | duplicate-path | error | Two files resolve to the same URL | | dynamic-conflict | error | [id].tsx and [slug].tsx in the same directory | | catchall-shadow | warn | Catch-all * route may shadow siblings | | orphan-special-file | warn | _error.tsx/_loading.tsx without _layout.tsx | | empty-module | warn | Module has no page files | | missing-index | warn | Has _layout.tsx but no index.tsx |

Exits with code 1 if any errors are found — useful in CI.

TypeScript Support

This library is written entirely in TypeScript with full type definitions:

import type { GlobModules, RouteConfigNode } from 'modules-page-routing';

Benefits

Automatic - No need to manually define routes, just create files following conventions

Module-based - Organize code by features/modules, easy to scale

Type-safe - Full TypeScript support

Flexible - Can be combined with traditional file-based routing

Nested layouts - Support for nested layouts with _layout.tsx

API routes - Build both UI routes and API endpoints the same way

Real-world Example

See complete examples at: https://github.com/sonicname/modules-page-routing/tree/development/example

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request or create an Issue on GitHub.

Repository

https://github.com/sonicname/modules-page-routing

If you encounter any issues or have questions, please create an issue on the GitHub repository.