Awesome
dush-router
A simple regex-based router for
dush
,base
,minibase
and anything based on them. Works on Browser and Node.js
You might also be interested in dush-no-chaining, dush-methods and dush-tap-report, a plugins for dush microscopic event emitter with simple & powerful plugin system.
Quality 👌
<!-- uncomment when need --> <!-- [![develop deps][daviddm-devdeps-img]][daviddm-devdeps-url] -->By using commitizen and conventional commit messages, maintaining meaningful ChangeLog and commit history based on global conventions, following StandardJS code style through ESLint and having always up-to-date dependencies through integrations like GreenKeeper and David-DM service, this package has top quality.
Stability 💯
By following Semantic Versioning through standard-version releasing tool, this package is very stable and its tests are passing both on Windows (AppVeyor) and Linux (CircleCI) with results from 100% to 400% test coverage, reported respectively by CodeCov and nyc (istanbul).
Support :clap:
If you have any problems, consider opening an issue, ping me on twitter (@tunnckoCore), join the support chat room or queue a live session on CodeMentor with me. If you don't have any problems, you're using it somewhere or you just enjoy this product, then please consider donating some cash at PayPal, since this is OPEN Open Source project made with :heart: at Sofia, Bulgaria 🇧🇬.
Highlights :sparkles:
- Small: Really small and lightweight
- Easy: Regex-based routing, for simple cases
- Extensible: Can use path-match under the hood
- Isomorphic: For the browser or Node.js >= v0.10
- Customize: Control over route handler's arguments
- Great: Sane and good defaults, but easy to customize
- Simple: Based on awesome event system like dush
- Stable: Well tested, with 400% coverage
- Modern: Plays well with nanomorph, bel or any other thing
- Allows: Adding multiple handlers on same route
Table of Contents
(TOC generated by verb using markdown-toc)
Install
Install with npm
$ npm install dush-router --save
or install using yarn
$ yarn add dush-router
Usage
For more use-cases see the tests
const dushRouter = require('dush-router')
API
router()
A plugin that adds .createRoute
, .addRoute
and .navigate
methods for any app based on dush, base or minibase. Notice that this plugin emit events - route
if match, and notFound
if not route found on defined routes.
Params
opts
{Object}: no options currentlyreturns
{Function}: a plugin function which should be passed to.use
method
Example
var dush = require('dush')
var router = require('dush-router')
var app = dush()
app.use(router())
console.log(app._routes) // => []
console.log(app.createRoute) // => function
console.log(app.addRoute) // => function
console.log(app.navigate) // => function
.addRoute
Add/register an actual
route
withhandler
to theapp._routes
array. It uses.createRoute
method to create an "route" object that is then pushed toapp._routes
.
Note: If route handler returns something the app.navigate
method
will return that exact value on route match.
Params
route
{String}: a simple route, express-like definition, e.g./user/:id
handler
{Function}: a function to be called whenroute
matchreturns
{Object}: instance for chaining
Example
app.addRoute('/foobar', (context) => {
console.log('state:', context.state) // => { hello: 'world' }
console.log('params:', context.params) // => {}
console.log('route:', context.route) // => '/foobar'
console.log('pathname:', context.pathname) // => '/foobar'
})
app.navigate('/foobar', { hello: 'world' })
// or with params
app.addRoute('/user/:id', ({ state, params, route, pathname }) => {
console.log('Hello ', state.username) // => 'Hello Charlike'
console.log('Your ID is', params.id) // => 'Your ID is 123'
console.log('route', route) // => '/user/:id'
console.log('path', pathname) // => '/user/123'
})
app.navigate('/user/123', { username: 'Charlike' })
.createRoute
Just create a
route
withhandler
, same as.addRoute
method, but without adding it toapp._routes
array. This "route" object contains.match
,.regex
,.route
and.handler
properties. Where.match
is a function that accepts single argument "pathname" to check against givenroute
,.handler
is the passedhandler
function,.regex
is the generated regex for thatroute
string and the.route
is the givenroute
. The.match
function returnsnull
if passed "pathname" string match to the givenroute
but not params andfalse
if passed "pathname" not match.
Note: This method does not call the given route handler.
Params
route
{String}: a simple route, express-like definition, e.g./user/:id
handler
{Function}: a function to be called whenroute
matchreturns
{Object}: a "route" object with few properties
Example
const r = app.createRoute('/user/:id', function abc (params) {
console.log('hi user with id:', params.id)
})
console.log(r.match) // => function
console.log(r.handler) // => function
console.log(r.handler.name) // => 'abc'
console.log(r.route) // => '/user/:id'
console.log(r.regex) // => /^\/user\/(\w+)$/i
var params = r.match('/user/123')
console.log(params) // => { id: 123 }
// manually call the route handler
if (params !== false) {
r.handler(params || {})
}
// not match, so returns `false`
params = r.match('/foobar')
console.log(params) // => false
var route = app.createRoute('/foobie', () => {})
// match, but no params, so return `null`
var res = route.match('/foobie')
console.log(res) // => null
.navigate
Manually navigate to some route with url
pathname
and returns what the route handler returns. You can pass a customstate
which will be passed to route handler's context ascontext.state
. This method firesnotFound
event when not found match, androute
when find a route.
Params
pathname
{String}: a url to navigate tostate
{any}: optionally pass a "state", passed to route's handlerreturns
{any}: basically returns what the route handler return
Example
app.on('notFound', (context) => {
console.log(`sorry ${context.pathname} page not exist`)
console.log('this is incoming state:', context.state)
})
app.navigate('/foo/bar/qux', { aa: 11 })
app.addRoute('/hello/:place', (context) => {
console.log('hi', context.params.place) // => 'hi world'
})
app.navigate('/hello/world')
// remove default "on route" handler
app.off('route')
// and define your custom one,
// to change route handler arguments
app.on('route', (handler, context) => {
return handler(context.state, context.params)
})
// notice the handler signature, it's different than
// the default one seen in above `/hello/:place` route
app.addRoute('/user/:name', (state, params) => {
var name = state.username || params.name
console.log('name:', name) // => 'name: john' or 'name: charlike'
return name
})
// it returns what the route handler return
var res = app.navigate('/user/john')
console.log(res) // => 'john', because there's no passed state
var ret = app.navigate('/user/hey', { username: 'charlike '})
console.log(ret) // => 'charlike'
Notes
About "on route"
You can customize everything. By default, we call the route handler with single "context" object
which contains .route
, .pathname
, .params
and .state
properties.
route
- the route of the handler, e.g./user/:id
pathname
- the incoming url - 1st argument of.navigate
method, e.g./user/charlike
state
- optional "state" for the page - 2nd argument of.navigate
method, e.g.{ foo: 1 }
params
- object, containing the params of the route, e.g.{ id: 'charlike' }
But instead of this you may want to pass more additional arguments to route handler or include
only few of these above. To do this you can off
the default .on('route')
logic and provide
a new logic. The listener of route
event will be passed with (handler, context, el)
signature.
Where handler
is the route handler function, context
is the above context object, and el
can be
the "previous" returned value of the handler call (it is useful for diffing).
In above API docs have existing example, but let's try it again.
// remove the defafult
app.off('route')
Okey, let's say we want our route handlers to have (params, actions)
signature.
We can get the first from the "context" object, but what about "actions". Let's think
of the route handler as "view", so we want to pass some actions to be done on some scenario.
Tip: This is the perfect place to plug in a virtual or real dom diffing algorithm! You definitely should try to use nanomorph here to see the magic! :)
const actions = {
hi: (name) => alert('hi ' + name)
}
app.on('route', (handler, context) => {
return handler(context.params, actions)
})
Now, let's define our simple view with bel, a simple DOM builder using tagged template strings.
const html = require('bel')
app.addRoute('/hello/:name', (params, actions) => {
return html`<div>
<h1>Hello ${params.name}</h1>
<button onclick=${() => actions.hi(params.name)}>Click me to alert you</button>
</div>`
})
This view just outputs one heading and a button, which when is clicked will say "hi" to different persons,
based on the passed url, which in our case will be fired with .navigate
method.
const res = app.navigate('/hello/charlike')
console.log(res) // => DOM element
console.log(res.toString())
// =>
// <div>
// <h1>Hello charlike</h1>
// <button>Click me to alert you</button>
// </div>
And because .navigate
method returns what is returned value from the matched route, we can
easy get the rendered page.
About routing
By default we use really simple approach for covering most common and simple cases. It is similar
to what we see in Express app's routing, where :name
is a placeholder for some param.
But because everything is some simple, small and pluggable, you can create another plugin
that provide a different .createRoute
method, for example using path-match. There's
only few things that you should follow and they can be seen in the source code,
it is pretty small and easy to understand.
Related
- dush-better-use: Adds support for named plugins and better error handling, by overriding the default
.use
method | homepage - dush-methods: Plugin for
dush
and anything based on it. It adds helper.define
and.delegate
methods | homepage - dush-no-chaining: A plugin that removes the emitter methods chaining support for
dush
,base
,minibase
or anything based on them | homepage - dush-options: Adds
.option
,.enable
and.disable
methods to yourdush
application | homepage - dush-promise: Plugin for
dush
that makes it a Deferred promise and adds.resolve
,.reject
,.than
and.catch
methods for more better… more | homepage - dush-tap-report: A simple TAP report producer based on event system. A plugin for
dush
event emitter or anything based on it | homepage - dush: Microscopic & functional event emitter in ~260 bytes, extensible through plugins. | homepage
- minibase-create-plugin: Utility for minibase and base that helps you create plugins | homepage
- minibase-is-registered: Plugin for minibase and base, that adds
isRegistered
method to your application to detect if plugin is already registered and… more | homepage - minibase: Minimalist alternative for Base. Build complex APIs with small units called plugins. Works well with most of the already existing… more | homepage
Contributing
Pull requests and stars are always welcome. For bugs and feature requests, please create an issue.
Please read the contributing guidelines for advice on opening issues, pull requests, and coding standards.
If you need some help and can spent some cash, feel free to contact me at CodeMentor.io too.
In short: If you want to contribute to that project, please follow these things
- Please DO NOT edit README.md, CHANGELOG.md and .verb.md files. See "Building docs" section.
- Ensure anything is okey by installing the dependencies and run the tests. See "Running tests" section.
- Always use
npm run commit
to commit changes instead ofgit commit
, because it is interactive and user-friendly. It uses commitizen behind the scenes, which follows Conventional Changelog idealogy. - Do NOT bump the version in package.json. For that we use
npm run release
, which is standard-version and follows Conventional Changelog idealogy.
Thanks a lot! :)
Building docs
Documentation and that readme is generated using verb-generate-readme, which is a verb generator, so you need to install both of them and then run verb
command like that
$ npm install verbose/verb#dev verb-generate-readme --global && verb
Please don't edit the README directly. Any changes to the readme must be made in .verb.md.
Running tests
Clone repository and run the following in that cloned directory
$ npm install && npm test
Author
Charlike Mike Reagent
License
Copyright © 2017, Charlike Mike Reagent. Released under the MIT License.
This file was generated by verb-generate-readme, v0.4.3, on April 02, 2017.
Project scaffolded using charlike cli.