Связано с Testlify
В процессе

Testlify: общая библиотека компонентов

Возглавил инициативу по внедрению общей библиотеки компонентов Vue во всех 4 приложениях Testlify, опубликованной как приватные пакеты, устранив дублирование UI в каждом приложении.

Testlify работает как набор из 4 отдельных веб-приложений. Раньше каждая продуктовая команда разрабатывала и стилизовала общие UI-компоненты независимо, что приводило к дублированию инженерных усилий и визуальным расхождениям между продуктами. Я предложил идею и возглавил команду, которая построила общую библиотеку компонентов на Vue 3, чтобы стандартизировать разработку UI.

Что я сделал

  • Архитектурная консолидация: возглавил инициативу по объединению общих UI-примитивов в централизованной библиотеке, установив единые дизайн-токены и контракты компонентов между командами.
  • Компоненты без состояния: держал компоненты библиотеки строго без состояния и презентационными, что позволяло им чисто встраиваться в любое из 4 приложений, оставляя бизнес-логику отделённой.
  • Распространение как приватный пакет: публиковал и поддерживал библиотеку как версионированные пакеты в GitHub Packages, что позволяло командам получать исправления и новые компоненты через обычные обновления зависимостей без дублирования кода.

Почему это было важно

Централизация разработки UI в общем пакете устранила избыточный код во всех 4 приложениях, ускорила циклы выпуска функций и обеспечила единую систему дизайна во всём наборе продуктов Testlify.

Возглавил, но не в одиночку

Я предложил библиотеку и вёл архитектуру, но это была не одиночная разработка: 86 коммитов от 7 контрибьюторов с мая 2026 года, при этом мои собственные коммиты составляют примерно две трети от общего числа. Чтобы общую систему дизайна приняли 4 продуктовые команды, нужно больше, чем написать компоненты; нужен процесс релизов, который делает их внедрение низкорисковым, и именно это стало настоящей сложной задачей.

Тестирование неопубликованного изменения компонента без публикации на каждый PR

Главное препятствие для внедрения общей библиотеки, это не написание компонента, а разрыв между «я что-то изменил» и «команда-потребитель может реально это попробовать». Публикация временной версии на каждый отдельный PR стала бы реальными, повторяющимися затратами CI ради пакета, который большинство PR никуда так и не устанавливают, поэтому это опционально: PR получает метку needs-snapshot только тогда, когда потребителю реально нужно его протестировать, что запускает GitHub Action snapshot.yml, публикующий временный пакет с тегом @pr<number>. Парный cleanup-snapshot.yml удаляет тег после закрытия PR. Обычные релизы идут через Changesets по двум каналам, @latest из main и @beta из staging-ветки, а релизный workflow автоматически сливает собственный сгенерированный PR «Version Packages», как только проходит CI.

Монорепозиторий, который сам следит за направлением своих зависимостей

Библиотека разбита на слои, а не представляет собой один плоский пакет: tokens, icons и styles лежат в основании с нулевыми внутренними зависимостями, core строится поверх них, ds строится поверх core, а ds-patterns строится поверх ds, core и styles. Каждый слой может зависеть только «вниз», никогда «вверх», так что низкоуровневый примитив не может незаметно обрасти зависимостью от компонента-паттерна более высокого уровня. ds-patterns тоже не только общие примитивы: он включает настоящие доменные виджеты Testlify (например, CandidateCard), построенные на том же слое примитивов, что и всё остальное. Storybook с включённым аддоном доступности документирует каждый компонент и развёрнут публично, так что команда-потребитель (или внешний ревьюер) может проверить состояния компонента и результаты a11y, не клонируя репозиторий. Каждый компонент также несёт отдельный файл .a11y.spec.ts, запускающий настоящие проверки axe-core в CI, а не просто аддон Storybook для ручного осмотра.

Модель данных и масштаб

  • 6 опубликованных пакетов (ds, -core, -icons, -patterns, -styles, -tokens), каждый версионируется независимо.
  • 243 спек-файла (Vitest + Vue Test Utils), проверяющих библиотеку напрямую, а не только приложения-потребители.
  • 9 workflow'ов GitHub Actions, покрывающих CI, preview- и production-деплои, деплои Storybook, staging- и production-релизы, снапшоты PR и их очистку.
  • pnpm workspaces вместе с Turborepo кэшируют и ограничивают задачу сборки пакетами, реально затронутыми конкретным изменением; тесты запускаются напрямую через Vitest по всему workspace, а не через граф задач Turbo.

Внедрение развёртывалось по командам, а не в принудительный «день переключения»: приложение рекрутёра/администратора сегодня работает на всех 6 опубликованных пакетах, в то время как другие продуктовые команды подтягивают отдельные компоненты по собственному релизному графику, а не через единый скоординированный переход по всем 4 приложениям сразу.

Своё решение или готовое

Никаких самописных скриптов повышения версии: Changesets управляет версионированием и changelog'ами по всем 6 пакетам из одного файла changeset на PR. Никакого самостоятельно размещённого приватного реестра: GitHub Packages переиспользует ту же аутентификацию GitHub, которая уже ограничивает доступ к репозиторию, вместо того чтобы запускать и защищать отдельный реестр вроде Verdaccio.

Стек

Vue 3, TypeScript, Vite, pnpm workspaces с Turborepo, Storybook с аддоном доступности, Changesets для версионирования, Vitest и Vue Test Utils, публикуется через GitHub Packages.