@revealui/router
v0.2.1
Published
Lightweight file-based router for RevealUI with SSR support
Downloads
39
Readme
@revealui/router
Lightweight, type-safe file-based router for RevealUI with built-in SSR support.
Features
- 🚀 Simple & Fast - Minimal API, maximum performance
- 📁 File-based routing - Convention over configuration
- 🔒 Type-safe - Full TypeScript support
- 🌊 SSR & Hydration - Built-in server-side rendering with React
- 🎯 Hono Integration - First-class support for Hono server
- 📦 No dependencies - Except React and path-to-regexp
- ⚡ Code splitting ready - Supports lazy loading
- 🔗 Data loading - Built-in loader support per route
Installation
pnpm add @revealui/routerQuick Start
1. Define Your Routes
import { Router, type Route } from '@revealui/router'
import Home from './pages/Home'
import About from './pages/About'
import Post from './pages/Post'
const routes: Route[] = [
{
path: '/',
component: Home,
meta: { title: 'Home' },
},
{
path: '/about',
component: About,
meta: { title: 'About Us' },
},
{
path: '/posts/:id',
component: Post,
loader: async ({ id }) => {
const post = await fetch(`/api/posts/${id}`).then(r => r.json())
return { post }
},
},
]
const router = new Router()
router.registerRoutes(routes)2. Client-Side Usage
import { RouterProvider, Routes, Link } from '@revealui/router'
function App() {
return (
<RouterProvider router={router}>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes />
</RouterProvider>
)
}3. Server-Side Rendering (SSR)
import { Hono } from 'hono'
import { createSSRHandler } from '@revealui/router/server'
import routes from './routes'
const app = new Hono()
app.get('*', createSSRHandler(routes, {
template: (html, data) => `
<!DOCTYPE html>
<html>
<head>
<title>${data?.title || 'My App'}</title>
</head>
<body>
<div id="root">${html}</div>
<script id="__REVEALUI_DATA__" type="application/json">
${JSON.stringify(data)}
</script>
<script type="module" src="/client.js"></script>
</body>
</html>
`,
}))API Reference
Router
const router = new Router(options)Methods:
register(route: Route)- Register a single routeregisterRoutes(routes: Route[])- Register multiple routesmatch(url: string)- Match a URL to a routeresolve(url: string)- Match and load route datanavigate(url: string, options?)- Client-side navigationback()/forward()- Browser history navigationsubscribe(listener)- Subscribe to route changesinitClient()- Initialize client-side routing
Components
<RouterProvider>
Provides router instance to your app:
<RouterProvider router={router}>
<App />
</RouterProvider><Routes>
Renders the matched route component:
<Routes /><Link>
Client-side navigation link:
<Link to="/about" replace={false}>
About Us
</Link><Navigate>
Declarative navigation:
<Navigate to="/login" replace />Hooks
useRouter()
Access the router instance:
const router = useRouter()
router.navigate('/about')useParams()
Get route parameters:
const { id } = useParams<{ id: string }>()useData()
Get route data from loader:
const { post } = useData<{ post: Post }>()useMatch()
Get current route match:
const match = useMatch()
console.log(match?.route.path, match?.params)useNavigate()
Get navigation function:
const navigate = useNavigate()
navigate('/about', { replace: true })Route Patterns
Supports path-to-regexp patterns:
'/posts/:id' // Named parameter
'/posts/:id?' // Optional parameter
'/posts/:id(\\d+)' // Parameter with regex
'/posts/*' // Wildcard
'/posts/:path*' // Wildcard with nameData Loading
Routes can have loaders for data fetching:
{
path: '/user/:id',
component: UserProfile,
loader: async ({ id }) => {
const user = await fetchUser(id)
return { user }
},
}Access data in your component:
function UserProfile() {
const { user } = useData<{ user: User }>()
return <div>{user.name}</div>
}Layouts
Wrap routes with layouts:
{
path: '/dashboard',
component: Dashboard,
layout: DashboardLayout,
}Layout component:
function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className="dashboard">
<Sidebar />
<main>{children}</main>
</div>
)
}SSR with Streaming
Enable streaming SSR for better performance:
createSSRHandler(routes, {
streaming: true,
onError: (error, context) => {
console.error('SSR Error:', error)
},
})Dev Server
Quick development server:
import { createDevServer } from '@revealui/router/server'
await createDevServer(routes, {
port: 3000,
template: (html, data) => `...`,
})Integration with RevealUI
Works seamlessly with other RevealUI packages:
import { Router } from '@revealui/router'
import { getRevealUI } from '@revealui/core'
const router = new Router()
router.register({
path: '/cms/:slug',
component: CMSPage,
loader: async ({ slug }) => {
const revealui = await getRevealUI()
const page = await revealui.find({
collection: 'pages',
where: { slug: { equals: slug } },
})
return { page: page.docs[0] }
},
})TypeScript
Full type safety:
import type { Route, RouteParams } from '@revealui/router'
interface PostParams extends RouteParams {
id: string
}
const route: Route = {
path: '/posts/:id',
component: Post,
loader: async (params: PostParams) => {
// params.id is typed as string
return { post: await fetchPost(params.id) }
},
}Comparison with Other Routers
| Feature | @revealui/router | TanStack Router | React Router | |---------|-----------------|-----------------|--------------| | Bundle Size | ~5KB | ~50KB | ~20KB | | SSR Built-in | ✅ | ⚠️ Requires Start | ⚠️ Complex setup | | Type Safety | ✅ | ✅ | ⚠️ Limited | | Data Loading | ✅ | ✅ | ✅ | | Learning Curve | Low | Medium | Low |
License
MIT - RevealUI
Contributing
See CONTRIBUTING.md
