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

rsbuild-plugin-pages

v0.0.3

Published

Rsbuild plugin for filesystem routing and Express API

Readme

rsbuild-plugin-pages

A powerful Rsbuild plugin that enables filesystem-based routing similar to Next.js, with full support for Express.js@5 API routes.

Features

  • 🚀 Filesystem-based routing - Automatic route generation from your file structure
  • 🔥 Next.js-style conventions - Familiar routing patterns with [id] and [...params] support
  • Express.js@5 API routes - Full-featured API endpoints with HTTP method support
  • 📝 TypeScript first - Complete type safety for routes and parameters
  • 🔄 Hot reloading - Automatic route updates during development
  • 📦 Code splitting - Dynamic imports for optimal bundle size
  • 🛠️ Zero config - Works out of the box with sensible defaults

Installation

npm install rsbuild-plugin-pages
# or
yarn add rsbuild-plugin-pages
# or
pnpm add rsbuild-plugin-pages

Quick Start

1. Add the plugin to your Rsbuild config

// rsbuild.config.ts
import { defineConfig } from '@rsbuild/core';
import { pluginPages } from 'rsbuild-plugin-pages';

export default defineConfig({
  plugins: [
    // pluginPages returns an array of plugins (virtual module + pages plugin)
    ...pluginPages({
      pagesDir: 'src/pages',
      apiDir: 'src/pages/api',
    }),
  ],
});

2. Create your page structure

src/
  pages/
    index.tsx          # → /
    about.tsx          # → /about
    blog/
      index.tsx        # → /blog
      [slug].tsx       # → /blog/:slug
    users/
      [id].tsx         # → /users/:id
      [...params].tsx  # → /users/*params
    api/
      hello.ts         # → /api/hello
      users/
        [id].ts        # → /api/users/:id

3. Create your pages

// src/pages/index.tsx
export default function HomePage() {
  return <h1>Welcome to the home page!</h1>;
}

// src/pages/blog/[slug].tsx
import { useParams } from 'react-router-dom';

export default function BlogPost() {
  const { slug } = useParams();
  return <h1>Blog post: {slug}</h1>;
}

4. Create API routes

// src/pages/api/hello.ts
import type { Request, Response } from 'express';

export function GET(req: Request, res: Response) {
  res.json({ message: 'Hello from API!' });
}

export function POST(req: Request, res: Response) {
  res.json({ message: 'Posted!', body: req.body });
}

// src/pages/api/users/[id].ts
import type { Request, Response } from 'express';

export function GET(req: Request, res: Response) {
  const { id } = req.params;
  res.json({ user: { id, name: `User ${id}` } });
}

5. Use the generated routes

// src/App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import routes from 'virtual:rsbuild-pages/routes';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        {routes.map((route, index) => (
          <Route
            key={index}
            path={route.path}
            element={<route.component />}
            exact={route.exact}
          />
        ))}
      </Routes>
    </BrowserRouter>
  );
}

export default App;

Configuration

Plugin Options

interface PagesPluginOptions {
  /**
   * Directory containing pages (default: 'src/pages')
   */
  pagesDir?: string;
  
  /**
   * Directory containing API routes (default: 'src/pages/api')
   */
  apiDir?: string;
  
  /**
   * File extensions to include (default: ['.tsx', '.ts', '.jsx', '.js'])
   */
  extensions?: string[];
  
  /**
   * Patterns to ignore
   */
  ignore?: string[];
  
  /**
   * Enable dynamic imports for code splitting (default: true)
   */
  dynamicImports?: boolean;
  
  /**
   * Express.js configuration
   */
  express?: {
    middleware?: ExpressMiddleware[];
  };
}

Example Configuration

// rsbuild.config.ts
import { defineConfig } from '@rsbuild/core';
import { pluginPages } from 'rsbuild-plugin-pages';

export default defineConfig({
  plugins: [
    ...pluginPages({
      pagesDir: 'src/pages',
      apiDir: 'src/api',
      extensions: ['.tsx', '.ts'],
      ignore: ['**/*.test.*', '**/components/**'],
      dynamicImports: true,
      express: {
        middleware: [
          {
            path: '/api',
            handler: (req, res, next) => {
              // CORS middleware
              res.header('Access-Control-Allow-Origin', '*');
              next();
            },
          },
        ],
      },
    }),
  ],
});

Routing Conventions

