Метаданные маршрутов

Universal Router — это гибкая библиотека маршрутизации для JavaScript, которая позволяет описывать маршруты не только через путь и обработчик, но и через метаданные, расширяющие возможности навигации и управления приложением. Метаданные — это объект с произвольными свойствами, который можно прикрепить к каждому маршруту для хранения дополнительной информации, полезной для контроллеров, middleware или UI.

Метаданные не влияют на поведение маршрутизатора напрямую, но служат инструментом для контроля доступа, логирования, SEO и кастомной логики.


Определение метаданных маршрута

Метаданные задаются через поле meta в описании маршрута:

import UniversalRouter from 'universal-router';

const routes = [
  {
    path: '/dashboard',
    component: Dashboard,
    meta: {
      requiresAuth: true,
      title: 'Панель управления',
      roles: ['admin', 'editor']
    }
  },
  {
    path: '/login',
    component: Login,
    meta: {
      requiresAuth: false,
      title: 'Вход в систему'
    }
  }
];

const router = new UniversalRouter(routes);

Ключевые моменты:

  • meta — это объект с произвольными ключами.
  • Значения метаданных могут быть строками, числами, массивами или функциями.
  • Метаданные доступны в объекте context.route.meta при обработке маршрута.

Использование метаданных в обработчиках

Метаданные помогают реализовать условную логику внутри маршрутов. Например, проверка авторизации перед загрузкой компонента:

const router = new UniversalRouter(routes, {
  resolveRoute: async (context) => {
    const { route } = context;

    if (route.meta?.requiresAuth && !context.user.isAuthenticated) {
      return router.resolve({ pathname: '/login' });
    }

    return route.component;
  }
});

Здесь:

  • Проверяется флаг requiresAuth в meta.
  • В случае отсутствия авторизации происходит перенаправление на /login.
  • Контекст маршрута (context) всегда содержит route, включая его метаданные.

Метаданные и динамические маршруты

Метаданные особенно полезны для маршрутов с параметрами, позволяя хранить информацию, зависящую от параметров:

const routes = [
  {
    path: '/user/:id',
    component: UserProfile,
    meta: (params) => ({
      title: `Профиль пользователя ${params.id}`,
      canEdit: params.id === '1' // только пользователь с id=1 может редактировать
    })
  }
];
  • В этом случае meta может быть функцией, которая принимает параметры маршрута.
  • Это позволяет динамически формировать заголовки страниц, права доступа или другие свойства.

Интеграция метаданных с UI

Метаданные можно использовать для управления отображением интерфейса:

  • Заголовки страниц:
document.title = context.route.meta?.title || 'Приложение';
  • Отображение элементов меню:
const menuItems = routes.filter(r => r.meta?.showInMenu);
  • Управление доступом к компонентам:
if (!route.meta?.roles.includes(user.role)) {
  return router.resolve({ pathname: '/403' });
}

Таким образом, метаданные позволяют хранить правила отображения и безопасности рядом с маршрутом, не смешивая их с бизнес-логикой компонентов.


Вложенные маршруты и наследование метаданных

Universal Router поддерживает вложенные маршруты. Метаданные можно определять как на родительском, так и на дочерних маршрутах:

const routes = [
  {
    path: '/admin',
    meta: { requiresAuth: true },
    children: [
      {
        path: '/users',
        component: UsersList,
        meta: { title: 'Список пользователей' }
      },
      {
        path: '/settings',
        component: Settings,
        meta: { title: 'Настройки системы' }
      }
    ]
  }
];
  • При необходимости можно создавать логики наследования метаданных, комбинируя значения родителя и дочернего маршрута.
  • Это удобно для установки общих правил (например, авторизация) на уровне родительского маршрута и уточнения деталей на уровне дочерних маршрутов.

Метаданные и middleware

Метаданные часто используют вместе с middleware для централизованной обработки:

async function authMiddleware(context, next) {
  if (context.route.meta?.requiresAuth && !context.user.isAuthenticated) {
    return context.router.resolve({ pathname: '/login' });
  }
  return next();
}

const router = new UniversalRouter(routes, {
  context: { user },
  resolveRoute: async (context) => authMiddleware(context, () => context.route.component)
});
  • Middleware может использовать любые ключи meta для проверки прав, логирования или отслеживания событий.
  • Универсальный подход позволяет поддерживать единое место для всех проверок, не загромождая компоненты.

Рекомендации по использованию метаданных

  1. Разделение ответственности: хранить только информацию, связанную с маршрутом, а не логику самого компонента.
  2. Использование функций: для динамических значений метаданных использовать функции, принимающие параметры маршрута.
  3. Стандартизация ключей: использовать предопределённые ключи (title, requiresAuth, roles, showInMenu) для консистентности.
  4. Минимизация вложенности: не перегружать meta большим количеством данных — оставлять только то, что реально используется в логике маршрутизации.

Метаданные в Universal Router предоставляют мощный инструмент для гибкой маршрутизации, управления доступом и интеграции с UI, делая маршруты не просто путями, а носителями всей дополнительной информации, необходимой для работы приложения.