Общая библиотека компонентов и composables
↑ 6.2 Сборка и инфраструктура: Vite, monorepo, CI∕CD · ← Предыдущая · → Следующая
Зачем это на собесе
Как вынести общий UI и логику для нескольких приложений и не создать зависимость-монстра.
Объяснение
Состав библиотеки:
| Слой | Что | Пример |
|---|---|---|
| Токены | цвета, отступы, типографика | @acme/tokens (CSS-переменные, SCSS) |
| UI-kit | базовые компоненты | BaseButton, BaseInput, DataTable (на Quasar/Headless UI) |
| Composables | общая логика | useDebounce, usePagination, useAuth |
| Утилиты и типы | форматирование, валидаторы | @acme/utils, @acme/types |
| API-клиент | сгенерированный из OpenAPI | @acme/api-client |
| Конфиги | ESLint, TS, Vite | @acme/config |
Сборка библиотеки (Vite library mode):
// vite.config.ts
export default defineConfig({
plugins: [vue(), dts({ tsconfigPath: "./tsconfig.build.json" })],
build: {
lib: { entry: "src/index.ts", formats: ["es"], fileName: "index", cssFileName: "style" },
rollupOptions: { external: ["vue", "quasar", "vue-router", "pinia"], output: { preserveModules: true, globals: { vue: "Vue" } } }, // зависимости — внешние
},
});// package.json
{ "name": "@acme/ui", "version": "1.4.0", "type": "module",
"exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" }, "./style.css": "./dist/style.css" },
"peerDependencies": { "vue": "^3.4.0", "quasar": "^2.16.0" }, "sideEffects": ["**/*.css"], "files": ["dist"] }Публикация: приватный реестр (GitLab/GitHub Packages, Verdaccio, Artifactory), Changesets/semantic-release (версии и changelog по Conventional Commits).
Практики:
- Vue/Quasar — peerDependencies, а не dependencies (иначе две копии).
- API компонентов стабильный и документированный (Storybook, см. Storybook и документация дизайн-системы), версионирование по semver, deprecation-цикл.
- Tree-shakeable экспорты (
preserveModules,sideEffects). - Тесты компонентов и визуальные регрессии.
- Типы:
.d.tsчерезvite-plugin-dts,vue-tsc. - Разработка в monorepo (
workspace:*) или через локальную связь (pnpm link). - Не переносите в библиотеку то, что используется одним приложением.
Нюансы и подводные камни
- Дубликаты Vue/Pinia из-за неверных зависимостей → «inject() can only be used inside setup».
- Ломающие изменения без major-версии сломают все приложения.
- Глобальные стили библиотеки конфликтуют с приложением — изолируйте (префиксы,
@layer). - Слишком большая универсальность усложняет компоненты («API из 40 props»).
- Обновление всех потребителей: coordinated-релизы, codemods.
Практика
- Вынесите
BaseInput,BaseButtonи токены в пакет, соберите в library mode. - Настройте peerDependencies и проверьте отсутствие дубликатов Vue.
- Автоматизируйте релизы через Changesets.
Вопросы с ответами
Почему Vue в peerDependencies?
Чтобы приложение и библиотека использовали один экземпляр Vue, иначе ломаются провайдеры и реактивность.
Как версионировать UI-библиотеку?
По semver: ломающие изменения — major с миграционным гайдом, автоматизация через Changesets/semantic-release.