Привет! Меня зовут Карлен, я lead frontend‑разработчик в ITFB Group. Сегодня расскажу о библиотеке, которую я создал для решения нашей внутренней боли. Но теперь она помогает не только нам, но и другим командам.

Когда у вас один стенд, проблем нет. Но когда их много, может начаться хаос, и появиться вопросы в духе "Обновлен ли стенд?" или "Выкатили ли правки?"

В результате мы начинаем уточнять информацию, искать пайплайны, лезть в Gitlab в раздел /environments или искать оповещения в чатах. Но это отнимает много времени. Хочется максимально просто получить:

  • версию сборки

  • время деплоя

  • а иногда ещё коммит или окружение.

А порой натыкаемся на одни и те же вопросы:

  • Как узнать id?

  • Какой код у этой модели?

Так и родилась идея debug-web, небольшой библиотеки, которая добавляет в консоль единую точку входа для отладки. И в этой статье я покажу, как добавить её в свой проект!

Знакомство

debug-web — компактная библиотека (~3.5 КБ) без зависимостей.

Ключевые возможности библиотеки

  • Уровни логирования
    debug, log, info, warn, error. Можно добавлять свои.

  • Стилизация сообщений
    Каждому уровню можно задать свои стили, консоль не сливается в кашу.

  • Сохранение данных
    Маршруты, состояние, права доступа и любые другие данные сохраняются в объекте window и доступны из консоли в любой момент.

  • Дамп данных
    Метод dump выводит приветственную информацию (версию, время сборки и т.п.) прямо при открытии консоли, игнорируя текущий уровень логирования.

  • Персистентный уровень
    Уровень логирования можно изменить прямо из консоли: debug.setLevel('log'). И даже после перезагрузки страницы он не сбросится.

Базовое использование

Установка

npm i debug-web
yarn add debug-web

Создаём экземпляр

Здесь мы настраиваем отладчик под конкретный проект. Уровень по умолчанию я рекомендую выставлять в зависимости от окружения: в процессе разработки показывать всё, а на проде только ошибки

import { createDebug } from 'debug-web';

export const debug = createDebug({
  // Название приложения, если используются микрофронты
  app: 'my-app',
  
  // Уровень по умолчанию
  level: isDEV ? 'log' : 'error',
  
  // Мета-информация о сборке
  data: {
    version: env.APP_VERSION,        // '2.0.0'
    buildTime: env.APP_BUILD_TIME,   // '2026-03-20T10:30:00Z'
    message: env.APP_BUILD_TITLE,    // 'chore: fix title'
    environment: env.MODE,           // 'development'
  },

  // Опишем стили для пользовательских методов логирования
  style: { emoji: 'text-decoration: underline', _websocket: 'color: orange' },

  // Описываем заголовки для пользовательских методов логирования
  title: { emoji: 'Эмоции стенда:', _websocket: 'WebSocket:' },
});

Выводим приветственную информацию

Чтобы при открытии консоли сразу было видно главное, используем метод dump. Оборачиваем его в условие по флагу VITE_APP_INFO — так мы сможем включать дамп только на нужных стендах (например, на тестовых, но не на проде).

if (env.APP_INFO === 'true') {
  debug.dump(['version', 'message', 'buildTime'], {
    level: 'info',
    title: data => `Тестовый проект: ${data.version}}`,
  });
}

Логируем

Теперь можно пользоваться отладчиком в любом месте приложения.

Важно: данные, переданные в debug.set(), не выводятся в консоль сразу, но всегда доступны позже. Например, тестировщик может ввести debug и посмотреть текущее состояние.

debug.log('Запрашиваемые данные', data);
debug.info('Авторизация успешна', { id, role });
debug.error('Ошибка', error);

// Пользовательские (нейминг метода за Вами):
debug._websocket('Инизиализация...')
debug.emoji('😢')

// Сохраняем важные данные:
debug.set({ 
  route: '/home',
  permissions: ['read', 'write'],
});

Что видно в консоли?

