Публикация
Этот документ описывает, как опубликовать @lh-ui/vue3 в публичном репозитории npm и как разместить его на частном сервере (двумя способами: прямая ссылка на tarball и registry-метаданные).
Публикация поддерживает два канала: ручной и автоматический через CI — локально выполняются команды changeset, версия и состав изменений подтверждаются человеком перед отправкой (раздел «Процесс публикации»); при пуше в main с изменениями в .changeset/** GitHub Actions автоматически выполняет version + publish (см. «Автоматическая публикация через GitHub Actions»).
Подготовка
1. Аккаунт npm и владение scope
Зарегистрируйте аккаунт npm и включите двухфакторную аутентификацию (2FA).
Убедитесь, что ваш аккаунт имеет право публикации в scope
@lh-ui: scope выдаётся в порядке очереди — аккаунт, первым опубликовавший пакет@lh-ui/*, становится владельцем этого scope.Локальный вход:
bashnpm whoami # проверка текущего аккаунта npm login # вход с подсказками + 2FA, если ещё не выполнен
2. Проверка, что registry указывает на публичный репозиторий
В корневом .npmrc репозитория настроен только shamefully-hoist = true, registry не зафиксирован, по умолчанию используется https://registry.npmjs.org/. publishConfig в package.json также зафиксирован на публичном репозитории:
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
}Не указывайте адрес частного registry в корневом
.npmrcрепозитория — это направит публикации тоже на частный источник. Для временного переключения registry используйте пользовательский~/.npmrcвне проекта или параметры командной строки.
3. Что входит в пакет
Белый список files публикует только сборочные артефакты: es/ (ESM + типы + стили компонентов), lib/ (CJS), dist/ (UMD + полные стили). Исходники, документация, тесты и скрипты исключаются через .npmignore. При выполнении команды публикации prepublishOnly автоматически запускает pnpm build, поэтому собирать вручную заранее не нужно.
Процесс публикации
Шаг 1: написать changeset
Каждое видимое пользователю изменение должно сопровождаться changeset. Если для этого изменения changeset уже написан, переходите к шагу 2.
pnpm changesetВ интерактивном режиме выберите @lh-ui/vue3, тип bump (major / minor / patch) и описание изменений.
Внимание: changeset'ы в этом репозитории накапливаются. В
.changeset/скопились десятки непотреблённых changeset, и при выполненииchangeset versionна шаге 2 они потребляются все разом и сливаются в одну версию. Если нужно публиковать партиями, предварительно распределите изменения по git-веткам или перенесите часть файлов changeset вручную, чтобы контролировать темп.
Шаг 2: повысить номер версии, сгенерировать CHANGELOG
pnpm changeset:versionКоманда выполняет:
- расчёт нового номера версии по наивысшему уровню bump в changeset'ах и запись в
package.json - генерацию
CHANGELOG.mdна основе всех changeset'ов - удаление потреблённых
.changeset/*.md(вconfig.jsonзаданоcommit: false, авто-коммита не происходит)
После выполнения обязательно проверьте вручную:
git status # убедитесь, что changeset'ы потреблены, CHANGELOG сгенерирован
git diff package.json # убедитесь, что номер версии соответствует ожиданиямШаг 3: публикация
pnpm changeset:publishКоманда внутри себя выполняет pnpm publish в следующем порядке:
- запуск
prepublishOnly→pnpm build(полная сборка ESM / CJS / UMD / типы / стили) - упаковка по
publishConfigи отправка в публичный репозиторий npm - создание и отправка git-тега (формат
@lh-ui/vue3@<version>)
Поскольку publishConfig.access равно public, scoped-пакет тоже будет публично виден — дополнительно указывать --access public не нужно.
Шаг 4: отправка изменений (выполняет человек)
git push --follow-tagsСамопроверка перед публикацией
Перед публикацией посмотрите на фактическое содержимое пакета через dry-run:
npm pack --dry-runУбедитесь, что в выводе:
- присутствуют только три каталога
es/,lib/,dist/ - нет
src/,packages/,docs/,tests/,scripts/,ai/ - размер разумен (UMD-сборка целиком около 600 КБ, полные стили около 700 КБ — это ожидаемый диапазон)
Проверка после публикации
# 1. Новая версия видна в npm
npm view @lh-ui/vue3
npm view @lh-ui/vue3 versions
# 2. В sandbox-проекте проверить все три модульных формата
pnpm create vite verify-pkg --template vue-ts
cd verify-pkg && pnpm add @lh-ui/vue3В sandbox-проекте проверьте по очереди:
| Что проверяем | Как |
|---|---|
| Полный импорт (ESM) | import LhUiPlus from '@lh-ui/vue3' + import '@lh-ui/vue3/dist/index.css' |
| Импорт компонента по требованию | import { LhButton } from '@lh-ui/vue3' |
| Импорт стилей по требованию (нужен sass) | import '@lh-ui/vue3/style/button' |
| Импорт стилей по требованию (без sass) | import '@lh-ui/vue3/style-css/button' |
| Инструменты темы | import { getThemeVars } from '@lh-ui/vue3/theme' |
| CDN (появляется через несколько минут) | https://unpkg.com/@lh-ui/vue3 |
Размещение на частном сервере (статический tarball)
Публичный репозиторий npm — основной канал публикации; если нужно собственное зеркало (внутренняя сеть, блокировка npm или фиксация конкретной версии), разместите tarball на своём сервере — это самое лёгкое решение, не требующее разворачивать частный npm registry.
1. Упаковка tarball
pnpm build
npm packИмя файла — lh-ui-vue3-<version>.tgz: npm преобразует @lh-ui/ в scope в lh-ui-vue3- (слэш становится дефисом). Также можно предварительно проверить через npm pack --dry-run.
2. Загрузка на сервер
Следуя сложившемуся соглашению о каталогах для существующих nginx-сайтов (сайт документации развёрнут в /home/webuser/nginx/lh-ui/vue3/), создайте внутри каталог packages/ и храните tarball'ы по версиям:
/home/webuser/nginx/lh-ui/vue3/
├── index.html # сайт документации
└── packages/
├── 1.0.0/
│ └── lh-ui-vue3-1.0.0.tgz
├── 1.1.0/
│ └── lh-ui-vue3-1.1.0.tgz
└── latest # символьная ссылка на текущую рекомендованную версию
└── lh-ui-vue3-1.1.0.tgzСоответствующий URL:
https://www.lhgb.top/lhui/vue3/packages/1.0.0/lh-ui-vue3-1.0.0.tgzpackages/ — статический каталог; достаточно переиспользовать конфигурацию nginx существующего сайта, новый location не нужен:
# Существующий location сайта документации уже покрывает префикс /lhui/vue3/,
# а packages/ как его подкаталог доступен автоматически — достаточно,
# чтобы Content-Type для .tgz отдавался корректно (по умолчанию octet-stream подходит)
location /lhui/vue3/ {
alias /home/webuser/nginx/lh-ui/vue3/;
autoindex off;
}3. Установка с частного сервера
Три равнозначных варианта на выбор:
# pnpm
pnpm add https://www.lhgb.top/lhui/vue3/packages/1.0.0/lh-ui-vue3-1.0.0.tgz
# npm
npm install https://www.lhgb.top/lhui/vue3/packages/1.0.0/lh-ui-vue3-1.0.0.tgz
# yarn
yarn add https://www.lhgb.top/lhui/vue3/packages/1.0.0/lh-ui-vue3-1.0.0.tgzИли прямо в package.json:
{
"dependencies": {
"@lh-ui/vue3": "https://www.lhgb.top/lhui/vue3/packages/1.0.0/lh-ui-vue3-1.0.0.tgz"
}
}4. Замечания
- Обход разрешения зависимостей в registry: при установке tarball registry не опрашивается, зависимости берутся из деклараций внутри tarball. У пакета нулевые
dependenciesво время выполнения, толькоpeerDependencies.vue— поэтому достаточно, чтобы в проекте-потребителе был Vue 3, и установка и работа пройдут успешно. - Нет метаданных версий:
npm updateне работает с tarball-зависимостями, для обновления нужно вручную менять URL (или переключить символьную ссылкуlatestи переустановить). Подходит для зеркалирования зафиксированных версий, но не для частых обновлений. - https обязателен: pnpm / npm / yarn по умолчанию отклоняют http-адреса tarball.
- В
pnpm-lock.yamlпопадёт полный URL + integrity-хеш: при командной разработке lock-файл корректно воспроизводит установку без доступа к npm.
Размещение на частном сервере (метаданные registry)
Прямая ссылка на tarball выше работает, но pnpm update не действует, а в lockfile лежит URL. Если вы хотите, чтобы потребитель устанавливал пакет как обычный (pnpm add @lhgb/vue3) с версионным разрешением и dist-tags, можно заставить статический каталог Nginx дополнительно отдавать поддельные метаданные npm registry, выступая в роли registry только для чтения. Оба способа могут сосуществовать.
1. Упаковка
pnpm build
node scripts/pack-private.mjsСкрипт делает следующее: переименовывает ту же сборку в @lhgb/vue3 (отличаются только name / publishConfig), упаковывает tarball через npm pack, считает integrity (sha512) и shasum (sha1), собирает JSON с метаданными registry и складывает всё в private-registry/:
private-registry/
├── @lhgb/vue3 # JSON с метаданными (без расширения)
└── tarballs/@lhgb/vue3/
└── lhgb-vue3-1.0.0.tgzЧастые параметры:
--dry-run: только вывести список генерируемых файлов и метаданные, не записывая на диск — для проверки перед публикацией--incremental: читать существующие метаданные и добавлять новую версию, чтобы не затереть историю версий
2. Развёртывание на сервере
Загрузите содержимое private-registry/ в каталог на сервере и примените location из scripts/nginx-private-registry.conf.example (тот же Nginx, что и у сайта документации /lhui/vue3/, отдельный location):
/home/webuser/nginx/registry/
├── @lhgb/vue3
└── tarballs/@lhgb/vue3/
└── lhgb-vue3-1.0.0.tgzКлючевая строка конфигурации Nginx — default_type application/json: у файла метаданных нет расширения, и без явного указания типа клиенты будут получать его как plain text, и парсинг завершится ошибкой. Полная конфигурация — в scripts/nginx-private-registry.conf.example (.tgz должен лежать в отдельном location с регулярным выражением верхнего уровня, не вложенном в ^~ /lhgb/, иначе префиксное сопоставление пропустит регулярное выражение):
location ^~ /lhgb/ {
alias /home/webuser/nginx/registry/;
default_type application/json;
autoindex off;
expires 5m;
}
location ~ ^/lhgb/(.+\.tgz)$ {
alias /home/webuser/nginx/registry/$1;
default_type application/octet-stream;
expires 1y;
add_header Cache-Control "public, immutable" always;
}3. Установка из частного registry
Добавьте строку в .npmrc уровня проекта или пользователя:
@lhgb:registry=https://www.lhgb.top/lhgbВсе три пакетных менеджера одинаковы:
pnpm add @lhgb/vue3
# или
npm install @lhgb/vue3
# или
yarn add @lhgb/vue34. Отношение к публичному пакету
@lhgb/vue3 и @lh-ui/vue3 — один источник и одни версии: сборочные артефакты полностью идентичны, различаются только name и registry, пакеты взаимозаменяемы:
- Для внутренних сетей / блокировки npm / фиксации источника публикаций —
@lhgb/vue3 - Для открытого доступа и попадания в CDN unpkg / jsdelivr —
@lh-ui/vue3
5. Замечания
- Метаданные нужно обновлять инкрементально: после каждой публикации добавляйте новую версию через
--incremental— прямая перезапись потеряет метаданные старых версий, и установить их будет невозможно. - Tarball нельзя перемещать: URL
tarballв метаданных абсолютный, расположение файла и URL должны соответствовать один к одному. - https также обязателен: pnpm / npm / yarn по умолчанию отклоняют http-адреса.
- Не записывайте registry
@lhgbв корневой.npmrcрепозитория: корневой.npmrcдолжен содержать толькоshamefully-hoist = true, адрес частного сервера помещайте в пользовательский~/.npmrc, чтобы не загрязнять цепочку публикации.
Автоматическая публикация через GitHub Actions
Помимо ручного процесса, .github/workflows/release.yml предоставляет автоматический канал:
- Условие запуска: пуше в
mainс изменениями в.changeset/**илиpackage.json; либо ручной запуск на странице Actions репозитория (workflow_dispatch). - Поведение: запуск
pnpm build+pnpm verify:dts, затем version + publish из changesets/action; при отсутствии ожидающих changeset ничего не происходит, поэтому безопасно держать триггер на пуше. - Нужный secret: в репозитории Settings → Secrets and variables → Actions настройте
NPM_TOKEN— создайте в npm Granular Access Token с правом публикации в организации@lh-ui.
Ручной и автоматический каналы могут сосуществовать: локальный pnpm changeset:publish удобен, когда требуется ручное подтверждение каждой публикации; CI подходит для автоматической публикации накопленных changeset «эффектом снежного кома».
Откат
# Пометить версию как устаревшую (рекомендуется: не затрагивает пользователей, уже установивших пакет)
npm deprecate @lh-ui/vue3@1.0.0 "В этой версии есть проблема xx, обновитесь до 1.0.1"
# Полное удаление: возможно только в течение 72 часов с публикации и при отсутствии зависимостей от других пакетов
npm unpublish @lh-ui/vue3@1.0.0Кеш CDN (unpkg / jsdelivr) сбрасывается в течение нескольких часов — суток; после отката можно проверить в sandbox-проекте по URL с номером версии, что старая версия всё ещё устанавливается.