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

slyrouter

v0.0.1

Published

Simple vanilla js router for wapka, wapkiz, and other normal sites

Readme

SlyRouter 🚀

An expressJS-inspired lightweight, powerful client-side router for modern web applications. Works everywhere - ESM, CommonJS, and browsers (including wapka, wapkiz, xtgem)!

Installation

npm install slyrouter

Quick Start

ESM (Modern Bundlers)

// Main Router (Express-style)
import SlyRouter from 'slyrouter';
const router = new SlyRouter();

// Core components
import { EnhancedComponent, StateManager } from 'slyrouter/core';

// Plugins
import { SEOPlugin } from 'slyrouter/plugins';

// Utilities
import { DOM, parseQueryString } from 'slyrouter/utils';

CommonJS (Node.js)

// Main Router (Express-style)
const SlyRouter = require('slyrouter');
const router = new SlyRouter();

// Core components
const { EnhancedComponent, StateManager } = require('slyrouter/core');

// Plugins  
const { SEOPlugin } = require('slyrouter/plugins');

// Utilities
const { DOM, parseQueryString } = require('slyrouter/utils');

UMD (Browser - Script Tag)

<script src="https://unpkg.com/slyrouter"></script>
<script>
  // Main Router (Express-style)
  const router = new SlyRouter();
  
  // Core components are available on the main object
  const { EnhancedComponent, StateManager } = SlyRouter;
</script>

Architecture

SlyRouter follows an Express.js-inspired architecture:

  • Main Export: import SlyRouter from 'slyrouter' - The main Router class
  • Core Components: import { EnhancedComponent } from 'slyrouter/core' - Building blocks
  • Plugins: import { SEOPlugin } from 'slyrouter/plugins' - Extended functionality
  • Utilities: import { DOM } from 'slyrouter/utils' - Helper functions

This modular approach allows for optimal tree-shaking and lets you import only what you need.

Core Concepts

🛣️ Router

The main router class that handles navigation and route management.

Constructor

const router = new SlyRouter(options);

Options:

  • root (string): Base path for all routes (default: '/')
  • mode (string): 'history' or 'hash' (default: 'history')
  • linkSelector (string): Selector for links to handle (default: '[data-sly-link]')
  • formSelector (string): Selector for forms to handle (default: '[data-sly-form]')
  • container (string): DOM element to render components (default: '#app')
  • loadingTemplate (string): HTML to show during loading
  • errorTemplate (string): HTML to show on errors
  • state (object): StateManager options
  • auth (object): AuthService options

Examples:

// ESM
import SlyRouter from 'slyrouter';
const router = new SlyRouter({ container: '#app' });

// CommonJS  
const SlyRouter = require('slyrouter');
const router = new SlyRouter({ container: '#app' });

// UMD (browser)
const router = new SlyRouter({ container: '#app' });

Methods

addRoute(path, component, options)

Add a route to the router.

router.addRoute('/user/:id', UserComponent, {
  name: 'user-profile',
  title: 'User Profile',
  meta: { requiresAuth: true },
  guards: [authGuard]
});

Parameters:

  • path (string): Route path with optional parameters (/user/:id)
  • component (Class): Component class to render
  • options (object): Route configuration

Route Options:

  • name (string): Route name for programmatic navigation
  • title (string|function): Page title or function that returns title
  • meta (object): Route metadata for guards and SEO
  • guards (array): Array of guard functions
navigate(path, options)

Navigate to a route.

// Basic navigation
router.navigate('/about');

// With query parameters
router.navigate('/search', { query: { q: 'javascript' } });

// Replace current history entry
router.navigate('/login', { replace: true });

Options:

  • query (object): Query parameters to include
  • replace (boolean): Replace history entry instead of pushing
back(), forward(), go(delta)

Browser history navigation.

router.back();    // Go back
router.forward(); // Go forward  
router.go(-2);    // Go back 2 pages
addMiddleware(middleware)

