silkrouter

Silk router is an app routing library

Usage no npm install needed!

<script type="module">
  import silkrouter from 'https://cdn.skypack.dev/silkrouter';
</script>

README

Node.js CI License GitHub file size in bytes GitHub file size in bytes

If you are searching for version 3 documentation (previous version), please click on the link below:
https://github.com/scssyworks/silkrouter/blob/master/READMEv3.md

Silk router

Silk router is a reactive app routing library.

Install

npm install --save silkrouter rxjs

What's new?

Silk router uses the Observer pattern instead of EventEmitter pattern used in previous versions. Almost 80% of the code has been re-written. You can use a bunch of operators provided by rxjs as well as silkrouter. You can create your own operators if you want.

RxJS

Silk router uses classes such as Observables and Subscription provided by rxjs. RxJS is a peer dependency which means you need to install it separately.

How to use Silk router

Silkrouter syntax has changed (and for good).

  1. Import
import { Router } from 'silkrouter';
import { route } from 'silkrouter/operators';
...
  1. Create a router instance
const router = new Router();
  1. Add a subscriber
router.subscribe((e) => {
  // This is your new generic route syntax
});
  1. Use route operator to add a path

Use pipe method to chain an operator (similar to RxJS)

router.pipe(route('/path/to/route')).subscribe((e) => {
  // This listens to a specific route '/path/to/route'
});
  1. Trigger a route change
router.set('/path/to/another/route');

You can pipe as many operators you want. Please refer to API section below for more details.

API

Classes

Class Description Options and Example
Router Creates a router instance new Router({ /*Router options*/ })

Router options:

hashRouting[optional] - Enables hash routing (default: false)
preservePath[optional] - Preserves existing pathname when hashRouting is enabled (default: false)
context[optional] - Element reference to bind vpushstate synthetic event (default: document.body)
init[optional] - Enable/disable handler execution on initialization (default: true)

Router methods

Method Description Example
set Sets browser router path routerIns.set(pathStringOrObject[, replace][, exec])

Set parameters:

pathStringOrObject - String or object to configure current path
Examples:
routerIns.set('/example/path')
routerIns.set({ route: '/example/path', /*...otherOptions*/ })
replace[optional] - Use history replaceState function instead of pushState (default: false).
exec[optional] - Disable or enable subscriber execution (default: true)

Path object options: route, data, queryString, preserveQuery (bool), pageTitle, replace (bool), exec (bool)
subscribe Returns RxJS subscription routerIns.subscribe(e => { ... })
pipe Pipes operators to return new observable routerIns.pipe(route('/example/route')).subscribe(e => { ... })
destroy Destroys current router instance routerIns.destroy(() => { /* Unsubscribe your subscriptions here */ })

Operators

Operator Description Example
route Set a filter for specific route path routerIns.pipe(route(path[, routerIns][, ignoreCase])).subscribe(...)

route options:

path - Path filter to apply on generic route observer
routerIns[optional] - Current Router instance. Required only if noMatch operator is used.
ignoreCase[optional] - Ignores the case of current route
deparam Converts query string to JS object Before: routerIns.subscribe(e => { console.log(e.search); }).
Output: a=10&b=20
After: routerIns.pipe(deparam()).subscribe(e => { console.log(e.search); }).
Output: { a:"10", b:"20" }

deparam options:

coerce[optional] - Converts object properties to their correct types
noMatch Adds an optional route for 'page not found' routerIns.pipe(noMatch(routerIns)).subscribe(...)

noMatch options:

routerIns - Router instance for tracking current routes
cache Caches event object to call subscribers only if there is a change in URL or data routerIns.pipe(cache([keys][, deep])).subscribe(e => { ... })

cache options:
keys[optional] - Event object keys which you want to cache and compare
deep[optional] - Enable deep comparison (By default shallow comparison is used)

Examples:
1. Perform shallow comparison of all keys (excluding event objects)
routerIns.pipe(cache()).subscribe(e => { ... })
2. Perform deep comparison
routerIns.pipe(cache(true)).subscribe(e => { ... })
3. Perform comparison on selected keys
routerIns.pipe(cache(['route', 'data'], true)).subscribe(e => { ... })

Examples

Enable hash routing

Unlike previous versions of silk router, hash routing has to be enabled via flag.

const router = new Router({
  hashRouting: true,
});

Your application will continue to run the same way. Hash routing strips away the dependency to define server-side routes for your application (since hash routing is pretty much client-side).

By default hash routes replaces your current path. In order to keep the current path, you need to pass an additional flag called preservePath.

const router = new Router({
  hashRouting: true,
  preservePath: true,
});

Handle error page

Silk router version 4 brings a neat way to handle error pages using operators. It comes with built-in noMatch operator which works as an error handler keeping track of routes that have been added previously, and call subsriber only if a route is missing.

const router = new Router();

router.pipe(route('/first/path', router)).subscribe(() => { ... });
router.pipe(route('/second/path', router)).subscribe(() => { ... });
router.pipe(noMatch(router)).subscribe(() => { ... }); // Called only if "first" and "second" paths are not matched

Make sure to pass the current router instance as parameter.

Passing data

There are three ways you can pass data.

  1. Route params
  2. Query strings
  3. Direct method

Route params

...
router.pipe(route('/route/:with/:params')).subscribe(e => {
    console.log(e.params); // --> { with: 'param1', params: 'param2' }
});
...
router.set('/route/param1/param2');

Query string

router.set('/example/route?with=query&string=true');
// OR
router.set({
  route: '/example/route',
  queryString: 'with=query&string=true',
});

You can preserve existing query string by passing preserveQuery flag.

router.set({
  route: '/example/route',
  queryString: 'with=query&string=true',
  preserveQuery: true, // Default: false
});

Query strings are passed to subscriber as e.search and e.hashSearchparameters (where e is an event object) depending on which router mode is enabled. You might get both under certain circumstances.

Passing data directly

router.subscribe(e => {
    console.log(e.data); // --> Hello World!
});
...
router.set({
    route: '/example/route',
    data: 'Hello World!'
});

Similar to route parameters and query strings, data passed this way is also persisted.

Contribution

Please feel free to raise pull requests for new code fixes and features.