Дебаг промежуточных состояний

Page.js — это легковесная клиентская библиотека для маршрутизации в одностраничных приложениях (SPA). Одной из важных задач при разработке сложных приложений является отладка промежуточных состояний, когда пользователь перемещается между маршрутами, но компонентные состояния и данные могут находиться в промежуточном, неполном или неконсистентном состоянии.


Принцип работы Page.js с маршрутами

Page.js использует функцию page(path, callback) для регистрации маршрутов. Каждый маршрут получает объект ctx, который содержит информацию о текущем пути и параметрах:

page('/user/:id', ctx => {
    console.log('Параметр id:', ctx.params.id);
    renderUser(ctx.params.id);
});

ctx включает следующие ключевые свойства:

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

Использование ctx.state позволяет сохранять промежуточные данные, например, пользовательский ввод или состояние формы, между навигациями.


Промежуточные состояния и управление переходами

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

next()

next() используется внутри middleware для передачи управления следующему обработчику маршрута. Если его забыть вызвать, дальнейшие обработчики не сработают:

page('/profile', ctx, next => {
    console.log('Промежуточное состояние до загрузки данных');
    next();
});

Это позволяет вставлять промежуточные точки, где можно:

  • Логировать состояние данных.
  • Выполнять проверку авторизации.
  • Манипулировать ctx.state перед рендером компонента.

page.redirect()

Для корректного управления промежуточными маршрутами часто используют редиректы:

if (!ctx.state.userLoggedIn) {
    page.redirect('/login');
}

В сочетании с ctx.state редирект позволяет безопасно обрабатывать переходы без потери промежуточного состояния.


Middleware для дебага

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

function debugMiddleware(ctx, next) {
    console.group('Debug Route');
    console.log('Path:', ctx.path);
    console.log('Params:', ctx.params);
    console.log('State before next:', ctx.state);
    next();
    console.log('State after next:', ctx.state);
    console.groupEnd();
}

page('*', debugMiddleware);
  • ctx.state до вызова next() — текущее состояние перед обработкой маршрута.
  • ctx.state после next() — состояние после всех обработчиков маршрута.
  • Группы console.group позволяют структурировать вывод для удобного анализа сложных переходов.

Отслеживание асинхронных переходов

Для SPA с асинхронной загрузкой данных важно фиксировать момент начала и окончания загрузки:

page('/dashboard', async ctx => {
    ctx.state.loading = true;
    renderLoading();

    try {
        const data = await fetchDashboardData();
        ctx.state.data = data;
        renderDashboard(data);
    } catch (error) {
        ctx.state.error = error;
        renderError(error);
    } finally {
        ctx.state.loading = false;
    }
});
  • ctx.state.loading позволяет отследить состояние загрузки.
  • С помощью ctx.state.data сохраняются промежуточные результаты.
  • Любые ошибки фиксируются в ctx.state.error для последующей отладки.

Инструменты визуального дебага

Для сложных SPA удобно визуализировать переходы и промежуточные состояния:

  1. Логирование маршрутов — как показано выше с debugMiddleware.
  2. DevTools состояния — можно создать объект window.__ROUTE_STATE__ = ctx.state, чтобы отслеживать текущее состояние в консоли браузера.
  3. История переходов — хранение массива состояний позволяет воспроизводить шаги пользователя и выявлять баги при некорректных переходах.
const routeHistory = [];

page('*', ctx => {
    routeHistory.push({ path: ctx.path, state: { ...ctx.state } });
});

Работа с динамическими маршрутами

Особенно важен дебаг при динамических маршрутах с параметрами:

page('/post/:postId/comment/:commentId', ctx => {
    console.log('Текущий пост:', ctx.params.postId);
    console.log('Текущий комментарий:', ctx.params.commentId);
});
  • ctx.params помогает отслеживать, какой именно элемент данных загружается.
  • ctx.state позволяет хранить промежуточные результаты, например, текст комментария перед сохранением.

Рекомендации по дебагу промежуточных состояний

  • Использовать middleware для всех маршрутов — это гарантирует логирование всех переходов.
  • Не изменять ctx.state напрямую без необходимости — для отладки полезно видеть «чистое» состояние.
  • Асинхронные операции должны явно управлять состоянием загрузки и ошибок.
  • Использовать группирование и развёрнутый вывод в консоли — упрощает поиск проблем в сложных переходах.
  • Сохранять историю состояний — для воспроизведения багов и анализа поведения пользователя.

Page.js предоставляет минимальный, но мощный инструмент для контроля состояния маршрутов. Корректное использование ctx.state, next(), middleware и редиректов позволяет точно отслеживать промежуточные состояния и предотвращать неконсистентность данных в одностраничных приложениях.