Composition API vs Options API в Vue 3 для больших библиотек компонентов
Vue 3: Composition API vs Options API — как выбор влияет на повторное использование, тестирование и онбординг в больших админ‑библиотеках компонентов и командах контрибуторов.

Почему этот выбор важен для больших админ‑библиотек компонентов
Большая библиотека компонентов в админ‑приложении — это не сайт‑визитка с парой кнопок. Это десятки (или сотни) строительных блоков, которые повторяются на экранах: таблицы с сортировкой и массовыми действиями, панели фильтров, формы с правилами валидации, выдвижные панели и модальные окна, потоки подтверждений и мелкие утилиты вроде селекторов дат и защит по правам доступа.
Поскольку эти паттерны встречаются везде, команды часто копируют и слегка правят код, чтобы успеть к дедлайну. Одна таблица получает кастомный фильтр‑бар, другая — немного другой, и вскоре у вас есть пять «почти одинаковых» реализаций. Вот тогда вопрос Composition API vs Options API перестаёт быть вопросом личных предпочтений и начинает влиять на здоровье всей библиотеки.
Чаще всего первым ломается консистентность. UI продолжает работать, но поведение дрейфует: модальное окно закрывается по Escape в одном месте и не закрывается в другом; то же поле формы валидируется по blur на одной странице и по submit на другой. Дальше падает скорость работы, потому что каждое изменение требует охоты по почти‑дубликатам. Наконец падает уверенность: люди избегают рефакторов, потому что не могут предсказать, что сломается.
Три практических решения имеют наибольшее значение в общей библиотеке:
- Повторное использование кода: как вы упаковываете общую логику без запутанных зависимостей.
- Тестирование: насколько просто проверить поведение без хрупких, UI‑тяжёлых тестов.
- Онбординг: как быстро новый контрибутор может прочитать компонент и безопасно внести изменение.
Простой пример: в админке 20 страниц списков, и продукт просит фичу «Сохранённые фильтры». Если таблица, фильтры и логика синхронизации с URL разбросаны и непоследовательны, вы либо сделаете это медленно, либо выпустите с багами. Выбранный стиль API формирует, живёт ли эта логика в одном переиспользуемом месте, насколько явно она связана с каждым экраном и как легко её расширит новый человек.
Если вы строите Vue 3 админ‑приложения (включая команды, которые используют Vue 3 внутри платформ вроде AppMaster для слоя веб‑UI), ранний выбор может сэкономить месяцы поддержки позже.
Как Options и Composition отличаются в повседневном коде
Самый быстрый способ почувствовать разницу — открыть большой админ‑компонент и спросить: «Где я поменяю поведение для этой одной фичи?» В библиотеке компонентов этот вопрос возникает каждый день.
С Options API код сгруппирован по типу: data для состояния, methods для действий, computed для производных значений и watch для побочных эффектов. Такая структура легко читается, когда компонент небольшой. В большой таблице или форме логика одной фичи (например, массовые действия или валидация поля) часто оказывается разбросана по нескольким блокам. Держать это в порядке можно, но нужно дисциплина и согласованная именовальная политика, чтобы не получить «перескакивание» по файлу при чтении.
С Composition API код обычно группируется по фиче. Вы определяете связанное состояние, производные значения, побочные эффекты и хелперы рядом друг с другом и можете вынести повторяющуюся логику в composables. В админ‑библиотеке это часто совпадает с ментальной моделью людей: «всё про фильтрацию здесь», «всё про выбор строк здесь». Это также помогает уменьшить дублирование между похожими компонентами, например, переиспользовать usePagination в разных таблицах.
Большая ежедневная разница — как проявляются зависимости.
- Options API может казаться более неявным: метод может полагаться на
this.user,this.filtersиthis.loading, и вы это поймёте, только прочитав метод. - Composition API склоняет к большей явности: когда функция замыкает
filtersиloading, вы видите эти переменные рядом, и при необходимости можете явно передать их в хелперы.
Плюс в том, что Composition API может стать шумным, если всё свалить в один setup() без структуры.
Практическое эмпирическое правило:
- Выбирайте Options API, когда компоненты в основном презентационные и логики немного.
- Выбирайте Composition API, когда компоненты имеют несколько фич с общими правилами по всей библиотеке.
- Если выбираете Composition API, договоритесь о простом расположении кода, которое группирует по фиче (а не «все refs сначала»).
- Если выбираете Options API, строго соблюдайте именования и держите связанную логику вместе с короткими комментариями и единообразными именами методов.
Обе модели работают. Важно выбрать организацию, которая делает следующее изменение очевидным, а не «умным».
Повторное использование кода: что масштабируется, а что становится грязным
В админ‑приложениях повторное использование — не опция, а необходимость. Вы повторяете одно и то же поведение на десятках экранов, и мелкие несоответствия превращаются в баги и заявки в поддержку.
Большинство случаев повторного использования укладывается в повторяющиеся категории: сортировка/фильтрация/пагинация под API, валидация форм и маппинг ошибок, проверки прав и условное отображение UI, синхронизация запросов (параметры URL, сохранённые представления, дефолтные фильтры) и массовые действия с правилами выбора строк.
Повторное использование в Options API: мощно, но можно спрятать сложность
В Options API повторное использование часто начинается с mixins, extends или плагинов.
Mixins быстры, но плохо масштабируются, потому что скрывают, откуда появился метод или computed. Два миксина могут тихо конфликтовать по имени метода, и вы начинаете дебажить поведение, которое в компоненте не видно.
extends может казаться аккуратнее, чем mixins, но создаёт задачи с наследованием: нужно читать несколько файлов, чтобы понять, что делает компонент. Плагины подходят для глобальных вопросов (директивы, сервисы), но не для бизнес‑правил, которые меняются от экрана к экрану.
Сложный момент приходит, когда повторное использование становится неявным. Новые участники не могут ответить «откуда эти данные?» без поиска по всему кодовой базе.
Повторное использование в Composition API: composables, которые остаются явными
В Composition API повторное использование обычно строится вокруг composables: маленьких функций, возвращающих refs, computed и обработчики. Главное преимущество в том, что повторное использование видно вверху компонента, и вы можете передавать параметры вместо опоры на скрытый контекст компонента.
Например, usePagination может принимать дефолты и выдавать изменения в согласованной форме, а usePermissions — принимать текущую роль и имя фичи. Тогда выбор уже меньше о синтаксисе и больше о том, предпочитает ли ваша библиотека явную проводку зависимостей вместо неявного наследования.
Чтобы повторное использование оставалось предсказуемым, относитесь к каждому переиспользуемому юниту как к небольшому API: дайте понятное имя, определите входы и выходы и держите одну ответственность. Если composable начинает заниматься и пагинацией, и кешированием, и правами, и уведомлениями — разделите его. Так проще поменять одну часть, не ломая остальное.
Как строить переиспользуемые формы и таблицы без боли
В админ‑приложениях формы и таблицы — это те места, где библиотека либо окупает себя, либо превращается в лабиринт. Обе модели работают. Разница в том, как вы упакуете общие поведения вроде dirty‑state, маппинга ошибок и submit‑флоу, не делая каждый компонент «особенным».
Для общей логики форм Options API обычно тянет к mixins или общим хелперам. Mixins удобны сначала, но с течением времени становится сложно ответить на вопросы вроде: «Откуда здесь ошибка поля?» или «Почему кнопка Submit отключена?»
Composition API делает такое повторное использование более явным: вы можете вынести логику в composables (например, useDirtyState, useFormErrors, useSubmitFlow) и сразу видеть, что подтягивается в компонент формы. В большой библиотеке эта прозрачность важнее, чем экономия парочки строк.
Практический способ поддерживать стабильный API компонентов — рассматривать публичную поверхность как контракт: props, emits и слоты должны редко меняться, даже если вы переписываете внутренности. Контракт одинаков в обеих стилях, но Composition API часто делает рефакторы безопаснее, потому что можно заменять composable по частям без изменения шаблона.
Паттерны, которые обычно остаются здравыми по мере роста библиотеки:
- Стройте базовые компоненты, которые хорошо выполняют одну задачу (BaseInput, BaseSelect, BaseTable), и комбинируйте их в фичевые компоненты.
- Предпочитайте слоты для гибкости расположения (зона действий, пустое состояние, рендер клетки), вместо добавления пропов для каждого крайнего случая.
- Нормализуйте события рано (например
update:modelValue,submit,rowClick), чтобы приложения не завязывались на внутренностях. - Держите валидацию и форматирование рядом с инпутами, а бизнес‑правила выносите наружу (в composables или родительские контейнеры).
Частая ошибка — чрезмерная абстракция. «Супер‑форма», которая обрабатывает все типы полей, все правила валидации и все варианты лэйаута, часто становится сложнее в использовании, чем простая Vue‑форма. Хорошее практическое правило: если базовому компоненту нужно больше чем пара пропов, возможно, это два компонента.
Иногда дублирование — правильный выбор. Если только один экран требует странного шапочного блока таблицы с многострочной группировкой, скопируйте небольшой кусок и держите его локально. Хитрые абстракции имеют длинный хвост сопровождения, особенно когда к проекту присоединяются новые люди и пытаются понять разницу между «обычными» компонентами и фреймворком внутри фреймворка.
Если вы выбираете между Composition и Options для большой библиотеки форм и таблиц, оптимизируйте сначала читаемость потока данных. Повторное использование — хорошо, но не когда оно прячет путь от действия пользователя до эмита события.
Влияние на тестирование: что легче проверять
В библиотеке компонентов тесты обычно делятся на три категории: чистая логика (форматирование, валидация, фильтрация), рендеринг (что видно при заданном состоянии) и взаимодействия (клики, ввод, клавиатура, эмиты). Выбор стиля API меняет, как часто вы можете протестировать первую категорию без монтирования полного компонента.
В Options API тесты чаще выглядят как «смонтируй компонент, подергай состояние экземпляра, утверждай DOM». Это работает, но может поощрять большие тесты, потому что логика смешана в methods, computed, watch и lifecycle. При падении теста вы тратите время, пытаясь понять, связано ли это с таймингом watcher, побочным эффектом lifecycle или самой логикой.
Options API обычно подходит для:
- пользовательских сценариев, завязанных на порядке lifecycle (fetch on mount, reset on route change);
- поведения, управляемого watchers (auto‑save, синхронизация query);
- эмита событий из методов компонента (
save(),reset(),applyFilter()).
Composition API смещает баланс. Если логику вынести в composables, вы можете юнит‑тестировать её как обычные функции с простыми входами и явными выходами. Это уменьшает количество «замонтируй и кликни» тестов и делает падения более локальными. Также легче контролировать зависимости: вместо мокания глобалов вы передаёте зависимость (функцию fetch, форматер дат или проверку прав) в composable.
Конкретный пример: переиспользуемая AdminTable с сортировкой, пагинацией и выбором строк. В Composition API логика выбора может жить в useRowSelection() и тестироваться без рендеринга таблицы вообще (переключение, очистка, выбрать все, сохранение на страницах). Затем вы держите небольшой набор компонентных тестов, чтобы подтвердить, что шаблон связывает кнопки, чекбоксы и эмиты правильно.
Чтобы тесты оставались маленькими и читабельными (независимо от стиля):
- Выносите бизнес‑правила в чистые функции или composables, а не в watchers.
- Окружайте побочные эффекты (fetch, storage, таймеры) через внедряемые зависимости.
- Предпочитайте несколько сфокусированных интеграционных тестов на компонент, а не один гигантский «всё сразу».
- Единообразно называйте состояния и события по всей библиотеке (это уменьшает настройку тестов).
- Избегайте скрытых связей (например, метод A зависит от того, что watcher B выполнится).
Если ваша цель — стиль, который улучшает стабильность тестов, стремитесь к меньшему количеству lifecycle‑зависимого поведения и большему числу изолированных логических юнитов, которые можно проверить без DOM.
Онбординг новых контрибуторов: как быстро люди становятся продуктивными
В большой админ‑библиотеке онбординг — это не столько обучение Vue, сколько помощь людям в нахождении кода, соблюдении соглашений и уверенности в том, что правка не сломает пять экранов. Большинство замедлений связано с тремя пробелами: навигация (где логика?), соглашения (как это делается здесь?) и уверенность (как изменить без побочных эффектов?).
С Options API новички обычно начинают быстрее в первый день, потому что структура знакома: props, data, computed, methods, watchers. Цена — реальное поведение часто разбросано. Одна фича вроде «фильтрация на сервере» может быть разбита между watcher, computed и двумя методами плюс mixin. Люди читают блоки, но тратят время на склеивание истории.
С Composition API выигрыш в онбординге в том, что связанная логика может находиться вместе: состояние, побочные эффекты и хелперы в одном месте. Расход — необходимость знать composables. Новым людям нужно понять паттерны вроде useTableState() и как реактивные значения проходят через несколько composables. Без чётких границ это может выглядеть как прыжки между файлами без карты.
Несколько соглашений решают большинство вопросов, вне зависимости от выбранного стиля:
- Предсказуемая структура:
components/,composables/,types/,tests/. - Шаблон именования и его соблюдение (например:
useX,XTable,XForm). - Короткие докблоки: что делает компонент, ключевые props и основные события.
- Одно правило «лазейки»: когда можно добавлять новый composable или хелпер.
- Небольшой «золотой» компонент, демонстрирующий предпочтительный паттерн.
Пример: если команда генерирует Vue 3 админ‑панель и затем кастомизирует её (например, веб‑приложение, построенное на AppMaster и расширяемое разработчиками), онбординг сильно улучшается, когда есть одно очевидное место для настройки поведения таблицы (сортировка, фильтры, пагинация) и одно место для связки UI (слоты, рендер колонок, действия строк). Эта ясность важнее, чем выбранный API.
Пошагово: как выбрать стиль и ввести его безопасно
Для большой админ‑UI библиотеки самый безопасный способ решить вопрос — начать с одной хорошо ограниченной фичи и воспринимать её как пилот, а не как полный рефактор.
Выберите модуль с явным поведением и высокой степенью переиспользования, например фильтрацию таблицы или валидацию формы. До изменения кода опишите, что он делает сейчас: входы (props, параметры запроса, действия пользователя), выходы (события, URL‑изменения) и кейсы (пустое состояние, сброс, ошибки сервера).
Дальше установите границы. Решите, что должно остаться в компоненте (рендеринг, DOM‑события, доступность), а что можно вынести в общую логику (парсинг фильтров, дебаунс, построение параметров API, дефолтное состояние). Частая ошибка — выносить UI‑решения в общий код — тогда повторное использование становится сложным.
Практический план внедрения:
- Выберите один компонент, который явно демонстрирует паттерн и используется на нескольких экранах.
- Вынесите один общий модуль (composable или простой helper) с маленьким, явным API.
- Напишите фокусный тест для этого модуля, основанный на реальных сценариях админки.
- Рефакторьте выбранный компонент полностью, используя новый модуль.
- Примените тот же паттерн ещё к одному компоненту, чтобы подтвердить масштабируемость.
Держите общий API скучным и очевидным. Например, useTableFilters() может принимать начальные фильтры и выдавать filters, apply(), reset() и toRequestParams(). Избегайте «магии», которая читает глобальное состояние, если только это не уже устоявшееся правило в приложении.
После пилота опубликуйте короткое внутреннее руководство с одним примером, который контрибуторы могут скопировать. Одно конкретное правило побеждает длинную документацию, например: «Вся логика фильтрации таблиц живёт в composable; компоненты только бинди́т UI‑контролы и вызывают apply()».
Перед масштабированием используйте простое определение готовности:
- Новый код читается одинаково в двух разных компонентах.
- Тесты покрывают общую логику без монтирования UI.
- Новый участник может изменить правило фильтра без правок в несвязанных файлах.
Если команда также генерирует админ‑порталы no‑code инструментами вроде AppMaster, тот же пилотный подход применим: выберите рабочий процесс (например, утверждения), опишите поведение и стандартизируйте паттерн прежде чем масштабировать.
Распространённые ошибки и ловушки в больших библиотеках
Главные проблемы в большой библиотеке редко про синтаксис. Они возникают из мелких локальных решений, которые накапливаются и усложняют повторное использование, тестирование и поддержку.
Одна распространённая ловушка — случайная смесь паттернов. Если половина библиотеки написана на Options API, а другая — на Composition API без правил, каждый новый компонент превращается в стильную дискуссию. В результате вы получаете дублирующиеся решения для одинаковых проблем. Если вы допускаете оба стиля, опишите политику: новый код использует один стиль, старый трогается только при необходимости, а общая логика живёт в одном согласованном месте.
Ещё одна ловушка — «бог‑composable». Он часто начинается как полезный useAdminPage() или useTable() и постепенно поглощает рутинг, фетчинг, кеширование, выбор, диалоги, тосты и права. Такой composable трудно тестировать и трудно переиспользовать: каждый экран использует только 30% функционала, но платит ценой сложности 100%.
Watchers — ещё один источник боли. Их легко добавить, когда что‑то не синхронизируется, но с асинхронными данными и дебаунсом появляются тайминговые баги. Когда пользователи сообщают «иногда очищается выбор», вы можете потратить часы на воспроизведение.
Сигналы тревоги:
- Компонент работает только при строго определённом порядке props и событий.
- Composable читает и пишет глобальное состояние, не обозначая этого явно.
- Несколько watchers обновляют одно и то же состояние.
- Рефакторы постоянно ломающие экраны по‑мелочи.
- Люди боятся править «тот файл» из‑за риска.
Последняя ловушка — ломать публичный API при рефакторе. В админ‑приложениях таблицы, фильтры и поля формы быстро распространяются. Переименование пропа, изменение эмита или слота может тихо сломать десятки экранов.
Безопаснее относиться к API компонентов как к контрактам: депрекейтить вместо удаления, держать shim‑совместимость какое‑то время и добавлять простые тесты использования, которые монтируют компонент так, как это делают потребители. Если вы генерируете Vue 3 админ‑интерфейсы при помощи инструментов вроде AppMaster, это особенно важно: согласованные контракты компонентов упрощают повторное использование экранов и делают изменения предсказуемыми.
Быстрая проверка перед тем, как зафиксировать выбор
Перед тем как окончательно выбрать Composition API, Options API или смешанный подход, проверьте несколько реальных компонентов из вашей библиотеки. Цель простая: чтобы логику было легко найти, безопасно переиспользовать и просто тестировать то, на чём реально завязана админ‑часть.
1) Легко ли найти логику?
Откройте типичный компонент с фильтрами + таблицей + правами + массовыми действиями. Представьте, что вы новый в кодовой базе.
Хороший знак — когда человек отвечает на вопросы «где логика фильтров?» или «что решает, выключена ли кнопка?» за две минуты. В Options API это обычно означает, что логика чётко разделена между computed, methods и watchers. В Composition API это значит, что setup() организован в маленькие именованные блоки (или composables) и не превращён в одну гигантскую функцию.
2) Ведут ли общие утилиты себя как функции, а не магия?
Независимо от паттерна, общий код должен иметь ясные входы и выходы и минимальные побочные эффекты. Если helper лезет в глобальное состояние, мутирует переданные объекты или делает сетевые вызовы незаметно, повторное использование становится рискованным.
Быстрая проверка:
- Можно ли по сигнатуре composable/хелпера догадаться, что он возвращает?
- Можно ли использовать его в двух компонентах без дополнительной магии?
- Можно ли в тестах сбросить его состояние без ухищрений?
3) Фокусируются ли тесты на реальном админ‑поведении?
Админ‑приложения ломаются предсказуемо: фильтры применяются неправильно, права пропускают действие, формы валидации непоследовательны, состояние таблицы портится после правок.
Тестируйте поведение: «для роли X действие Y скрыто», «при ошибке сохранения ввод остаётся», «смена фильтра обновляет запрос и отображает пустое состояние». Такие тесты устойчивы к внутренним рефакторам.
4) Есть ли стандарт для асинхронного состояния?
Большая библиотека накапливает много мелких асинхронных потоков: загрузка опций, валидация полей, получение строк таблицы, ретраи. Если каждый компонент придумывает собственные loading/error‑флаги, отладка становится медленной.
Выберите одну форму для асинхронного состояния (loading, error, retries, cancellation). Composition API часто поощряет useAsyncX() composables, Options API — стандартную data()‑структуру и общие методы. Главное — консистентность.
5) Публичные API компонентов стабильны и понятны?
Относитесь к компонентам как к продуктам. Их props, события и слоты — контракт. Если этот контракт меняется часто, каждая страница админки становится хрупкой.
Ищите комментарии, объясняющие намерение (что означает проп, какие события гарантированы), а не механику. Если вы работаете с генераторами типа AppMaster, такой подход ещё важнее: стабильные строительные блоки ускоряют последующие релизы.
Пример сценария и дальнейшие шаги для вашей команды
Представьте страницу «Пользователи», которую вы переделываете: панель фильтров (статус, роль, дата создания), таблица с выбором строк, массовые действия (деактивировать, удалить, экспорт) и ролевой доступ (только админы могут массово удалять, менеджеры могут менять роли).
Код может выглядеть одинаково в UI, но организация отличается.
В Options API вы часто получаете большой компонент с data для фильтров и выбора, computed для производных состояний и methods для фетчинга, массовых действий и проверок прав. Повторное использование проявляется как mixins или общие хелперы. Это привычно, но логика может быть разбросана (фетчинг в methods, синхронизация query в watchers, права в computed).
В Composition API вы разделяете страницу на фокусные composables: один для query и фильтров, другой — для выбора строк и массовых действий, третий — для прав. Компонент страницы становится сборкой этих частей, и логика каждой области остается рядом. Минус — нужно договориться об именах и структурe папок, чтобы contrib‑ы не чувствовали магию в setup().
Повторное использование чаще встречается вокруг фильтров с синхронизацией в URL, паттернов серверных таблиц (пагинация, сортировка, select‑all, guards для массовых действий), проверок прав и консистентных состояний пустоты/загрузки.
План действий, который хорошо работает для большинства команд:
- Выберите стиль по умолчанию для нового кода и допускайте исключения только с письменным обоснованием.
- Определите соглашения: где живут composables, как называются, что они могут импортировать и что обязаны возвращать.
- Добавьте небольшую эталонную страницу (например, ту самую Users) как золотой стандарт паттернов и структуры.
- Пишите тесты сначала для переиспользуемых частей (фильтры, права, массовые действия), а не для визуального лэйаута.
- Если скорость важнее глубокой кастомизации для части админ‑экранов, подумайте о их генерации с помощью no‑code‑инструмента вроде AppMaster, а ручную библиотеку держите для действительно уникальных частей.
Если вы уже используете AppMaster, полезно сохранять одну и ту же модель мысленно между сгенерированными и ручными частями: стабильные контракты компонентов и общая логика, упакованная в небольшие явные юниты. Для команд, оценивающих no‑code для внутренних инструментов, AppMaster создан, чтобы генерировать полный стек (бэкенд, веб и мобильную часть), при этом давая возможность стандартизировать Vue 3 UI там, где это важно.
Если вы сделаете на этой неделе только одно: возьмите страницу «Пользователи» за шаблон и применяйте его в ревью кодов. Один понятный пример сделает больше для консистентности, чем длинный стильгайд.
Вопросы и ответы
По умолчанию выбирайте Composition API, если ваша библиотека повторяет поведение вроде фильтрации, пагинации, массовых действий и контроля прав. Он упрощает вынос общей логики в composables и делает зависимости более явными. Используйте Options API, когда компоненты в основном презентационные и содержат мало логики.
Options API группирует код по типу (data, methods, computed, watch), поэтому логика одной функции часто оказывается разбросана. Composition API обычно группирует код по фиче — всё, что относится к «фильтрам» или «выбору строк», находится рядом. Лучший выбор — тот, который делает следующую правку очевидной и безопасной.
В Options API повторное использование часто начинается с mixins или extends, которые скрывают источник методов и вычисляемых значений и могут приводить к конфликтам имён. В Composition API повторное использование обычно реализуется через composables с понятными входами и выходами, и связь видна прямо в компоненте. Для общей библиотеки явное повторное использование обычно дольше остаётся поддерживаемым.
Относитесь к каждому composable как к маленькому API: одна ответственность, явные параметры и предсказуемые возвращаемые значения. Если composable начинает смешивать пагинацию, кеширование, права и уведомления — разбейте его. Мелкие composables проще тестировать, переиспользовать и они меньше создают неожиданных побочных эффектов.
Стабильный публичный контракт — это ключ: props, события и слоты должны меняться редко. Держите форматирование ввода и базовую валидацию рядом с полями, а бизнес‑правила — в composables или контейнерных компонентах. Тогда вы сможете рефакторить внутренности, не ломая потребителей.
Composition API обычно упрощает модульное тестирование логики без монтирования компонента, потому что можно тестировать composables и чистые функции напрямую. Options API чаще ведёт к тестам, где компонент монтируется, и обработка watchers/lifecycle добавляет шум. Но в обоих случаях разделение бизнес‑правил и UI‑связки делает тесты маленькими и стабильными.
Установите единый формат для асинхронного состояния: loading, error и понятная стратегия повторных попыток или отмены. Пусть один и тот же контракт асинхронного состояния используется повсеместно — это можно реализовать как через composables, так и через согласованную data()‑структуру в Options API.
Options API может быть проще с первого дня, потому что структура знакомая: props, data, computed, methods. Но поведение часто разбросано, и новичку придётся складывать картинку вручную. Composition API даёт преимущество, когда люди понимают ваши composables и соглашения по папкам: связанная логика находится рядом и поведение видно из импортов. Главное — иметь один «золотой» пример и следовать ему в ревью.
Выберите одну хорошо ограниченную, широко используемую фичу (например, фильтрация таблицы или отображение ошибок формы) и отработайте её как пилот: вынесите общий модуль с простым API, напишите фокусный тест и полностью рефакторьте один компонент. Проверьте паттерн на ещё одном компоненте, прежде чем масштабировать.
Признаки проблем: много близких, но разных дублей; цепочки watchers, которые конфликтыуют; компоненты, работающие только при точном порядке props/events; частые ломки публичного API (props, события, слоты). Если люди боятся править файл — это признак, что нужны более явные контракты и повторное использование.


