Обратная совместимость — это способность нового кода работать с API
предыдущих версий. Для timeago.js она означает, что старые вызовы
format(date) продолжают работать после обновления
библиотеки.
Стабильные части API timeago.js — format,
render, cancel, register — не
менялись кардинально между мажорными версиями 3.x и 4.x. Это
означает:
// Этот код работал в 3.x и продолжает работать в 4.x
import { format, render, cancel, register } from 'timeago.js';
format(new Date(), 'ru');
render(document.querySelector('time'), 'ru');
cancel(document.querySelector('time'));
register('custom', (n, i) => ['давно', 'скоро']);
timeago.js следует semver:
4.0.0 → 4.0.1: patch — только багфиксы,
без breaking changes.4.0.0 → 4.1.0: minor — новые возможности,
без breaking changes.4.0.0 → 5.0.0: major — breaking changes
допускаются.{
"dependencies": {
"timeago.js": "^4.0.0"
}
}
^4.0.0 — разрешает обновления до 4.x.x,
блокирует 5.0.0.
Если приложение предоставляет API поверх timeago.js (например, React-компонент или утилиты), следовать тем же принципам:
// v1 — первоначальный API
export function formatDate(date: Date | string): string {
return format(date, 'ru');
}
// v2 — добавить параметр без нарушения совместимости
export function formatDate(date: Date | string, locale = 'ru'): string {
return format(date, locale);
}
// v2 обратно совместим: существующие вызовы formatDate(date) продолжают работать
Если нужно отказаться от части API, сначала пометить как устаревшее:
/**
* @deprecated Используйте formatDate(date, locale) вместо этого.
* Будет удалено в следующей мажорной версии.
*/
export function legacyFormatDate(date: Date): string {
console.warn('[timeago] legacyFormatDate устарела. Используйте formatDate.');
return formatDate(date);
}
TypeScript-декоратор @deprecated заставит IDE показывать
предупреждение при использовании.
Если приложение поддерживает старые браузеры (IE11, Safari 10), необходимо учитывать:
Promise — нужен полифилл для динамических импортов
локалей.Array.from — для конвертации
NodeList.Set, Map — для кеширования и
реестров.// Перед подключением timeago.js
import 'core-js/stable';
import { format, render, register } from 'timeago.js';
Правильная архитектура скрывает зависимость от конкретной библиотеки за интерфейсом:
// src/services/time.ts — единая точка входа
import { format, render, cancel, register } from 'timeago.js';
export type TimeService = {
format: (date: Date | string | number, locale?: string) => string;
render: (el: Element, locale?: string) => void;
cancel: (el?: Element) => void;
};
export const timeService: TimeService = {
format: (date, locale = 'ru') => format(date, locale),
render: (el, locale = 'ru') => render(el, locale),
cancel: (el) => cancel(el),
};
При смене библиотеки достаточно изменить реализацию в одном файле.
// Тест, запускаемый с каждой новой версией зависимости
describe('timeago.js API contract', () => {
it('format принимает Date', () => expect(typeof format(new Date(), 'ru')).toBe('string'));
it('format принимает string', () => expect(typeof format('2020-01-01', 'ru')).toBe('string'));
it('format принимает number', () => expect(typeof format(Date.now(), 'ru')).toBe('string'));
it('render не бросает исключение', () => {
const el = document.createElement('time');
el.setAttribute('datetime', '2020-01-01');
document.body.appendChild(el);
expect(() => render(el)).not.toThrow();
cancel(el);
document.body.removeChild(el);
});
it('register принимает кастомную функцию', () => {
expect(() => register('test_compat', () => ['давно', 'скоро'])).not.toThrow();
});
});
В production следует фиксировать точную версию:
{
"dependencies": {
"timeago.js": "4.0.2"
}
}
Это гарантирует, что автоматические обновления не сломают production. Обновления выполняются осознанно с прохождением тестов.