В библиотеке Universal Router маршрутизация строится на основе дерева маршрутов, где каждый маршрут может иметь дочерние маршруты. Работа с относительными путями во вложенных роутерах позволяет создавать компактные, модульные маршруты и управлять навигацией без дублирования базовых частей URL.
Вложенные маршруты задаются через свойство children
объекта маршрута. Каждый дочерний маршрут наследует контекст родителя,
что упрощает построение URL и логику обработки. Пример структуры:
import UniversalRouter from 'universal-router';
const routes = [
{
path: '/dashboard',
action: () => 'Главная панель',
children: [
{
path: 'analytics',
action: () => 'Аналитика'
},
{
path: 'settings',
action: () => 'Настройки'
}
]
}
];
const router = new UniversalRouter(routes);
Здесь маршруты analytics и settings
являются относительными, их полный путь формируется автоматически:
/dashboard/analytics и
/dashboard/settings.
Относительные пути не начинаются с символа /. Если
указать путь с ведущим /, Universal Router интерпретирует
его как абсолютный, игнорируя родительский маршрут.
Пример различия:
// Абсолютный путь
{ path: '/settings', action: () => 'Настройки' }
// Относительный путь
{ path: 'settings', action: () => 'Настройки' }
Относительные пути поддерживают динамические сегменты, что позволяет передавать параметры через URL:
const routes = [
{
path: '/users',
children: [
{
path: ':id',
action: ({ params }) => `Пользователь ${params.id}`,
children: [
{
path: 'profile',
action: ({ params }) => `Профиль пользователя ${params.id}`
},
{
path: 'settings',
action: ({ params }) => `Настройки пользователя ${params.id}`
}
]
}
]
}
];
Запрос /users/42/profile вернет строку
"Профиль пользователя 42", а
/users/42/settings —
"Настройки пользователя 42". Параметры автоматически
наследуются вложенными маршрутами.
Дочерний маршрут получает контекст родителя, включая
параметры и дополнительные свойства, переданные через объект
context. Это позволяет создавать маршруты, которые
используют общие данные без повторного определения.
const routes = [
{
path: '/projects',
action: (context) => `Проекты пользователя ${context.user}`,
children: [
{
path: ':projectId',
action: (context, params) => `Проект ${params.projectId} пользователя ${context.user}`
}
]
}
];
const router = new UniversalRouter(routes);
router.resolve('/projects/123', { user: 'Alice' }).then(console.log);
// Результат: "Проект 123 пользователя Alice"
Контекст можно расширять на любом уровне, сохраняя относительные маршруты независимыми от внешнего кода.
children и относительных путейВажное преимущество использования children заключается в
том, что можно создавать группы маршрутов, которые
логически связаны, без дублирования базового пути. Пример модульной
структуры:
const adminRoutes = [
{
path: '/admin',
children: [
{ path: 'users', action: () => 'Управление пользователями' },
{ path: 'roles', action: () => 'Управление ролями' }
]
}
];
const appRoutes = [
{ path: '/', action: () => 'Главная' },
...adminRoutes
];
const router = new UniversalRouter(appRoutes);
/admin/users и /admin/roles формируются
автоматически.path.path, относительный маршрут
считается относительно корня.Относительные маршруты поддерживают асинхронные action
функции:
const routes = [
{
path: '/products',
children: [
{
path: ':id',
async action({ params }) {
const product = await fetch(`/api/products/${params.id}`).then(res => res.json());
return product.name;
}
}
]
}
];
Асинхронность интегрируется на любом уровне вложенности без изменения структуры относительных маршрутов.
async/await на любом уровне.Эта система позволяет строить сложные приложения с глубокой иерархией маршрутов без дублирования кода, сохраняя при этом чистую и понятную структуру URL.