README
🐉 Dragon Router
Dragon Router is an ExpressJS-like client side router built from the ground up on debuggability and simplicity.
It uses the browser's history
API to control the pushing and popping of page navigation;
overwriting the need for a full page refresh on user navigation. Add it to your project with NPM:
npm install --save dragon-router
Try the demo:
Setup and usage
ES6
Router
is an es6 class. Import it like you would any other module. After
setting up your routes (See below), register the router on the
window.
import { Router } from 'dragon-router';
const router = new Router();
... // add routing rules here
router.registerOn(window);
router.start() // run this function after you have established routing rules, so that the router knows it should immediately apply them
CommonJS
If you are using CommonJS, you may import the proper version from the /dist
folder.
const { Router } = require('dragon-router/dist/dragon-router.min.js')
Native Browser Sourcing
Likewise, you can include it in your HTML from a script
tag.
<!-- Globally Registered -->
<script src="/path/to/dragon-router/dist/dragon-router.min.js"></script>
OR
<!-- ES6 Module Imports -->
<script type="module" src="/path/to/dragon-router/dist/dragon-router.module.js"></script>
Options
let options = {
basePath: '/my-app/base/route', // mount the router off of a specific path [default is '/']
routerId: 'my-cool-dragon-router', // unique identifier between apps [default is a random number]
registerOn: window, // bind to the client's browser immediately [if not given, `router.registerOn(...)` must be called separately]
debug: true // show additional logging info [default is false]
}
const router = new Router(options);
Router.use()
The .use()
method allows us to apply matchers or behaviors to the routing.
Route matching
Route matching follows a similar pattern as Express. You can match with literal paths
or parameterized paths (which populate the Context
with parameters).
// render a page on a literal path matching
router.use('/about', renderYourAboutPageCB);
router.use('/:section/:subSection', (context) => {
// prefixing a path section with ':' will name that section in `context.params`
let section = context.params.section;
let subSection = context.params.subSection;
// now you can use the grepped data to apply on your app.
renderYourPageCB(section, subSection);
});
You can append a parameter declaration with (
)
to specify a regex pattern
to enforce a match.
router.use('/:section(home|about)/:subSection', (context) => {
// now, the path will only ever match if the `section` is 'home' or 'about'
let section = context.params.section;
...
});
Additionally, you may apply an array of matchers to a given handler.
router.use(['/home/:subSection', '/about/:subSection'], (context) => {
// your code here
});
Full RegExp
matchers are also supported. (Note that these do not get parameterized, unlike the string matchers mentioned above)
router.use(/^\/some\/fancy\/regular\/expression$/, (context) => {
// your code here
});
Optional Subpaths
Additional syntax of matchers includes *
and ?
postfixes to sections.
The *
postfix (e.g. /your/route*
) will match any incoming route that is
prefixed with the text before the *
character.
The ?
postfix (e.g. /your/:route?
) allows that section of the route to be
optional. If you want to have the router automatically populate an optional section
with data, see Derived Subpaths below.
Derived Subpaths
A DerivedSubpath
allows for a route to specify default values for an optional path.
These are derived from a given callback. The callback for the DerivedSubpath can return
an async
object or a String
. This is especially useful for automatically redirecting
to fully qualified paths in your app.
Here is an example:
let defaultSection = new DerivedSubpath('section', (context) => {
return 'main'; // or whatever you need to do to compute the default `section`
})
router.use(defaultSection);
...
// prefixing a parameter with '