Изменения в API между версиями

Развитие библиотеки Choices.js сопровождалось изменением архитектуры, внутреннего состояния компонентов, набора методов, форматов конфигурации и поведения событий. Между версиями происходили как косметические улучшения, так и серьёзные несовместимые изменения, затрагивающие существующий код.

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

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

Изменения между ранними версиями и современным API

Старые версии: акцент на минимализм

Первые версии Choices.js предоставляли ограниченный набор возможностей:

  • базовый sel ect replacement;
  • single select;
  • multiple select;
  • tag input;
  • простую поисковую фильтрацию;
  • минимальное количество хуков.

Конфигурация выглядела относительно компактной:

const choices = new Choices(element, {
  searchEnabled: true,
  removeItemButton: true
});

Внутренний API был менее структурирован:

  • часть методов напрямую изменяла DOM;
  • отсутствовала строгая система состояний;
  • некоторые методы возвращали нестабильные данные;
  • наблюдались различия между sel ect и text input режимами.

Изменения системы конфигурации

Переименование и переработка опций

С течением времени некоторые параметры были переименованы для унификации API.

Устаревшие настройки

Ранние версии могли использовать:

silent: false

Позже поведение логирования и ошибок стало более строгим, а часть параметров перестала влиять на внутренние предупреждения.


Изменения searchFloor

В старых версиях:

searchFloor: 1

означало минимальное количество символов перед началом поиска.

Позже логика поиска изменилась:

  • поиск стал более оптимизированным;
  • появились внутренние debounce-механизмы;
  • изменилось поведение пустых запросов.

В некоторых версиях наблюдалось различие между:

searchFloor: 0

и полностью отключённым поиском:

searchEnabled: false

Изменение allowHTML

Одно из наиболее значимых изменений связано с безопасностью.

Старое поведение

Ранние версии допускали HTML практически без ограничений:

allowHTML: true

Это позволяло вставлять:

choices.setChoices([
  {
    value: '1',
    label: '<strong>Admin</strong>'
  }
]);

Новое поведение

Поздние версии стали осторожнее относиться к XSS-рискам.

Изменения включали:

  • очистку HTML;
  • ограничения на рендеринг;
  • изменение внутренних шаблонов;
  • более строгую обработку пользовательского ввода.

В некоторых версиях HTML рендерился иначе даже при одинаковых настройках.


Изменения методов API

Эволюция setChoices

Ранние версии

Метод принимал массив:

choices.setChoices([
  { value: '1', label: 'One' },
  { value: '2', label: 'Two' }
]);

Поддержка Promise

Позже появилась возможность асинхронной загрузки:

choices.setChoices(async () => {
  const response = await fetch('/api/users');
  return response.json();
});

Это стало важным архитектурным изменением.

Новые особенности

Современный API:

  • умеет работать с Promise;
  • поддерживает динамическое обновление;
  • использует внутренний store;
  • может автоматически очищать существующие значения.

Изменение сигнатуры setChoices

В некоторых версиях параметры выглядели так:

setChoices(choices, valueKey, labelKey, replaceChoices)

Например:

choices.setChoices(data, 'id', 'name', true);

Позже логика параметров была переработана.

Проблемы старого API:

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

Изменение clearChoices

Старое поведение

choices.clearChoices();

мог очищать:

  • DOM;
  • store;
  • выбранные значения;
  • placeholder.

Новое поведение

Поздние версии разделили ответственность методов.

Теперь различаются:

  • очистка choices;
  • очистка items;
  • очистка input;
  • сброс store.

Это уменьшило количество побочных эффектов.


Изменения removeActiveItems

Ранние реализации:

choices.removeActiveItems();

удаляли все выбранные элементы.

Позже появились дополнительные параметры:

choices.removeActiveItemsByValue('admin');

Это повысило точность работы API.


Изменения событийной системы

Ранний event API

Старые версии генерировали ограниченный набор событий:

element.addEventListener('addItem', event => {
  console.log(event.detail);
});

Расширение event.detail

Позже структура события стала значительно богаче.

Современные события могут содержать:

