slick-router

A powerful and flexible client side router

Usage no npm install needed!

<script type="module">
  import slickRouter from 'https://cdn.skypack.dev/slick-router';
</script>

README

Slick Router

Slick Router is a powerful, flexible router that translates URL changes into route transitions allowing to put the application into a desired state. It is derived from cherrytree library (see differences).

Features

  • Can be used with any view and data framework
  • Can nest routes allowing to create nested UI and/or state
  • Route transition is a first class citizen - abort, pause, resume, retry
  • Generate links in a systematic way, e.g. router.generate('commit', {sha: '1e2760'})
  • Use pushState or hashchange for URL change detection
  • Define path dynamic segments (uses path-to-regexp under the hood)
  • Supports custom query string parser
  • Trigger router navigate programatically
  • With builtin middlewares/components:
    • Render nested UI using web components
    • Streamlined support for code spliting and lazy loading
    • Expose route state to components
    • Declarative handling of router links
    • Allow to animate route transitions

Installation

The main library size including path-to-regexp dependency is ~15kB minified (without gzip compression). wc and routerLinks middlewares accounts for 3kb each. See webpack test project for more results.

$ npm install --save slick-router

Docs

Builtin middlewares

  • wc (advanced Web Component rendering and lifecycle)
  • routerLinks (handle route related links state)
  • events (fires route events on window)

Builtin components

Usage

import { Router } from 'slick-router';

// route tree definition
const routes = function (route) {
  route('application', {path: '/', component: 'my-app'}, function () {
    route('feed', {path: ''})
    route('messages')
    route('status', {path: ':user/status/:id'})
    route('profile', {path: ':user', private: true}, function () {
      route('profile.lists', {component: 'profile-lists'})
      route('profile.edit', {component: 'profile-edit'})
    })
  })
}

// create the router
var router = new Router({
  routes
})

// renders a web component defined through component option
// or using route name suffixed with "-view"
// for advanced features use builtin wc middleware
router.use(async function render (transition) {
  const routes = transition.routes
  for (const route of routes) {
    const parent = routes[routes.indexOf(route) - 1]
    const tagName = route.options.component || `${route.name}-view`
    const el = route.el = document.createElement(tagName)
    const containerEl = parent ? parent.el.querySelector('.outlet') : document.body
    containerEl.appendChild(el)
    // supports lazy rendering e.g. LitElement and SkateJS
    await (el.updateComplete || Promise.resolve())
  }
})

// protect private routes
router.use(function privateHandler (transition) {
  if (transition.routes.some(route => route.options.private)) {
    if (!userLogged()) {
      transition.cancel()
    }
  }
})

// for error logging attach a catch handler to transition promise...
router.use(function errorHandler (transition) {
  transition.catch(function (err) {
    if (err.type !== 'TransitionCancelled' && err.type !== 'TransitionRedirected') {
      console.error(err.stack)
    }
  })
})

// ...or use the error hook
router.use({
  error: function (transition, err) {
    if (err.type !== 'TransitionCancelled' && err.type !== 'TransitionRedirected') {
      console.error(err.stack)
    }    
  }
})

// start listening to URL changes
router.listen()

Examples

You can also clone this repo and run the examples locally:

Browser Support

Slick Router works in all modern browsers. V1 requires es5 environment and es6 promises. Use polyfills for those if you have to support older browsers, e.g.:


Copyright (c) 2020 Luiz Américo Pereira Câmara

Copyright (c) 2017 Karolis Narkevicius