Кастомные резолверы в Universal Router позволяют полностью контролировать процесс обработки маршрутов, расширяя стандартный механизм поиска маршрута. Резолверы отвечают за определение того, как библиотека находит подходящий маршрут и возвращает результат. В стандартной конфигурации Universal Router использует дефолтный резолвер, который ищет совпадение по пути и выполняет соответствующий обработчик. Кастомный резолвер предоставляет возможность модифицировать этот процесс для особых требований: логирования, асинхронной обработки, авторизации, динамического разрешения маршрутов.
Резолвер — это функция с определённой сигнатурой:
async function customResolver(route, context, next) {
// route — текущий маршрут
// context — объект контекста маршрутизации
// next — функция для передачи управления следующему резолверу
}
path, action, children,
name.router.resolve(context) и доступен в каждом резолвере.Резолвер должен вернуть результат маршрутизации, либо вызвать
next() для продолжения поиска.
Для начала можно создать резолвер, который логирует каждый маршрут перед выполнением его обработчика:
import UniversalRouter from 'universal-router';
const routes = [
{ path: '/', action: () => 'Главная' },
{ path: '/about', action: () => 'О нас' },
];
const loggerResolver = async (route, context, next) => {
console.log(`Попытка обработки маршрута: ${route.path}`);
const result = await next();
console.log(`Результат маршрута: ${result}`);
return result;
};
const router = new UniversalRouter(routes, {
resolveRoute: loggerResolver
});
router.resolve({ pathname: '/' }).then(console.log);
В данном примере loggerResolver выполняет
логирование до и после обработки маршрута. Функция next()
гарантирует, что стандартный обработчик маршрута будет вызван после
логирования.
Кастомные резолверы идеально подходят для интеграции асинхронной логики: загрузки данных, проверки прав доступа, выполнения API-запросов.
const authResolver = async (route, context, next) => {
if (route.meta?.requiresAuth && !context.user) {
return '/login'; // перенаправление на страницу логина
}
return next(); // продолжаем стандартную обработку
};
const router = new UniversalRouter(routes, {
resolveRoute: authResolver
});
Здесь резолвер проверяет наличие пользователя в контексте и при необходимости перенаправляет на страницу логина. Асинхронная проверка возможна, если, например, получать пользователя через API:
const asyncAuthResolver = async (route, context, next) => {
context.user = await fetchUserFromAPI();
if (route.meta?.requiresAuth && !context.user) return '/login';
return next();
};
Universal Router позволяет использовать цепочку резолверов: первый
резолвер может обработать часть логики, второй — другую. Это достигается
вызовом next():
const resolver1 = async (route, context, next) => {
console.log('Резолвер 1');
return next();
};
const resolver2 = async (route, context, next) => {
console.log('Резолвер 2');
return next();
};
const router = new UniversalRouter(routes, {
resolveRoute: async (route, context, next) => resolver1(route, context, () => resolver2(route, context, next))
});
Цепочка позволяет разделять ответственность: один резолвер занимается авторизацией, другой — логированием, третий — загрузкой данных.
Кастомный резолвер предоставляет возможность создавать маршруты на лету. Например, можно подгружать дочерние маршруты по мере необходимости:
const dynamicResolver = async (route, context, next) => {
if (!route.childrenLoaded && route.loadChildren) {
route.children = await route.loadChildren();
route.childrenLoaded = true;
}
return next();
};
const routes = [
{
path: '/dashboard',
loadChildren: async () => [
{ path: '/stats', action: () => 'Статистика' },
{ path: '/settings', action: () => 'Настройки' },
]
}
];
const router = new UniversalRouter(routes, { resolveRoute: dynamicResolver });
Резолвер динамически загружает дочерние маршруты при первом обращении, позволяя реализовать ленивую загрузку компонентов.
Контекст (context) передаётся при вызове
router.resolve(context) и доступен во всех резолверах. Его
можно использовать для передачи состояния, например, данных
пользователя, конфигурации приложения или маршрута перенаправления.
const contextResolver = async (route, context, next) => {
context.startTime = Date.now();
const result = await next();
console.log(`Время обработки маршрута: ${Date.now() - context.startTime}мс`);
return result;
};
router.resolve({ pathname: '/about', user: { id: 1 } }).then(console.log);
Кастомные резолверы могут ловить ошибки отдельных маршрутов и возвращать альтернативный результат или перенаправление:
const errorHandlingResolver = async (route, context, next) => {
try {
return await next();
} catch (err) {
console.error(`Ошибка маршрута ${route.path}:`, err);
return '/error';
}
};
Это позволяет централизованно управлять ошибками, избегая дублирования кода обработки исключений в каждом маршруте.
async/await
внутри резолверов.next() для продолжения поиска маршрута,
если логика резолвера не завершает обработку полностью.Кастомные резолверы в Universal Router обеспечивают гибкость маршрутизации, позволяя интегрировать сложные сценарии авторизации, асинхронной загрузки данных и динамического формирования маршрутов, сохраняя при этом ясность и управляемость кода.