Обратная совместимость

Библиотека Pikaday исторически проектировалась как лёгкий datepicker без избыточных зависимостей, что напрямую повлияло на её стратегию обратной совместимости. Основная цель — минимизация ломающих изменений при обновлениях, особенно в части публичного API, конфигурационных опций и поведения выбора дат.

Ключевым принципом является сохранение стабильности конструктора new Pikaday() и неизменность базового набора опций. Любые изменения в поведении библиотеки вводятся через расширение, а не модификацию существующих контрактов.


Стабильность конструктора и опций

Конструктор Pikaday является основным контрактом между библиотекой и приложением:

const picker = new Pikaday({
  field: document.querySelector('#date'),
  format: 'DD.MM.YYYY',
  onSelect: (date) => console.log(date)
});

Обратная совместимость обеспечивается тем, что:

  • существующие поля конфигурации не удаляются;
  • изменения поведения опций происходят только через расширение логики;
  • новые параметры всегда имеют безопасные значения по умолчанию;
  • неизвестные поля игнорируются, а не вызывают ошибки.

Такой подход позволяет использовать старые конфигурации даже после значительных обновлений версии.


Политика изменения API и deprecation cycle

Любое изменение, затрагивающее публичные интерфейсы, проходит через этап устаревания (deprecation). Типичный цикл включает:

  1. добавление новой функциональности параллельно старой;
  2. пометка старого поведения как устаревшего через комментарии в документации или runtime warning;
  3. сохранение поддержки минимум в одном major-цикле;
  4. удаление только в следующем major-релизе.

Пример эволюции опции:

// старый вариант
firstDay: 1

// новый расширенный вариант
weekStart: 1

Вместо немедленного удаления firstDay сохраняется, но внутренняя логика переводится на унифицированный параметр.


Совместимость с форматами дат

Одним из ключевых аспектов является обработка дат и взаимодействие с внешними библиотеками (moment, Date, dayjs в форках).

Pikaday по умолчанию использует нативный Date, что обеспечивает:

  • отсутствие внешних зависимостей;
  • предсказуемое поведение в разных средах;
  • минимизацию breaking changes при обновлениях.

При этом поддерживаются стратегии адаптации:

  • форматирование через toString-подобные функции;
  • кастомные парсеры через опции parse и format;
  • возможность интеграции с внешними библиотеками без изменения ядра.

Устойчивость к изменениям DOM API

Обратная совместимость затрагивает и работу с DOM:

  • использование стандартных методов addEventListener вместо устаревших on*;
  • отсутствие зависимости от нестабильных браузерных API;
  • защита от изменений поведения input-элементов в новых версиях браузеров.

Даже при изменениях в спецификациях HTML input[type=“date”], Pikaday продолжает работать через абстракцию над текстовым полем.


CSS и визуальная совместимость

Стили Pikaday вынесены отдельно и не являются частью логики, что снижает риск поломки при обновлениях JS-ядра.

Основные принципы:

  • минимальные структурные изменения DOM;
  • сохранение классов вида .pika-single, .pika-button, .is-selected;
  • добавление новых классов без удаления старых;
  • расширение, а не переработка разметки.

Это позволяет старым CSS-темам работать даже с новыми версиями библиотеки.


Поддержка модульных систем

Pikaday поддерживает несколько форматов подключения:

  • UMD (универсальный формат для браузеров и bundler-ов);
  • CommonJS (require);
  • ES Modules (import).

Обратная совместимость обеспечивается следующим образом:

  • сохранение UMD как основного слоя распространения;
  • экспорт ESM без изменения логики ядра;
  • отсутствие разрушения CommonJS-экосистемы при переходе на ESM.
// CommonJS
const Pikaday = require('pikaday');

// ESM
import Pikaday from 'pikaday';

Совместимость с браузерами

Исторически Pikaday ориентирован на широкую поддержку браузеров, включая старые версии.

Подход к обратной совместимости включает:

  • использование ES5-синтаксиса в ядре (или транспиляция);
  • отсутствие обязательного использования современных API без полифиллов;
  • защита от особенностей IE11 в старых версиях (через условные проверки);
  • graceful degradation при отсутствии современных возможностей.

Изменения в event-системе

События являются критической частью обратной совместимости. Основные события:

  • onSelect
  • onOpen
  • onClose
  • onDraw

Стабильность обеспечивается тем, что:

  • сигнатуры событий не меняются;
  • добавление новых аргументов происходит через расширение объекта, а не позиционных параметров;
  • старые обработчики продолжают работать без изменений.

Пример расширения:

onSelect: (date, context) => {}

Где context может появляться в новых версиях, но не ломает старые функции с одним аргументом.


Обработка устаревших опций

Механизм backward compatibility включает слой нормализации конфигурации.

function normalizeOptions(opts) {
  return {
    ...opts,
    firstDay: opts.firstDay ?? opts.weekStart ?? 0
  };
}

Такой подход позволяет:

  • поддерживать старые конфигурации;
  • постепенно мигрировать пользователей;
  • избегать резких breaking changes.

Защита от breaking changes в рендеринге

Метод draw() и внутренняя логика рендеринга календаря проектируются так, чтобы:

  • минимально менять структуру DOM;
  • сохранять порядок элементов;
  • не полагаться на внешние стили при вычислениях логики;
  • отделять состояние от представления.

Это особенно важно при кастомизации тем и внедрении Pikaday в сложные UI-фреймворки.


Версионирование и семантика изменений

Pikaday следует семантическому версионированию:

  • major — потенциальные breaking changes;
  • minor — добавление функциональности без нарушения совместимости;
  • patch — исправления и оптимизации.

При этом даже в minor-релизах избегаются изменения поведения по умолчанию, если они могут повлиять на существующие проекты.


Стратегии миграции между версиями

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

  • сохранение старых API-поверхностей;
  • наличие альтернативных опций;
  • обратимые изменения конфигурации;
  • документированные различия поведения.

Типичный паттерн миграции:

  • добавление нового параметра;
  • сохранение старого как alias;
  • постепенное снижение значимости legacy-ветки;
  • удаление только в следующем major.

Внутренняя изоляция изменений

Одним из механизмов сохранения обратной совместимости является строгая модульность:

  • логика парсинга дат отделена от UI;
  • рендеринг календаря изолирован от состояния input;
  • события не зависят от реализации DOM;
  • конфигурация обрабатывается отдельным слоем нормализации.

Это позволяет менять внутреннюю реализацию без изменения внешнего API.


Поддержка legacy-кода в форках и интеграциях

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

  • неизменность структуры объекта picker;
  • сохранение публичных методов (show, hide, destroy);
  • отсутствие переименования ключевых методов;
  • поддержка старых паттернов инициализации.

Даже при внутренних изменениях объектная модель остаётся совместимой с предыдущими версиями.


Ограничения обратной совместимости

Несмотря на усилия по стабильности, существуют ограничения:

  • невозможность бесконечного сохранения старых API без усложнения кода;
  • необходимость удаления устаревших браузерных костылей;
  • ограниченность в расширении архитектуры без major-версий;
  • риск накопления legacy-веток.

Эти ограничения компенсируются строгим versioning и постепенной эволюцией API.