Для использования Universal Router на сервере необходимо установить пакет через npm:
npm install universal-router
После установки создаётся базовая структура маршрутизатора. Основной
объект — это экземпляр UniversalRouter, которому передаётся
массив маршрутов. Каждый маршрут представляет собой объект с полями:
path — строка с шаблоном URL;action — функция, вызываемая при совпадении
маршрута;children — массив дочерних маршрутов
(опционально).Пример базовой конфигурации:
import UniversalRouter from 'universal-router';
const routes = [
{
path: '/',
action: () => 'Главная страница'
},
{
path: '/about',
action: () => 'О сайте'
},
{
path: '/user/:id',
action: ({ params }) => `Пользователь с ID: ${params.id}`
}
];
const router = new UniversalRouter(routes);
Universal Router поддерживает асинхронные действия,
что удобно при работе с серверными данными. Функция action
может возвращать Promise. Это позволяет получать данные из
базы или API перед формированием ответа.
const routes = [
{
path: '/posts/:id',
async action({ params }) {
const post = await getPostById(params.id);
if (!post) throw new Error('Пост не найден');
return post;
}
}
];
Асинхронные маршруты обеспечивают гибкость и делают серверный рендеринг динамичным.
При инициализации маршрутизатора можно передать объект
context, который будет доступен во всех
action маршрутах:
const context = {
db,
user: { id: 1, name: 'Admin' }
};
const router = new UniversalRouter(routes, { context });
router.resolve('/user/1').then(result => {
console.log(result); // Доступ к db и user через context
});
Контекст позволяет централизованно хранить глобальные зависимости, такие как база данных, конфигурация или авторизационные данные.
Ошибки внутри маршрутов можно перехватывать с помощью стандартного
try/catch или через метод resolve с
.catch.
router.resolve('/posts/999')
.then(result => console.log(result))
.catch(err => console.error('Ошибка маршрута:', err.message));
Также можно определить маршрут с универсальной обработкой ошибок:
const routes = [
{
path: '*',
action: ({ path }) => `Маршрут ${path} не найден`
}
];
Маршрут с path: '*' выступает в роли fallback и
обрабатывает все неизвестные URL.
Universal Router поддерживает иерархию маршрутов через свойство
children. Это особенно удобно для сложной серверной
архитектуры.
const routes = [
{
path: '/admin',
action: () => 'Админ-панель',
children: [
{
path: '/users',
action: () => 'Список пользователей'
},
{
path: '/settings',
action: () => 'Настройки'
}
]
}
];
Вложенные маршруты могут наследовать контекст и обеспечивают структурированную навигацию без дублирования кода.
Маршруты с параметрами позволяют захватывать части URL. Параметры
задаются через двоеточие :param.
{
path: '/category/:name',
action: ({ params }) => `Категория: ${params.name}`
}
Поддерживается несколько параметров и регулярные выражения для валидации:
{
path: '/order/:id(\\d+)',
action: ({ params }) => `Заказ №${params.id}`
}
Такой подход позволяет строго контролировать формат параметров и избегать ошибок на сервере.
Для серверного рендеринга полезны редиректы и ленивые маршруты:
{
path: '/old-page',
action: () => ({ redirect: '/new-page' })
}
Также маршруты могут загружаться динамически:
{
path: '/dashboard',
async action() {
const module = await import('./dashboard.js');
return module.render();
}
}
Это уменьшает нагрузку на сервер и ускоряет обработку часто посещаемых маршрутов.
Хотя Universal Router не имеет встроенной системы middleware, её
можно реализовать через обёртки action:
async function auth({ context }) {
if (!context.user) throw new Error('Доступ запрещён');
return true;
}
const routes = [
{
path: '/protected',
async action(context) {
await auth(context);
return 'Секретная информация';
}
}
];
Такой подход обеспечивает проверку прав доступа и другие предварительные действия перед основной логикой маршрута.
Universal Router легко интегрируется с Node.js фреймворками:
import express from 'express';
import UniversalRouter from 'universal-router';
const app = express();
const router = new UniversalRouter(routes);
app.use(async (req, res) => {
try {
const result = await router.resolve(req.path);
res.send(result);
} catch (err) {
res.status(404).send(err.message);
}
});
app.listen(3000);
import Koa from 'koa';
import UniversalRouter from 'universal-router';
const app = new Koa();
const router = new UniversalRouter(routes);
app.use(async ctx => {
try {
ctx.body = await router.resolve(ctx.path);
} catch (err) {
ctx.status = 404;
ctx.body = err.message;
}
});
app.listen(3000);
Это делает Universal Router универсальным инструментом для серверного рендеринга и обработки маршрутов без зависимости от конкретного фреймворка.
Для больших приложений рекомендуется кешировать результаты
action, особенно если они требуют запросов к базе данных
или внешним API. Это снижает нагрузку на сервер и ускоряет отклик.
Используются стандартные подходы Node.js: in-memory кеш, Redis или
мемоизация функций маршрутов.
Использование Universal Router на сервере позволяет строить структурированные, динамичные и легко масштабируемые маршруты, обеспечивая асинхронную обработку, проверку параметров и интеграцию с любым серверным фреймворком.