Add global middleware.

router.addMiddleware(async (context, router) => {
  console.log('Navigating to:', context.route.path);
});
use(plugin, options)

Use a plugin.

router.use(AnalyticsPlugin, { trackingId: 'UA-XXXXX' });
getCurrentRoute(), getParams(), getQuery()

Get current route information.

const currentRoute = router.getCurrentRoute();
const params = router.getParams(); // Route parameters
const query = router.getQuery();   // URL query parameters

🧩 EnhancedComponent

Base class for creating components with lifecycle methods and state management.

Basic Component

// ESM
import { EnhancedComponent } from 'slyrouter/core';

class HomePage extends EnhancedComponent {
  constructor() {
    super();
    this.state = { count: 0 };
  }
  
  render() {
    return `
      <div>
        <h1>Count: ${this.state.count}</h1>
        <button data-sly-on="click:incrementCount">Increment</button>
      </div>
    `;
  }
  
  incrementCount() {
    this.setState({ count: this.state.count + 1 });
  }
}

// CommonJS
const { EnhancedComponent } = require('slyrouter/core');
class HomePage extends EnhancedComponent { /* ... */ }

// UMD - Note: In UMD, core components are on main object
class HomePage extends SlyRouter.EnhancedComponent { /* ... */ }

Lifecycle Methods

beforeEnter(context)

Called before component enters.

async beforeEnter(context) {
  console.log('Entering route with params:', context.params);
  await this.loadData(context.params.id);
}
afterEnter(context)

Called after component enters.

afterEnter(context) {
  this.setupAnalytics();
}
beforeLeave()

Called before component leaves.

beforeLeave() {
  this.cleanupEvents();
}
afterLeave()

Called after component leaves.

afterLeave() {
  console.log('Component left');
}
mount(container, context)

Called when component mounts to DOM.

async mount(container, context) {
  await this.beforeMount();
  this.element = container;
  this.update();
  await this.afterMount();
}
unmount()

Called when component unmounts from DOM.

async unmount() {
  await this.beforeUnmount();
  this.eventManager.unbindAll();
  await this.afterUnmount();
}

State Management

setState(newState)

Update component state and re-render.

this.setState({ count: 42, message: 'Hello' });
subscribeToState(key, callback)

Subscribe to global state changes.

this.subscribeToState('user', (user) => {
  this.setState({ currentUser: user });
});

Event Handling

Use data-sly-on attributes for automatic event binding:

render() {
  return `
    <button data-sly-on="click:handleClick; mouseenter:handleHover">
      Interactive Button
    </button>
  `;
}

handleClick(event, element) {
  console.log('Button clicked!');
}

handleHover(event, element) {
  element.style.backgroundColor = 'yellow';
}

Navigation

navigate(path, options)

Navigate from within component.

this.navigate('/dashboard');
this.navigate('/search', { query: { q: 'test' } });

Utility Methods

$(selector) and $$(selector)

DOM query helpers.

const button = this.$('button.submit');
const allInputs = this.$$('input[type="text"]');
createElement(tag, attributes, children)

Create DOM elements.

const div = this.createElement('div', { class: 'card' }, 'Hello World');

🗂️ StateManager

Global state management with persistence.

Usage

// ESM
import { StateManager } from 'slyrouter/core';

// CommonJS
const { StateManager } = require('slyrouter/core');

// UMD
const stateManager = new SlyRouter.StateManager();

Methods

set(key, value, persist)

Set state value.

stateManager.set('user', userData, true); // persist to localStorage
stateManager.set('theme', 'dark');        // volatile
get(key)

Get state value.

const user = stateManager.get('user');
subscribe(key, callback)

Subscribe to state changes.

const unsubscribe = stateManager.subscribe('user', (user) => {
  console.log('User changed:', user);
});

// Later...
unsubscribe(); // Stop listening
clear()

Clear all state.