Открываем консоль, и нас встречает приветственный дамп:

▼ Тестовый проект: 2.0.0
  ┌─────────────┬──────────────────────────┐
  │ ключ        │ значение                 │
  ├─────────────┼──────────────────────────┤
  │ version     │ 2.0.0                    │
  │ message     │ chore: fix title         │
  │ buildTime   │ 2026-03-20T10:30:00Z     │
  └─────────────┴──────────────────────────┘

Если нужно больше информации, просто пишем debug и нажимаем Enter, и видим все сохранённые данные:

▼ {…}
 version: '2.0.0',
 message: 'chore: fix title'
 buildTime '2026-03-20T10:30:00Z'
 route: '/home',
 permissions: ['read', 'write'],
}

Всё, никаких больше вопросов о том, актуален ли стенд, и долгих поисков по чатам 😊

А если хотим получить подробное логирование, вызываем в консоли debug.setLevel('debug') и видим все сообщения:

Как мы наполняем информацией

Чтобы debug-web показывал актуальные данные, нужно передать в него метаинформацию при сборке.

Так как некоторые переменные доступны только при merge request, было решено добавить файл .release-version для хранения релизной версии продукта.

Что в CI?!

В пайплайне у нас есть 2-а скрипта, первый определяет версию, второй обновляет .env-файл:

Что здесь:

  • VERSION_FILE — путь к файлу, где храним релизную версию;

  • VERSION — результирующая версия релиза (формируем из тега, milestone, нашего файла или из package.json);

  • CI_JOB_STARTED_AT — точное время старта задачи (формат ISO);

  • CI_COMMIT_TITLE — заголовок коммита (например, "chore: fix title");

  • VITE_APP_INFO — флаг, который включает приветственный дамп на текущем стенде.

variables:
  VERSION_FILE: '.gitlab/.release-version'

#
# Определяем версию
- |
  if [[ -n "$CI_COMMIT_TAG" ]]; then
    export VERSION="$CI_COMMIT_TAG"
  elif [[ -n "$CI_MERGE_REQUEST_MILESTONE" ]]; then
    export VERSION="$CI_MERGE_REQUEST_MILESTONE"
  elif [[ -f "${VERSION_FILE}" ]]; then
    export VERSION=$(cat "${VERSION_FILE}" | tr -d '[:space:]')
  else
    export VERSION=$(node -p "require('./package.json').version")
  fi
  # Сохраняем версию в файл ↓
  echo "$VERSION" > "${VERSION_FILE}"

#
# Создаём .env-файл
- |
  {
    echo "APP_VERSION=${VERSION}"
    echo "APP_BUILD_TIME=${CI_JOB_STARTED_AT}"
    echo "APP_BUILD_TITLE=${CI_COMMIT_TITLE}"
    echo "APP_INFO=true"
  } > .env

Как пакет работает под капотом

Каждому уровню логирования сопоставлен числовой приоритет:

const LEVEL_MAP = { debug: 0, log: 1, info: 2, warn: 3, error: 4 };

Когда вызывается debug.log, библиотека сравнивает приоритет текущего уровня с приоритетом сообщения. Если сообщение ниже порога, оно просто не доходит до консоли.

Можно запускать и собственные уровни лоигрования (по приоритету они будут сопоставимы с уровнем info или debug, если метод начинается с символа _):

debug.customLevel('👌')

Совет: логируйте осмысленно!

Раздувать проект оборачивая в логи всё что не попадя — это плохая идея. Логируйте только то, что действительно нужно при разборе проблем.

Если добавляете свои уровни (например, debug.performance()), договоритесь в команде, что они означают и когда их использовать.

Заключение

debug-web не решает всех проблем отладки, но упрощает жизнь и сокращает время на сборе информации. Надеюсь, наш опыт окажется полезным и вы тоже начнёте использовать этот подход.

Полный код пакета можете изучить на Github.

Если остались вопросы или есть идеи как улучшить библиотеку — пишите в комментариях, обсудим! Спасибо за внимание!