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

olova-router

v1.0.21

Published

Next.js-inspired router for Olova framework with 9 advanced routing features including prefetching, transitions, metadata, dynamic routes, route groups, parallel routes, and intercepting routes

Readme

olova-router

A powerful, feature-rich router for Olova framework with advanced routing capabilities, middleware support, and lazy loading.

Features

  • 🚀 Browser History & Hash Modes - Support for both history and hash-based routing
  • 🛡️ Route Guards - Protect routes with beforeEnter guards and middleware
  • 🎯 Dynamic Routes - Support for dynamic params like /blog/:slug and wildcards
  • 📦 Lazy Loading - Code splitting with lazy component loading
  • 🔗 Named Routes - Reference routes by name instead of path
  • 🎨 Active Link Styling - Automatic active state detection for links
  • 📍 Breadcrumbs - Built-in breadcrumb generation utilities
  • 🔄 Middleware Chain - Composable middleware for cross-cutting concerns
  • 📜 Route History - Track navigation history with utilities
  • Type Safe - Full TypeScript support with comprehensive types

Installation

npm install olova-router
# or
pnpm add olova-router
# or
yarn add olova-router

Quick Start

<script>
  import { BrowserRouter, Link } from "olova-router";
  import Home from "./Home.olova";
  import About from "./About.olova";
  import Blog from "./Blog.olova";

  const routes = [
    {
      path: "/",
      component: Home,
      name: "home"
    },
    {
      path: "/about",
      component: About,
      name: "about"
    },
    {
      path: "/blog/:slug",
      component: Blog,
      name: "blog.show"
    }
  ]
</script>

<nav>
  <Link href="/">Home</Link>
  <Link name="about">About</Link>
  <Link
    name="blog.show"
    params={{ slug: "getting-started" }}
    activeClass="text-emerald-300"
  >
    Blog
  </Link>
</nav>

<BrowserRouter routes={routes} />

Core API

Router Components

  • Router - Base router component
  • BrowserRouter - History mode router (recommended)
  • HashRouter - Hash mode router (for static hosting)
  • Link - Navigation link component
  • Outlet - Nested route outlet

Router Hooks

import { useRouter, useRoute, useParams, useQuery } from "olova-router";

// Get full router API
const router = useRouter();

// Get current route location
const route = useRoute();

// Get route parameters
const params = useParams();

// Get query parameters
const query = useQuery();

Navigation

import { navigate, link } from "olova-router";

// Programmatic navigation
navigate("/about");
navigate({ name: "blog.show", params: { slug: "hello" } });

// With options
navigate("/home", { replace: true, scroll: true });

// Link handler
const handleClick = link("/about");

Advanced Features

Route Guards

Protect routes with guards and middleware:

import { createConditionalGuard, createParamGuard } from "olova-router/guards";

const routes = [
  {
    path: "/admin",
    component: AdminPanel,
    beforeEnter: createConditionalGuard(
      () => isUserAdmin(),
      "/unauthorized"
    )
  },
  {
    path: "/user/:id",
    component: UserProfile,
    beforeEnter: createParamGuard(
      "id",
      (id) => /^\d+$/.test(id),
      "/not-found"
    )
  }
];

Middleware Chain

Compose multiple middleware for route transitions:

import {
  createMiddlewareChain,
  createAuthMiddleware,
  createAnalyticsMiddleware,
  createScrollMiddleware
} from "olova-router/middleware";

const middleware = createMiddlewareChain()
  .use(createAuthMiddleware(() => isAuthenticated(), "/login"))
  .use(createAnalyticsMiddleware((path) => trackPageView(path)))
  .use(createScrollMiddleware(true));

// Execute middleware
const result = await middleware.execute(context);

Lazy Loading

Code split components with lazy loading:

import { lazyComponent, lazyComponentWithFallback } from "olova-router/lazy";

const routes = [
  {
    path: "/dashboard",
    component: lazyComponent(() => import("./Dashboard.olova"))
  },
  {
    path: "/settings",
    component: lazyComponentWithFallback(
      () => import("./Settings.olova"),
      LoadingSpinner,
      ErrorFallback
    )
  }
];

Breadcrumbs

Generate breadcrumbs from route location:

import { generateBreadcrumbs, generateBreadcrumbsFromMatches } from "olova-router/breadcrumbs";