stateManager.clear();

🔐 AuthService

Authentication service with token management.

Usage

// ESM
import { AuthService } from 'slyrouter/core';

// CommonJS  
const { AuthService } = require('slyrouter/core');

// UMD
const authService = new SlyRouter.AuthService();

Methods

login(credentials)

Authenticate user.

try {
  const user = await authService.login({
    email: '[email protected]',
    password: 'password'
  });
  console.log('Logged in:', user);
} catch (error) {
  console.error('Login failed:', error);
}
logout()

Logout user.

await authService.logout();
isAuthenticated()

Check if user is authenticated.

const authenticated = await authService.isAuthenticated();
if (authenticated) {
  // User is logged in
}
hasRole(role)

Check if user has specific role.

const isAdmin = await authService.hasRole('admin');
getUser(), getToken()

Get current user and token.

const user = authService.getUser();
const token = authService.getToken();

🛠️ Utilities

parseQueryString(queryString)

Parse URL query string.

import { parseQueryString } from 'slyrouter/utils';

const query = parseQueryString('?search=test&page=1');
// { search: 'test', page: '1' }

buildURL(path, queryParams)

Build URL with query parameters.

import { buildURL } from 'slyrouter/utils';

const url = buildURL('/search', { q: 'test', page: 2 });
// '/search?q=test&page=2'

debounce(fn, delay) and throttle(fn, delay)

Rate limiting functions.

import { debounce } from 'slyrouter/utils';

const search = debounce((query) => {
  // API call
}, 300);

DOM Utilities

DOM manipulation helpers.

import { DOM } from 'slyrouter/utils';

DOM.updateMetaTag('description', 'Page description');
const element = DOM.createElement('div', { class: 'card' }, 'Content');

EventManager

Event management with automatic cleanup.

import { EventManager } from 'slyrouter/utils';

const events = new EventManager();
events.bind(button, 'click', () => console.log('clicked'));
events.unbindAll(); // Cleanup

Complete Examples

ESM Example

import SlyRouter from 'slyrouter';
import { EnhancedComponent } from 'slyrouter/core';

class App extends EnhancedComponent {
  constructor() {
    super();
    this.state = { user: null };
  }
  
  async beforeEnter(context) {
    this.subscribeToState('user', (user) => {
      this.setState({ user });
    });
  }
  
  render() {
    return `
      <nav>
        <a href="/" data-sly-link>Home</a>
        <a href="/about" data-sly-link>About</a>
        ${this.state.user ? `
          <a href="/dashboard" data-sly-link>Dashboard</a>
        ` : ''}
      </nav>
      <div id="app-content"></div>
    `;
  }
}

const router = new SlyRouter({ container: '#app-content' });

router.addRoute('/', HomeComponent, { title: 'Home' });
router.addRoute('/about', AboutComponent, { title: 'About' });
router.addRoute('/dashboard', DashboardComponent, { 
  meta: { requiresAuth: true },
  guards: [authGuard]
});

// Start the app
router.navigate('/');

CommonJS Example

const SlyRouter = require('slyrouter');
const { EnhancedComponent } = require('slyrouter/core');

class HomeComponent extends EnhancedComponent {
  render() {
    return '<h1>Welcome Home!</h1>';
  }
}

const router = new SlyRouter();
router.addRoute('/', HomeComponent);
router.navigate('/');

UMD Browser Example

<!DOCTYPE html>
<html>
<head>
  <title>SlyRouter Example</title>
</head>
<body>
  <div id="app"></div>
  
  <script src="https://unpkg.com/slyrouter"></script>
  <script>
    // Main Router (Express-style)
    const router = new SlyRouter({ container: '#app' });
    
    // Core components are available on SlyRouter object
    class HomePage extends SlyRouter.EnhancedComponent {
      render() {
        return '<h1>Hello from SlyRouter!</h1>';
      }
    }
    
    router.addRoute('/', HomePage);
    router.navigate('/');
  </script>
