@reliance/simple-router
v1.0.1
Published
A lightweight, plug-and-play React routing system with TypeScript support
Downloads
9
Readme
@reliance/simple-router
A lightweight, plug-and-play React routing system with TypeScript support. Designed for microfrontends and applications that need flexible routing without the complexity of larger routing libraries.
Features
- 🚀 Lightweight: Minimal bundle size with zero dependencies
- 🔧 Framework Agnostic Core: Core utilities work without React
- 📦 Plug and Play: Easy integration with existing applications
- 🎯 TypeScript First: Full TypeScript support with comprehensive types
- 🔄 Route Parameters: Dynamic route parameters with type safety
- 🔍 Query Parameters: Built-in query parameter handling
- 🏗️ Nested Routes: Support for complex nested routing structures
- 🛡️ Route Guards: Authentication and authorization guards
- 📱 SSR Compatible: Works with server-side rendering
- 🎨 Flexible: Use with any UI framework or component library
Installation
npm install @reliance/simple-router
# or
yarn add @reliance/simple-routerQuick Start
import React from "react";
import { Router, Link, useRouteParams } from "@reliance/simple-router";
// Define your route components
const Home = () => <div>Home Page</div>;
const About = () => <div>About Page</div>;
const User = () => {
const params = useRouteParams<{ id: string }>();
return <div>User: {params.id}</div>;
};
// Define your routes
const routes = [
{ path: "/", component: Home, exact: true },
{ path: "/about", component: About },
{ path: "/user/:id", component: User },
];
// Use the router
function App() {
return <Router routes={routes} />;
}
// Navigation example in a component
function Navigation() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/user/123">User 123</Link>
</nav>
);
}Core Concepts
Route Configuration
import { RouteConfig } from "@reliance/simple-router";
const routes: RouteConfig[] = [
{
path: "/",
component: HomePage,
exact: true,
title: "Home",
},
{
path: "/products",
component: ProductsLayout,
children: [
{ path: "", component: ProductsList, exact: true },
{ path: "/:id", component: ProductDetail },
{ path: "/new", component: CreateProduct },
],
},
];Route Parameters
Access route parameters using the useRouteParams hook:
import { useRouteParams } from "@reliance/simple-router";
function ProductDetail() {
const params = useRouteParams<{ id: string }>();
return <div>Product ID: {params.id}</div>;
}Or use the combined useParams hook to get both route and query parameters:
import { useParams } from "@reliance/simple-router";
function ProductDetail() {
const params = useParams<{ id: string; sort?: string }>();
return (
<div>
<div>Product ID: {params.id}</div>
<div>Sort: {params.sort}</div>
</div>
);
}Query Parameters
import { useQueryParams } from "@reliance/simple-router";
function ProductsList() {
const { queryParams, setQueryParams } = useQueryParams();
const search = queryParams.search || "";
const page = Number(queryParams.page) || 1;
return (
<div>
<input
value={search}
onChange={(e) => setQueryParams({ search: e.target.value, page: "1" })}
/>
<div>Page: {page}</div>
</div>
);
}Route Guards
Protect routes with authentication and authorization guards:
import {
createAuthGuard,
createRoleGuard,
combineGuards,
} from "@reliance/simple-router";
const authGuard = createAuthGuard(
() => !!localStorage.getItem("token"),
"/login"
);
const adminGuard = createRoleGuard(
(roles) => roles.includes("admin"),
["admin"],
"/unauthorized"
);
const routes = [
{
path: "/dashboard",
component: Dashboard,
guards: [authGuard],
},
{
path: "/admin",
component: AdminPanel,
guards: [combineGuards(authGuard, adminGuard)],
},
];Advanced Usage
Programmatic Navigation
import { useNavigate } from "@reliance/simple-router";
function MyComponent() {
const { navigate, back, forward, replace } = useNavigate();
const handleNavigation = () => {
// Navigate to a new route
navigate("/dashboard");
// Navigate with query parameters
navigate("/products", { queryParams: { category: "electronics" } });
// Replace current route (no history entry)
replace("/login");
// Go back/forward in history
back();
forward();
};
}Pagination Hook
import { usePagination } from "@reliance/simple-router";
function DataTable() {
const { page, limit, setPage, nextPage, previousPage } = usePagination(1, 20);
return (
<div>
<div>Page {page}</div>
<button onClick={previousPage} disabled={page === 1}>
Previous
</button>
<button onClick={nextPage}>Next</button>
</div>
);
}Filters Hook
Manage filter state synchronized with URL query parameters:
import { useFilters } from "@reliance/simple-router";
function ProductFilters() {
const { filters, setFilter, resetFilters } = useFilters({
category: "",
minPrice: 0,
maxPrice: 1000,
});
return (
<div>
<select
value={filters.category}
onChange={(e) => setFilter("category", e.target.value)}
>
<option value="">All Categories</option>
<option value="electronics">Electronics</option>
</select>
<button onClick={resetFilters}>Reset</button>
</div>
);
}URL State Management
import { useUrlState } from "@reliance/simple-router";
function SearchForm() {
const [searchTerm, setSearchTerm] = useUrlState("search", "");
return (
<input value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} />
);
}Building URLs with Route Parameters
import { buildRoutePath } from "@reliance/simple-router";
// Build URLs with route parameters
const userUrl = buildRoutePath("/users/:id", { id: "123" });
// Result: "/users/123"
const postUrl = buildRoutePath("/users/:userId/posts/:postId", {
userId: "123",
postId: "456",
});
// Result: "/users/123/posts/456"Framework Agnostic Core
The core utilities can be used without React:
import {
parseQueryParams,
buildRoutePath,
RouteMatcher,
Navigator,
} from "@reliance/simple-router";
// Parse query parameters
const params = parseQueryParams("?search=react&page=2");
// { search: 'react', page: '2' }
// Build route with parameters
const path = buildRoutePath("/users/:id/posts/:postId", {
id: "123",
postId: "456",
});
// '/users/123/posts/456'
// Match routes
const matcher = new RouteMatcher([{ path: "/users/:id", component: null }]);
const match = matcher.match("/users/123");
// { route: {...}, params: { id: '123' }, ... }
// Create a navigator for programmatic navigation
const navigator = new Navigator();
navigator.navigate("/dashboard");Patterns & Best Practices
Centralized Route Configuration
Create a dedicated file for your application routes:
// routes.ts
import { RouteConfig } from "@reliance/simple-router";
import {
HomePage,
UserPage,
ProductPage,
ProductList,
ProductDetail,
} from "./pages";
import { authGuard } from "./guards";
export const appRoutes: RouteConfig[] = [
{
path: "/",
component: HomePage,
exact: true,
title: "Home - My App",
},
{
path: "/users/:id",
component: UserPage,
title: "User Profile - My App",
guards: [authGuard],
},
{
path: "/products",
component: ProductPage,
children: [
{ path: "", component: ProductList, exact: true },
{ path: "/:id", component: ProductDetail },
],
},
];Microfrontend Integration
For microfrontend architectures, each microfrontend can have its own routes that are combined at the shell level:
// Wallet microfrontend routes
export const walletRoutes: RouteConfig[] = [
{ path: "/wallet", component: WalletDashboard, exact: true },
{ path: "/wallet/transactions", component: Transactions },
];
// Payment microfrontend routes
export const paymentRoutes: RouteConfig[] = [
{ path: "/payments", component: PaymentDashboard, exact: true },
{ path: "/payments/history", component: PaymentHistory },
];
// Shell app combines all routes
import { Router } from "@reliance/simple-router";
function App() {
const allRoutes = [...walletRoutes, ...paymentRoutes];
return <Router routes={allRoutes} />;
}Using Base Path for Microfrontends
Configure a base path for each microfrontend:
// In each microfrontend
function WalletApp() {
return <Router routes={walletRoutes} basePath="/wallet-ms" />;
}TypeScript Support
Full TypeScript support with comprehensive type definitions:
import { useRouteParams, useQueryParams } from "@reliance/simple-router";
import type { RouteParams, QueryParams } from "@reliance/simple-router";
interface UserParams extends RouteParams {
id: string;
}
interface UserQuery extends QueryParams {
tab?: string;
section?: string;
}
function UserProfile() {
const params = useRouteParams<UserParams>();
const { queryParams } = useQueryParams();
// params.id is typed as string
// queryParams.tab is typed as string | string[] | undefined
const tab = queryParams.tab as string | undefined;
}API Reference
Components
Router
Main router component that manages navigation and renders matched routes.
Props:
routes: RouteConfig[]- Array of route configurationsbasePath?: string- Base path for all routes (default: "")hashMode?: boolean- Use hash-based routing (default: false)caseSensitive?: boolean- Case-sensitive route matching (default: false)onNotFound?: React.ComponentType- Custom 404 componentonLoading?: React.ComponentType- Custom loading component
Link
Navigation link component.
Props:
to: string- Target pathreplace?: boolean- Replace current history entryclassName?: string- CSS classactiveClassName?: string- CSS class when link is activeexact?: boolean- Exact path matching for active stateonClick?: () => void- Click handler
Hooks
useRoute()
Get current route match information.
Returns: RouteMatch | null
useRouteParams<T>()
Get route parameters (e.g., /users/:id).
Returns: T extends RouteParams
useParams<T>()
Get combined route and query parameters.
Returns: T extends Record<string, any>
useQueryParams()
Manage URL query parameters.
Returns:
{
queryParams: QueryParams;
setQueryParam: (key: string, value: string | undefined) => void;
setQueryParams: (params: QueryParams, replace?: boolean) => void;
getQueryParam: (key: string) => string | undefined;
removeQueryParam: (key: string) => void;
clearQueryParams: () => void;
}useNavigate()
Programmatic navigation.
Returns:
{
navigate: (path: string, options?: NavigateOptions) => void;
back: () => void;
forward: () => void;
go: (delta: number) => void;
replace: (path: string, options?) => void;
buildUrl: (path: string, params?, queryParams?) => string;
canNavigate: () => boolean;
}useIsActive()
Check if a route is currently active.
Returns:
{
isActive: (path: string, exact?: boolean) => boolean;
getActiveClass: (path: string, activeClassName?: string, exact?: boolean) =>
string;
}useRouter()
Access router context with all navigation methods and current route state.
usePagination(defaultPage?, defaultLimit?, paramNames?)
Manage pagination with URL state.
Returns:
{
page: number;
limit: number;
setPage: (page: number) => void;
setLimit: (limit: number) => void;
nextPage: () => void;
previousPage: () => void;
resetPagination: () => void;
}useFilters<T>(defaultFilters, paramPrefix?)
Manage filters with URL state.
Returns:
{
filters: T;
setFilter: (key: keyof T, value: T[key]) => void;
setFilters: (filters: Partial<T>) => void;
resetFilters: () => void;
clearFilter: (key: keyof T) => void;
}useUrlState<T>(key, defaultValue, serialize?, deserialize?)
Manage single value in URL state.
Returns: [T, (value: T) => void]
Utilities
Route Guards
createAuthGuard(isAuthenticated, redirectTo)- Authentication guardcreateRoleGuard(hasRole, requiredRoles, redirectTo)- Role-based guardcreatePermissionGuard(hasPermission, requiredPermission, redirectTo)- Permission guardcombineGuards(...guards)- Combine guards with AND logiccombineGuardsOr(...guards)- Combine guards with OR logic
URL Utilities
parseQueryParams(search)- Parse query stringbuildQueryString(params)- Build query stringbuildRoutePath(routePath, params)- Build path with parametersnormalizePath(path)- Normalize URL pathjoinPaths(...paths)- Join path segments
Route Matching
RouteMatcher- Class for route matchingcreateRouteMatcher(routes, basePath?, caseSensitive?)- Create matcher instanceflattenRoutes(routes, parentPath?)- Flatten nested routes
Navigation
Navigator- Class for navigation managementcreateNavigator(basePath?, hashMode?)- Create navigator instance
Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
