Router5 is capable to run on the server and in clients. This enables you to reuse the same routes for both client-side navigation and server-side pre-rendering. This is essentially done via two steps:
Server-side - Pass to your router the current URL (using start), and pass the resolved state to your client.
Client-side - Pass to your router the starting state received from the server and pass it to your router, so it can start with the provided state (and won't run the transition to the already activated page).
Create your router (client & server)
You can use the same code for configuring your router on both client and server sides. The history plugin, for example, can be safely used on Node.js and in browsers.
This example is an Express with Swig application. Make changes where needed to suit your preferred frameworks.
For universal applications, you need to:
Create a new router instance for each request, using the request URL
Send the state to the client and start your router with this initial state
server.js
import express from'express';import createRouter from'router5';import swig from'swig';constapp=express();// Swig is used for templating in this example// Use what you are comfortable withapp.engine( 'html',swig.renderFile );app.set( 'view engine','html' );app.set( 'views','./views' );app.get( '*', ( req, res ) => {// Create a new router for each requestconstrouter=createRouter();router.start( req.originalUrl,functiondone( error, state ) {if ( error ) {res.status( 500 ).send( error ); } else {res.send(/* Use your router state, send some HTML! */ ); } });} );app.listen( 8080,functionlogServerStart() {console.log( 'Server is listening on port 8080...' );} );
base.html
<!doctype html>
<html lang="en-US">
<head>
<title>Example Server-side Routing</title>
</head>
<body>
<script src="/js/router.js"></script>
<script type="text/javascript">
/**
* Load the App's inital state from the server
* @type {JSON}
*/
var initialState = JSON.parse('{{ initialState | safe }}');
/**
* Start our Router
* @param {Error} error Router start error
* @param {Object} state State Object
* @return {undefined}
*/
app.router.start(initialState, function(error, state) {
if (error) console.error('router error', error);
});
</script>
</body>
</html>
From here forth, you can continue to use router5 as if it was a regular Single-Page Application.
Performance
A new router has to be created server-side on each request. If your app is large (containing dozens of routes), the creation of your router will take up to a couple of hundred milliseconds.
Instead of creating a new router for each request, router5 includes a cloning mechanism: create a base router, and clone it for each request.
A user reported a gain from 300ms to 10ms per request for creating a new router, with cloning.