</body>
</html>

Route Guards

Create route guards for authentication and authorization:

// Authentication guard
const authGuard = async ({ to, from, router }) => {
  const isAuthenticated = await router.authService.isAuthenticated();
  if (!isAuthenticated) {
    return '/login'; // Redirect to login
  }
  return true; // Allow navigation
};

// Role-based guard  
const adminGuard = async ({ to, from, router }) => {
  const isAdmin = await router.authService.hasRole('admin');
  if (!isAdmin) {
    return '/unauthorized';
  }
  return true;
};

// Usage
router.addRoute('/admin', AdminComponent, {
  guards: [authGuard, adminGuard]
});

Form Handling

Handle forms without page reloads:

<form data-sly-form action="/api/contact" method="POST">
  <input type="text" name="name" required>
  <input type="email" name="email" required>
  <button type="submit">Send</button>
</form>

In your component:

async handleFormResponse(result, form) {
  if (result.success) {
    this.showSuccess('Message sent!');
    form.reset();
  } else {
    this.showError('Failed to send message');
  }
}

async handleFormError(error, form) {
  this.showError('Network error: ' + error.message);
}

Advanced Features

Middleware System

Add global middleware for cross-cutting concerns:

// Logging middleware
router.addMiddleware(async (context, router) => {
  console.log(`Route change: ${context.from?.path} -> ${context.to.path}`);
});

// Authentication middleware
router.addMiddleware(async (context, router) => {
  if (context.to.meta?.requiresAuth) {
    const authenticated = await router.authService.isAuthenticated();
    if (!authenticated) {
      router.navigate('/login');
      return false; // Stop navigation
    }
  }
});

Plugin System

Extend SlyRouter with plugins:

// Using built-in plugins
import { SEOPlugin, AnalyticsPlugin } from 'slyrouter/plugins';

router.use(SEOPlugin, {
  defaultTitle: 'My App',
  defaultDescription: 'A modern web application'
});

router.use(AnalyticsPlugin, {
  trackingId: 'UA-XXXXX-Y'
});

// Creating custom plugins
function MyPlugin(router, options) {
  router.addMiddleware(async (context) => {
    // Plugin logic here
  });
}

router.use(MyPlugin, { customOption: true });

State Persistence

Persist state across page reloads:

import { StateManager } from 'slyrouter/core';

const stateManager = new StateManager({
  persistenceKey: 'myapp_state',
  persistKeys: ['user', 'settings', 'theme'] // Only these keys persist
});

// This will be saved to localStorage
stateManager.set('user', userData, true);

// This will not persist
stateManager.set('temporaryData', data);

Browser Support

  • Modern browsers (Chrome, Firefox, Safari, Edge)
  • IE11+ (with polyfills)
  • Node.js 14+
  • Mobile browsers
  • Legacy platforms (wapka, wapkiz, xtgem)

Migration Guide

From v0.0.0 to v0.0.1

Before:

import { Router } from 'slyrouter';

After:

import SlyRouter from 'slyrouter';
// or
import { Router } from 'slyrouter/core';

API Reference

Router Class

  • new SlyRouter(options)
  • addRoute(path, component, options)
  • navigate(path, options)
  • back(), forward(), go(delta)
  • addMiddleware(middleware)
  • use(plugin, options)
  • getCurrentRoute(), getParams(), getQuery()

EnhancedComponent Class

  • Lifecycle: beforeEnter, afterEnter, beforeLeave, afterLeave
  • State: setState, subscribeToState
  • Navigation: navigate
  • Utilities: $, $$, createElement

StateManager Class

  • set(key, value, persist)
  • get(key)
  • subscribe(key, callback)
  • clear()

AuthService Class

  • login(credentials)
  • logout()
  • isAuthenticated()
  • hasRole(role)
  • getUser(), getToken()

Contributing

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

License

MIT © Quabynah Davis