Page Routes

  • pages/index.tsx/
  • pages/about.tsx/about
  • pages/blog/index.tsx/blog
  • pages/blog/[slug].tsx/blog/:slug
  • pages/users/[id].tsx/users/:id
  • pages/posts/[...params].tsx/posts/*params

API Routes

API routes support all HTTP methods through named exports:

// pages/api/users.ts
import type { Request, Response } from 'express';

export function GET(req: Request, res: Response) {
  // Handle GET requests
}

export function POST(req: Request, res: Response) {
  // Handle POST requests
}

export function PUT(req: Request, res: Response) {
  // Handle PUT requests
}

export function DELETE(req: Request, res: Response) {
  // Handle DELETE requests
}

Dynamic Routes

Single Parameter

// pages/users/[id].tsx
// Matches: /users/123, /users/abc
import { useParams } from 'react-router-dom';

export default function User() {
  const { id } = useParams();
  return <div>User ID: {id}</div>;
}

Catch-All Routes

// pages/docs/[...params].tsx
// Matches: /docs/a, /docs/a/b, /docs/a/b/c
import { useParams } from 'react-router-dom';

export default function Docs() {
  const { params } = useParams();
  // params will be 'a/b/c' for /docs/a/b/c
  return <div>Docs: {params}</div>;
}

Virtual Modules

The plugin creates virtual modules that exist only in memory and are managed by Rsbuild:

  • virtual:rsbuild-pages/routes - Client-side route definitions
  • virtual:rsbuild-pages/api - Express.js router for API routes
  • virtual:rsbuild-pages/manifest - Complete route manifest
  • virtual:rsbuild-pages/types - TypeScript definitions

Import Virtual Modules

Import the generated virtual modules directly:

import routes from 'virtual:rsbuild-pages/routes';          // Page routes
import apiRouter from 'virtual:rsbuild-pages/api';          // API router
import manifest from 'virtual:rsbuild-pages/manifest';      // Route manifest

TypeScript Support

The plugin generates complete TypeScript definitions for type-safe routing. To use TypeScript with virtual modules, add this to your types.d.ts file:

// types.d.ts
declare module 'virtual:rsbuild-pages/routes' {
  import type { PageRoute } from 'rsbuild-plugin-pages';
  const routes: PageRoute[];
  export default routes;
}

declare module 'virtual:rsbuild-pages/api' {
  import type { Router } from 'express';
  const router: Router;
  export default router;
}

declare module 'virtual:rsbuild-pages/manifest' {
  import type { GeneratedRoutes } from 'rsbuild-plugin-pages';
  const manifest: GeneratedRoutes;
  export default manifest;
}

declare module 'virtual:rsbuild-pages/types' {
  // Auto-generated route types
  export interface PageRoutes {
    '/': [];
    '/about': [];
    '/blog/:slug': ['slug'];
    '/users/:id': ['id'];
    '/posts/*params': ['params'];
  }
  
  export interface ApiRoutes {
    '/hello': [];
    '/users/:id': ['id'];
  }
  
  // Type-safe route parameters
  export type RouteParams<T extends keyof PageRoutes> = 
    PageRoutes[T] extends string[] 
      ? Record<PageRoutes[T][number], string>
      : never;
}

Express.js Integration

Basic Setup

// server.ts
import express from 'express';
import apiRouter from 'virtual:rsbuild-pages/api';

const app = express();

// Add JSON parsing
app.use(express.json());

// Add API routes
app.use('/api', apiRouter);

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Custom Middleware

// Add custom middleware through plugin options
pluginPages({
  express: {
    middleware: [
      {
        path: '/api',
        handler: (req, res, next) => {
          console.log(`API ${req.method} ${req.path}`);
          next();
        },
      },
    ],
  },
});

Advanced Usage

Custom Route Processing

// Access the route manifest for custom processing
import manifest from 'virtual:rsbuild-pages/manifest';

console.log('Available routes:', manifest);
// {
//   pages: [...],
//   api: [...]
// }

Virtual Module Benefits

Using virtual modules provides several advantages:

  • 🚀 Performance: No file system I/O - modules exist only in memory
  • 🔄 Hot Reloading: Instant updates when routes change
  • 🧹 Clean: No generated files cluttering your project
  • 🔧 Integration: Seamless integration with Rsbuild's module system
  • 📦 Production: Virtual modules are properly bundled for production

Development vs Production

The plugin automatically handles development vs production builds:

  • Development: File watching with hot reloading of virtual modules
  • Production: Virtual modules are bundled normally by Rsbuild

Examples

Blog Application

src/
  pages/
    index.tsx           # Home page
    blog/
      index.tsx         # Blog listing
      [slug].tsx        # Individual blog post
      category/
        [name].tsx      # Category page
    api/
      posts/
        index.ts        # GET /api/posts
        [id].ts         # GET /api/posts/:id

E-commerce Application

src/
  pages/
    index.tsx           # Home
    products/
      index.tsx         # Product listing
      [id].tsx          # Product detail
      category/
        [...path].tsx   # Nested categories
    api/
      products/
        index.ts        # Product CRUD
        [id].ts         # Individual product
      cart/
        index.ts        # Cart operations

Migration Guide

From Next.js

The plugin follows Next.js conventions closely, making migration straightforward:

  1. Move your pages directory to src/pages
  2. Update your router setup to use the generated routes
  3. API routes work the same way with Express.js instead of Next.js API routes

From React Router

  1. Remove manual route definitions
  2. Organize components into the src/pages directory following the conventions
  3. Import and use the generated routes

Troubleshooting

Common Issues

  1. Virtual module not found: Make sure you're using the correct import path (virtual:rsbuild-pages/routes)
  2. Routes not updating: Ensure file watching is working and files are in the correct directory
  3. TypeScript errors: Add virtual module type declarations (see TypeScript Support section)
  4. API routes not working: Verify Express.js is properly configured and routes export the correct HTTP methods
  5. Plugin conflicts: Remember to spread the plugin array: ...pluginPages({...})

Debug Mode

Enable debug logging:

// Set environment variable
process.env.DEBUG = 'rsbuild-pages:*';

Development

This project uses Biome for linting and formatting.

Available Scripts

  • npm run build - Build the plugin for production
  • npm run dev - Build in watch mode for development
  • npm test - Run the test suite
  • npm run lint - Check for linting issues
  • npm run lint:fix - Fix linting issues automatically
  • npm run format - Check code formatting
  • npm run format:fix - Fix code formatting automatically
  • npm run check - Run both linting and formatting checks
  • npm run check:fix - Fix both linting and formatting issues

Contributing

We welcome contributions! Please see our Contributing Guide for details.

License

MIT License - see LICENSE for details.

Changelog

See CHANGELOG.md for version history and changes.