timeago.js может конфликтовать с другими библиотеками на уровне глобального состояния, DOM-манипуляций, управления датами и полифиллов. Знание типичных конфликтов помогает предотвратить их заранее.
Момент объекты не являются нативными 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 также возвращает объект-обёртку:
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 использует свой формат функций локалей, несовместимый с 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 — нативный браузерный 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 форматирование дат
i18n.t('date', { val: post.createdAt, formatParams: { val: { format: 'relative' } } });
// Одновременно timeago форматирует тот же элемент
format(post.createdAt, 'ru');
Решение — выбрать одну систему. Если используется i18next, реализовать relative time через его систему форматирования. Если timeago.js — использовать его напрямую без i18n обёрток.
В 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);
}, []);
При 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>;
}
Библиотеки вроде Preact или Solid.js могут применять diff-алгоритм к
элементам, которыми управляет timeago.js. Это приводит к перезаписи
textContent:
// Preact перерисовывает компонент и сбрасывает textContent
// который timeago обновил через render()
Решение — не использовать render
timeago.js для элементов внутри реактивного дерева. Вместо этого
использовать format + setInterval через
хук.
Некоторые библиотеки (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 | Подключать после полифиллов |