Синтаксис определения путей

Page.js — это небольшая и эффективная клиентская библиотека для маршрутизации в одностраничных приложениях (SPA) на JavaScript. Центральным элементом работы с Page.js является определение путей (routes), которые связывают URL с функциями-обработчиками.

Создание маршрута

Маршрут создается с помощью функции page(path, callback). Параметры:

  • path — строка, описывающая путь. Может включать динамические сегменты.
  • callback — функция, которая выполняется при совпадении текущего URL с указанным путём.

Пример базового маршрута:

page('/home', () => {
  console.log('Маршрут /home активирован');
});

В этом примере при переходе на /home будет вызвана указанная функция.

Динамические сегменты

Page.js поддерживает параметры в пути, обозначаемые двоеточием :. Эти сегменты передают данные в объект ctx.params.

Пример:

page('/user/:id', (ctx) => {
  console.log('ID пользователя:', ctx.params.id);
});

При переходе на /user/42 будет выведено:

ID пользователя: 42

Можно использовать несколько динамических сегментов:

page('/blog/:year/:month/:slug', (ctx) => {
  console.log(ctx.params.year, ctx.params.month, ctx.params.slug);
});

Опциональные параметры

Маршруты могут содержать опциональные параметры, обозначаемые ?. Если сегмент необязателен, он может отсутствовать в URL.

page('/archive/:year/:month?', (ctx) => {
  console.log(ctx.params.year, ctx.params.month || 'не указан');
});

Переход на /archive/2026 выведет:

2026 не указан

Переход на /archive/2026/03 выведет:

2026 03

Поддержка регулярных выражений

Page.js позволяет использовать регулярные выражения для сложных маршрутов, что повышает гибкость обработки URL.

page(/\/product\/(\d+)\/edit/, (ctx) => {
  const productId = ctx.params[0];
  console.log('Редактирование продукта', productId);
});

Здесь ctx.params — массив, соответствующий группам регулярного выражения.

Маршруты с несколькими обработчиками

Один путь может иметь несколько функций-обработчиков. Это удобно для промежуточной обработки данных, проверки прав доступа или логирования.

page('/dashboard', checkAuth, loadData, renderDashboard);

function checkAuth(ctx, next) {
  if (!ctx.user) {
    page.redirect('/login');
  } else {
    next();
  }
}

function loadData(ctx, next) {
  ctx.data = { stats: [1, 2, 3] };
  next();
}

function renderDashboard(ctx) {
  console.log('Данные для отображения:', ctx.data);
}

Функции вызываются последовательно, и next() передает управление следующему обработчику.

Глобальные маршруты и middleware

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

page((ctx, next) => {
  console.log('Переход на:', ctx.path);
  next();
});

Можно комбинировать глобальные и локальные обработчики, создавая цепочку вызовов для сложной логики.

Wildcard и catch-all маршруты

Для перехвата всех неопределённых путей используется *. Это удобно для страниц 404:

page('*', () => {
  console.log('Страница не найдена');
});

Wildcard можно использовать вместе с динамическими сегментами для гибкой маршрутизации.

Redirect и alias

Page.js позволяет перенаправлять пользователей с одного пути на другой:

page('/old-path', () => page.redirect('/new-path'));

Также можно создать несколько путей, ведущих к одному обработчику:

page('/home', renderHome);
page('/', renderHome);

Управление порядком маршрутов

Порядок определения маршрутов имеет значение: Page.js проверяет пути сверху вниз, останавливаясь на первом совпадении. Это важно при использовании wildcard и динамических сегментов:

page('*', showNotFound); // должен быть последним
page('/user/:id', showUser);

Объект контекста ctx

При каждом совпадении пути Page.js передает объект ctx с полезными свойствами:

  • ctx.path — текущий путь URL.
  • ctx.params — объект с параметрами маршрута.
  • ctx.querystring — строка запроса после ?.
  • ctx.query — объект с параметрами query (если использовать парсинг).
  • ctx.state — объект для передачи данных между middleware.

Использование ctx позволяет строить мощные цепочки обработки маршрутов без глобальных переменных.

Инициализация Page.js

После определения всех маршрутов необходимо запустить обработчик:

page();

Для работы с историей браузера можно включить pushState:

page({ hashbang: false });

Если используется хеш-роутинг:

page({ hashbang: true });

Итоговый пример сложного маршрута

page('/blog/:year/:month/:slug', checkAuth, loadPost, renderPost);

function loadPost(ctx, next) {
  fetch(`/api/posts/${ctx.params.slug}`)
    .then(res => res.json())
    .then(post => {
      ctx.post = post;
      next();
    });
}

function renderPost(ctx) {
  document.body.innerHTML = `<h1>${ctx.post.title}</h1><p>${ctx.post.content}</p>`;
}

Такой подход демонстрирует все ключевые возможности Page.js: динамические сегменты, цепочку middleware и использование объекта контекста для передачи данных.