Go Back

Building a Dynamic App Router in React with Vite and TypeScript

Introduction

In modern web development, routing is a fundamental feature for any single-page application (SPA). As projects grow, managing routes manually can become tedious and error-prone. To address this, I built a React application that automatically generates routes based on the files present in a specific directory. This approach streamlines the development process, making it easier to scale and maintain large React projects.

Motivation

Traditional React routing requires developers to manually import page components and define routes, which can quickly become cumbersome as the number of pages increases. Inspired by file-based routing systems in frameworks like Next.js and Remix, I wanted to bring a similar developer experience to a Vite-powered React app using TypeScript and React Router v7+.

The Idea

The core idea is simple: every file in the src/pages directory automatically becomes a route in the application. The file name determines the route path, and the component exported from that file is rendered when the route is accessed. This eliminates the need for repetitive route declarations and makes adding new pages as easy as creating a new file.

Implementation

Stack

  • React 19 for building the UI
  • Vite for fast development and build tooling
  • TypeScript for type safety
  • React Router v7+ for routing
  • ESLint for code quality

How It Works

  1. Dynamic Importing: Using Vite's import.meta.glob, all .tsx files in the src/pages directory are dynamically imported.

  2. Route Generation: The file names are converted into route paths. For example, home.tsx becomes /, about.tsx becomes /about, and so on.

  3. Automatic Registration: The app iterates over the imported modules and creates a <Route> for each, using React Router's <Routes> and <BrowserRouter> components.

  4. Adding Pages: To add a new route, simply create a new file in src/pages. No need to touch the routing logic.

Example

Suppose you have the following files in src/pages:

  • home.tsx/
  • about.tsx/about
  • help.tsx/help

Each file exports a React component that is rendered at its respective route.

Code Snippet

const pages = import.meta.glob("./pages/*.tsx");

const loadRoutes = async () => {
  const routeElements: JSX.Element[] = [];

  for (const path in pages) {
    const loader = pages[path];
    const module = (await loader()) as { default: React.ComponentType };

    let routePath = path
      .replace("./pages/", "")
      .replace(".tsx", "")
      .toLowerCase();

    if (routePath === "home") {
      routePath = "/";
    } else {
      routePath = "/" + routePath;
    }

    routeElements.push(
      <Route key={routePath} path={routePath} element={<module.default />} />
    );
  }
};

Benefits

  • Scalability: Easily add or remove pages without modifying routing code.
  • Maintainability: Reduces boilerplate and the risk of routing errors.
  • Developer Experience: Inspired by modern frameworks, making onboarding and collaboration easier.
  • Performance: Leveraging Vite's fast HMR and build process.

Conclusion

This project demonstrates how to implement a file-based dynamic router in a React app using Vite and TypeScript. It brings the convenience of automatic routing to standard React projects, making them easier to scale and maintain. If you're looking for a way to simplify your routing logic and improve your development workflow, consider adopting this approach in your next React project.