{
  id,
  value,
  label,
  customProperties,
  groupValue,
  keyCode
}

Изменение структуры данных

В ранних версиях:

event.detail.value

мог быть единственным полезным полем.

Позже появились:

  • metadata;
  • group data;
  • internal identifiers;
  • search score;
  • custom payload.

Новые события

Со временем были добавлены:

element.addEventListener('search', event => {
  console.log(event.detail.value);
});

choice

element.addEventListener('choice', event => {
  console.log(event.detail.choice);
});

showDropdown / hideDropdown

element.addEventListener('showDropdown', () => {});

Изменение порядка событий

Одной из сложностей миграции стало изменение последовательности вызовов.

Например:

Старое поведение

choice → addItem → change

Новое поведение

choice → change → addItem

Это влияло на:

  • формы;
  • валидацию;
  • React/Vue интеграции;
  • синхронизацию состояния.

Изменения внутреннего store

Старые версии

Ранние реализации использовали относительно простой state container.

Недостатки:

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

Новый store

Поздние версии внедрили более централизованное управление состоянием.

Особенности:

  • immutable-подход;
  • action-based обновления;
  • оптимизированный поиск;
  • разделение items и choices.

Изменение структуры данных

Раньше:

choices._store.choices

мог быть обычным массивом.

Позже структура усложнилась:

choices._store.activeChoices
choices._store.activeItems
choices._store.groups

Использование внутренних свойств стало более рискованным.


Изменения работы с DOM

Прямые DOM-манипуляции в старых версиях

Ранние версии:

  • активно изменяли DOM напрямую;
  • пересоздавали элементы;
  • удаляли узлы без оптимизации.

Это создавало проблемы:

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

Современный подход

Новые версии:

  • минимизируют DOM updates;
  • используют diff-like обновления;
  • уменьшают reflow;
  • оптимизируют dropdown rendering.

Изменения CSS-классов

Старые имена классов

Некоторые ранние версии использовали:

.is-open
.is-selected
.is-highlighted

Новые соглашения

Позже появились:

.choices__item--selectable
.choices__item--disabled
.choices__list--dropdown

Изменения затрагивали:

  • кастомные темы;
  • CSS overrides;
  • интеграции с Bootstrap;
  • тесты.

Изменения шаблонов

Эволюция callback-шаблонов

Ранние версии:

callbackOnCreateTemplates: function(template) {
  return {};
}

Новая структура

Позже шаблоны получили более сложный API:

callbackOnCreateTemplates(strToEl) {
  return {
    item: ({ classNames }, data) => {
      return strToEl(`
        <div class="${classNames.item}">
          ${data.label}
        </div>
      `);
    }
  };
}

Изменение параметров шаблонов

Изменились:

  • аргументы callback;
  • структура classNames;
  • data schema;
  • HTML helper utilities.

Старые шаблоны часто ломались после обновления.


Изменения совместимости с браузерами

Ранние версии и IE11

Старые версии активно поддерживали:

  • Internet Explorer 11;
  • старые Edge;
  • legacy mobile browsers.

Из-за этого:

  • использовались polyfills;
  • ограничивались современные API;
  • увеличивался размер bundle.

Современные версии

Поздние релизы отказались от legacy browser поддержки.

Последствия:

  • использование современных JS-конструкций;
  • уменьшение размера библиотеки;
  • ускорение работы;
  • изменение сборки.

Изменения модульной системы

Старый формат

Ранние версии часто подключались через:

<script src="choices.min.js"></script>

Глобальная переменная:

window.Choices

ESM и современные сборки

Поздние версии:

import Choices fr om 'choices.js';

Поддержка:

  • ES Modules;
  • tree shaking;
  • bundlers;
  • modern build pipelines.

Изменения TypeScript-поддержки

Отсутствие типизации

Ранние версии не предоставляли официальных типов.

Использовались:

  • community typings;
  • вручную написанные интерфейсы;
  • any.

Современные типы

Позже библиотека улучшила TypeScript integration.

Появились:

import Choices fr om 'choices.js';

