Конфликты с другими библиотеками

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


Конфликт с Moment.js при работе с датами

Момент объекты не являются нативными Date. При передаче в timeago.js они могут работать некорректно:

import moment from 'moment';
import { format } from 'timeago.js';

const m = moment('2025-06-01');
format(m, 'ru'); // Неопределённое поведение

Решение — конвертировать в нативный Date или ISO строку:

format(m.toDate(), 'ru');       // Date объект
format(m.toISOString(), 'ru'); // ISO строка
format(m.valueOf(), 'ru');     // timestamp в мс

Конфликт с Day.js

Day.js также возвращает объект-обёртку:

import dayjs from 'dayjs';
import { format } from 'timeago.js';

const d = dayjs('2025-06-01');
format(d, 'ru'); // Некорректно
format(d.toDate(), 'ru');  // Правильно
format(d.valueOf(), 'ru'); // Правильно

Конфликт с date-fns локалями

date-fns использует свой формат функций локалей, несовместимый с timeago.js:

import { ru } from 'date-fns/locale';
import { register } from 'timeago.js';

register('ru', ru); // Ошибка — ru из date-fns не является LocaleFunc timeago.js

Решение — писать свою LocaleFunc или импортировать из timeago.js:

import ruTimeago from 'timeago.js/esm/lang/ru';
import { register } from 'timeago.js';

register('ru', ruTimeago); // Правильно

Конфликт с Intl.RelativeTimeFormat

Intl.RelativeTimeFormat — нативный браузерный API. Конфликт возникает, когда обе системы применяются к одному элементу:

const rtf = new Intl.RelativeTimeFormat('ru');
const el  = document.querySelector('time');

render(el, 'ru');                        // timeago контролирует el
el.textContent = rtf.format(-1, 'day'); // Перезаписывает текст timeago

Решение — использовать только одну систему для одного элемента.


Конфликт с i18n библиотеками (i18next, vue-i18n)

i18n библиотеки могут перехватывать форматирование дат и применять свои правила:

// i18next форматирование дат
i18n.t('date', { val: post.createdAt, formatParams: { val: { format: 'relative' } } });

// Одновременно timeago форматирует тот же элемент
format(post.createdAt, 'ru');

Решение — выбрать одну систему. Если используется i18next, реализовать relative time через его систему форматирования. Если timeago.js — использовать его напрямую без i18n обёрток.


Конфликт с React 18 concurrent mode

В concurrent mode React может прерывать рендер. Если render timeago.js вызывается во время прерванного рендера:

// Проблема: useEffect не вызывается при отброшенных рендерах
// render вызывается в неправильный момент
function Comp() {
  render(document.querySelectorAll('time')); // Вне useEffect — неправильно
  return <div />;
}

Решение — всегда через useEffect:

useEffect(() => {
  const el = ref.current;
  if (!el) return;
  render(el, 'ru');
  return () => cancel(el);
}, []);

Конфликт с SSR фреймворками (Next.js, Nuxt)

При hydration серверный HTML не совпадает с клиентским, если timeago.js форматирует во время SSR:

// Проблема: разный текст на сервере и клиенте
function TimeAgo({ date }) {
  return <time>{format(date, 'ru')}</time>; // На сервере и клиенте разное время
}

Решение — подавлять hydration предупреждение или использовать useState:

function TimeAgo({ date }) {
  const [text, setText] = useState(''); // Пусто на сервере

  useEffect(() => {
    setText(format(date, 'ru')); // Только на клиенте
  }, [date]);

  return <time suppressHydrationWarning>{text}</time>;
}

Конфликт с Virtual DOM библиотеками

Библиотеки вроде Preact или Solid.js могут применять diff-алгоритм к элементам, которыми управляет timeago.js. Это приводит к перезаписи textContent:

// Preact перерисовывает компонент и сбрасывает textContent
// который timeago обновил через render()

Решение — не использовать render timeago.js для элементов внутри реактивного дерева. Вместо этого использовать format + setInterval через хук.


Конфликт глобальных полифиллов Date

Некоторые библиотеки (timezone-polyfill, date-polyfill) заменяют глобальный Date:

// Полифилл может изменить поведение new Date()
Date = customDatePolyfill;

// timeago.js использует new Date() внутри — поведение становится непредсказуемым

Решение — подключать timeago.js после полифиллов или проверять совместимость.


Таблица конфликтов

Библиотека Тип конфликта Решение
Moment.js Несовместимый тип объекта даты .toDate() или .valueOf()
Day.js Несовместимый тип объекта даты .toDate() или .valueOf()
date-fns Несовместимый формат LocaleFunc Использовать timeago.js локали
i18next Двойное форматирование Выбрать одну систему
React concurrent Неправильный момент вызова render Только через useEffect
Next.js SSR Hydration mismatch useState + useEffect
Virtual DOM (Preact) Перезапись textContent format + хук вместо render
Date полифиллы Нестандартное поведение Date Подключать после полифиллов