Configuring Aurelia Router and Its Basics: A Complete Guide


Introduction
Routing is a fundamental aspect of any single-page application (SPA), providing seamless navigation without traditional page refreshes. In Aurelia, a powerful JavaScript framework focused on simplicity and convention over configuration, the router plays a crucial role in defining the structure and flow of your application. This comprehensive guide will walk you through configuring Aurelia Router effectively, from basic setup to advanced techniques that will elevate your application architecture.
What is Aurelia Router?
Aurelia Router is a client-side routing solution that enables developers to build applications with multiple screens and navigation paths. It allows users to move between different views while maintaining application state and providing a smooth user experience. The router maps URLs to components, making your application more organized and easier to maintain.
Basic Setup: Getting Started with Aurelia Router
1. Installation and Prerequisites
Before configuring Aurelia Router, ensure you have a working Aurelia application. If you’re starting from scratch, you can create a new project using the Aurelia CLI:
javascriptCopynpm install -g aurelia-cli
au new my-aurelia-app
Aurelia Router comes pre-installed with the standard Aurelia setup, so no additional installation is required.
2. Configuring the Router
The router configuration typically resides in your app’s main component (usually app.js
or app.ts
). Here’s a basic setup:
javascriptCopyexport class App {
configureRouter(config, router) {
this.router = router;
config.title = 'My Aurelia App';
config.map([
{ route: ['', 'home'], name: 'home', moduleId: 'home/index', nav: true, title: 'Home' },
{ route: 'users', name: 'users', moduleId: 'users/index', nav: true, title: 'Users' }
]);
}
}
This configuration:
- Sets the application title
- Maps two routes: a default route (empty path or ‘home‘) and a ‘users’ route
- Specifies which components to load for each route
- Indicates which routes should appear in navigation menus
3. Key Router Configuration Parameters
Each route in your configuration can have several properties:
- route: String or array of strings representing the URL patterns to match
- name: A unique identifier for the route
- moduleId: Path to the component that should be displayed when this route is active
- nav: Boolean indicating whether this route should appear in navigation menus
- title: The title to display for this route in navigation menus
- settings: An object containing custom data associated with the route
Advanced Router Techniques
1. Child Routers
Aurelia supports nested routing, allowing you to create modular applications with hierarchical navigation:
javascriptCopyexport class Users {
configureRouter(config, router) {
config.map([
{ route: ['', 'list'], name: 'userList', moduleId: './list', nav: true, title: 'User List' },
{ route: 'detail/:id', name: 'userDetail', moduleId: './detail', nav: false }
]);
}
}
This creates a child router within the ‘users’ section, with its own navigation and routes.
2. Route Parameters
Dynamic routes with parameters allow you to pass data through the URL:
javascriptCopy// In router config
{ route: 'user/:id', name: 'userProfile', moduleId: 'user/profile' }
// In the component
export class Profile {
activate(params) {
this.userId = params.id;
// Fetch user data based on ID
}
}
3. Route Guards
Route guards provide protection for routes, controlling access based on conditions:
javascriptCopyexport class App {
configureRouter(config, router) {
config.addPipelineStep('authorize', AuthorizeStep);
config.map([
{ route: 'admin', name: 'admin', moduleId: 'admin/index', nav: true, title: 'Admin', settings: { roles: ['admin'] } }
]);
}
}
class AuthorizeStep {
run(navigationInstruction, next) {
const requiredRoles = navigationInstruction.getAllInstructions()
.map(i => i.config.settings?.roles || [])
.reduce((a, b) => a.concat(b), []);
if (requiredRoles.length === 0) {
return next();
}
if (!userHasRole(requiredRoles)) {
return next.cancel(new Redirect('login'));
}
return next();
}
}
4. Redirecting Routes
You can set up automatic redirects for certain routes:
javascriptCopyconfig.map([
{ route: 'legacy-path', redirect: 'new-path' }
]);
5. Lazy Loading Modules
For larger applications, lazy loading modules can significantly improve initial load time:
javascriptCopyconfig.map([
{
route: 'customers',
name: 'customers',
moduleId: './customers/index',
nav: true,
title: 'Customers',
layoutViewModel: './layouts/default',
PLATFORM: {
moduleId: PLATFORM.moduleName('./customers/index')
}
}
]);
Best Practices for Aurelia Router Configuration
1. Organize Routes by Feature
Group related routes together, especially when using child routers. This creates a more maintainable code structure:
javascriptCopy// Main router
config.map([
{ route: '', redirect: 'dashboard' },
{ route: 'dashboard', moduleId: './dashboard/index', nav: true, title: 'Dashboard' },
{ route: 'users', moduleId: './users/index', nav: true, title: 'User Management' },
{ route: 'reports', moduleId: './reports/index', nav: true, title: 'Reports' }
]);
2. Use Descriptive Route Names
Choose meaningful names for your routes to make your code more readable and debugging easier:
javascriptCopy// Avoid
{ route: 'u', name: 'u', moduleId: './users' }
// Better
{ route: 'users', name: 'userManagement', moduleId: './users/management' }
3. Implement Proper Error Handling
Add dedicated routes for handling errors, such as 404 pages:
javascriptCopyconfig.mapUnknownRoutes('not-found');
4. Create Reusable Router Configurations
For complex applications, consider extracting router configurations into separate modules:
javascriptCopy// user-routes.js
export function configureUserRoutes(config) {
config.map([
{ route: '', redirect: 'list' },
{ route: 'list', name: 'userList', moduleId: './list', nav: true, title: 'User List' },
{ route: 'create', name: 'userCreate', moduleId: './create', nav: true, title: 'Create User' },
{ route: 'edit/:id', name: 'userEdit', moduleId: './edit', nav: false }
]);
}
// In your component
import { configureUserRoutes } from './user-routes';
export class Users {
configureRouter(config, router) {
configureUserRoutes(config);
}
}
Dynamic Router Configuration
In real-world applications, you often need to configure routes dynamically based on application state, user permissions, or external data:
javascriptCopyexport class App {
constructor(authService) {
this.authService = authService;
}
configureRouter(config, router) {
this.router = router;
config.title = 'My App';
let routes = [
{ route: ['', 'home'], name: 'home', moduleId: 'home/index', nav: true, title: 'Home' }
];
if (this.authService.isAuthenticated()) {
routes.push(
{ route: 'profile', name: 'profile', moduleId: 'profile/index', nav: true, title: 'Profile' }
);
if (this.authService.hasRole('admin')) {
routes.push(
{ route: 'admin', name: 'admin', moduleId: 'admin/index', nav: true, title: 'Admin' }
);
}
}
config.map(routes);
}
}
Handling Router Events
Aurelia’s router provides several lifecycle hooks that you can use to perform actions during navigation:
javascriptCopyexport class App {
configureRouter(config, router) {
this.router = router;
config.title = 'My App';
config.map([...]);
router.events.subscribe(event => {
if (event.instruction.config.name === 'home') {
// Do something when navigating to home
}
});
}
}
Common router events include:
- navigating: Triggered when navigation begins
- navigatingBack: Triggered when navigating to a previous location
- navigatingForward: Triggered when navigating to a new location
- navigateComplete: Triggered when navigation completes successfully
- navigateError: Triggered when navigation fails
Styling Active Routes
Aurelia provides built-in CSS classes for active routes, making it easy to style your navigation:
htmlCopy<nav>
<ul>
<li repeat.for="route of router.navigation">
<a href.bind="route.href" class="${route.isActive ? 'active' : ''}">${route.title}</a>
</li>
</ul>
</nav>
cssCopy.active {
font-weight: bold;
background-color: #f0f0f0;
}
Working with Hash vs. Push State
Aurelia Router supports both hash-based routing (/#/users
) and push state routing (/users
):
javascriptCopyexport function configure(aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging();
aurelia.start().then(() => {
// Use push state routing with base URL
const root = document.body;
const baseUrl = document.querySelector('base').href;
aurelia.setRoot('app', root, { pushState: true, root: baseUrl });
});
}
Troubleshooting Common Aurelia Router Issues
1. Routes Not Working After Deployment
If your routes work locally but not in production, check your server configuration. With push state routing, the server must redirect all routes to the index.html
file.
For Apache, add a .htaccess
file:
Copy<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
For Nginx:
Copylocation / {
try_files $uri $uri/ /index.html;
}
2. Child Router Navigation Issues
If child routers aren’t working correctly, ensure that parent routes are properly configured to load child routers:
javascriptCopy// Incorrect
{ route: 'users', name: 'users', moduleId: 'users' }
// Correct
{ route: 'users', name: 'users', moduleId: 'users/index', nav: true, title: 'Users' }
3. Route Parameters Not Passing Correctly
If parameters aren’t being passed to your components, check your route syntax:
javascriptCopy// Make sure to use the correct parameter syntax
{ route: 'user/:id', name: 'userDetail', moduleId: './detail' }
Conclusion
Aurelia Router provides a powerful, flexible system for building complex, navigable single-page applications. By following the practices outlined in this guide, you can create well-structured, maintainable routing configurations that will scale with your application’s needs.
Whether you’re building a simple website or a complex enterprise application, mastering Aurelia Router will help you create more organized, user-friendly experiences. Start with the basics and gradually incorporate the more advanced techniques as your application grows.
Remember that effective routing is about more than just technical implementation—it’s about creating intuitive navigation paths that enhance the user experience and reflect the natural organization of your application’s features.
Additional Resources
Aurelia Discourse Forum for community support