const choices = new Choices(element, {
  removeItemButton: true
});

С типами:

  • Choice;
  • Group;
  • EventMap;
  • configuration interfaces.

Изменения работы с search

Старый search algorithm

Ранние версии использовали относительно простой поиск:

  • linear search;
  • substring matching;
  • чувствительность к регистру в некоторых случаях.

Fuse.js интеграция

Позднее появилась интеграция с более сложным поиском.

Преимущества:

  • fuzzy search;
  • ranking;
  • weighted matching;
  • improved relevance.

Изменения searchFields

Ранние версии могли игнорировать некоторые поля:

searchFields: ['label']

Позже поддержка customProperties стала стабильнее:

searchFields: ['label', 'value', 'customProperties.description']

Изменения производительности

Старые ограничения

Ранние версии плохо работали с большими наборами данных:

1000+ items

вызывали:

  • лаги;
  • долгий рендер;
  • подвисания dropdown;
  • медленный search.

Современные оптимизации

Новые версии:

  • оптимизировали store;
  • уменьшили количество repaint;
  • ускорили filtering;
  • улучшили lazy rendering.

Изменения destroy

Старое поведение destroy

choices.destroy();

не всегда:

  • снимал события;
  • очищал DOM;
  • восстанавливал select;
  • удалял listeners.

Новая реализация

Современные версии корректнее:

  • восстанавливают исходный элемент;
  • очищают обработчики;
  • удаляют внутренние контейнеры;
  • предотвращают memory leaks.

Устаревшие методы и deprecated API

Удалённые внутренние свойства

Ранние версии позволяли использовать:

choices.containerOuter
choices.input
choices.dropdown

Позже часть свойств:

  • стала private;
  • изменила структуру;
  • перестала документироваться.

Deprecated callbacks

Некоторые callback-механизмы были заменены событиями.

Например:

Старый подход

callbackOnInit: function() {}

Новый подход

Использование:

element.addEventListener(...)

и внешней логики инициализации.


Изменения интеграции с фреймворками

Старые проблемы

Ранние версии конфликтовали с:

  • React reconciliation;
  • Vue reactivity;
  • Angular zones.

Причины:

  • прямое изменение DOM;
  • нестабильный state;
  • повторные рендеры.

Современные улучшения

Новые версии:

  • лучше работают с virtual DOM;
  • уменьшают количество side effects;
  • корректнее уничтожаются;
  • стабильнее при SSR.

Типичные проблемы при миграции

Потеря custom templates

После обновления часто ломаются:

  • HTML templates;
  • custom renderers;
  • classNames;
  • dropdown структуры.

Изменение CSS

Обновление версии может нарушить:

  • темы;
  • адаптивность;
  • positioning;
  • z-index логику.

Изменение событий

Критичная проблема:

change

может вызываться иначе, чем в предыдущих версиях.

Особенно это влияет на:

  • формы;
  • autosave;
  • state synchronization.

Стратегии безопасной миграции

Изоляция конфигурации

Полезно выносить настройки:

const choicesConfig = {
  searchEnabled: true,
  removeItemButton: true
};

Обёртка над API

Для крупных проектов используется abstraction layer:

class SelectManager {
  constructor(element) {
    this.instance = new Choices(element);
  }

  clear() {
    this.instance.clearStore();
  }
}

Это уменьшает зависимость от внутренних изменений библиотеки.


Отказ от private API

Нежелательно использовать:

choices._store
choices._currentState
choices._templates

Внутренние структуры меняются между версиями без гарантий совместимости.


Изменения philosophy API

Ранние версии Choices.js ориентировались на:

  • минимализм;
  • простое улучшение select;
  • небольшое количество возможностей.

Современные версии превратились в более сложную систему:

  • с развитым state management;
  • расширяемыми шаблонами;
  • сложной событийной моделью;
  • асинхронным API;
  • улучшенной типизацией;
  • оптимизированным rendering pipeline.

Эволюция API привела к увеличению гибкости, но одновременно повысила требования к миграции, тестированию и контролю совместимости между версиями библиотеки.