const route = useRoute();
const breadcrumbs = generateBreadcrumbs(route, {
  home: "Home",
  blog: "Blog",
  settings: "Settings"
});

// Or from route matches
const breadcrumbs = generateBreadcrumbsFromMatches(route.matches);

Route History

Track navigation history:

import { createRouterHistory } from "olova-router/history";

const history = createRouterHistory(50); // max 50 entries

history.push("/home");
history.push("/about");

const prev = history.back(); // { path: "/home", timestamp: ... }
const next = history.forward(); // { path: "/about", timestamp: ... }

const entries = history.getHistory();

Route Configuration

Basic Route

{
  path: "/about",
  component: About,
  name: "about"
}

Dynamic Route

{
  path: "/blog/:slug",
  component: BlogPost,
  name: "blog.post"
}

Wildcard Route

{
  path: "/docs/*",
  component: DocsLayout,
  name: "docs"
}

Nested Routes

{
  path: "/dashboard",
  component: DashboardLayout,
  children: [
    { index: true, component: DashboardHome },
    { path: "settings", component: DashboardSettings },
    { path: "profile", component: DashboardProfile }
  ]
}

Route with Guards

{
  path: "/admin",
  component: AdminPanel,
  beforeEnter: async (context) => {
    if (!isAdmin()) {
      return "/unauthorized";
    }
    return true;
  }
}

Route with Props

{
  path: "/user/:id",
  component: UserProfile,
  props: (context) => ({
    userId: context.params.id,
    isAdmin: context.query.admin === "true"
  })
}

Route Redirect

{
  path: "/old-path",
  redirect: "/new-path"
}

Link Component

<script>
  import { Link } from "olova-router";
</script>

<!-- Simple href -->
<Link href="/about">About</Link>

<!-- Named route -->
<Link name="blog.post" params={{ slug: "hello" }}>Read Post</Link>

<!-- With query and hash -->
<Link
  name="search"
  query={{ q: "olova" }}
  hash="results"
>
  Search
</Link>

<!-- Active styling -->
<Link
  href="/about"
  class="nav-link"
  activeClass="active"
  inactiveClass="inactive"
  exact
>
  About
</Link>

<!-- Custom attributes -->
<Link
  href="/external"
  target="_blank"
  rel="noopener noreferrer"
  title="External Link"
>
  External
</Link>

Router Props

type RouterProps = {
  routes: RouterRoutes;
  mode?: "auto" | "history" | "hash"; // default: "auto"
  base?: string; // default: "/"
  scroll?: boolean; // default: true
};

TypeScript Support

Full type safety with comprehensive types:

import type {
  RouteLocation,
  RouteParams,
  RouteQuery,
  RouteTarget,
  RouterApi,
  RouteGuardContext
} from "olova-router";

Vite Plugin

Auto-generate routes from file structure:

// vite.config.ts
import { olovaRouter } from "olova-router/vite";

export default {
  plugins: [olovaRouter()]
};

Best Practices

  1. Use Named Routes - More maintainable than hardcoded paths
  2. Lazy Load Heavy Components - Improve initial load time
  3. Protect Sensitive Routes - Use guards for auth/permissions
  4. Handle 404s - Always include a wildcard route
  5. Scroll Management - Enable scroll reset on navigation
  6. Type Your Routes - Leverage TypeScript for safety

Examples

Authentication Guard

import { createConditionalGuard } from "olova-router/guards";

const authGuard = createConditionalGuard(
  async (context) => {
    const token = localStorage.getItem("auth_token");
    if (!token) return false;

    const valid = await validateToken(token);
    return valid;
  },
  "/login"
);

const routes = [
  {
    path: "/dashboard",
    component: Dashboard,
    beforeEnter: authGuard
  }
];

Analytics Tracking

import { createAnalyticsMiddleware } from "olova-router/middleware";

const analyticsMiddleware = createAnalyticsMiddleware((path) => {
  gtag.pageview({
    page_path: path,
    page_title: document.title
  });
});

Composite Guards

import { createCompositeGuard } from "olova-router/guards";

const protectedGuard = createCompositeGuard([
  createAuthMiddleware(() => isAuthenticated()),
  createRoleMiddleware(() => userRole(), ["admin", "moderator"])
]);

License

MIT