Skip to content

Публикация ​

Этот документ описывает, как опубликовать @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.

  • Локальный вход:

    bash
    npm whoami          # проверка текущего аккаунта
    npm login           # вход с подсказками + 2FA, если ещё не выполнен

2. Проверка, что registry указывает на публичный репозиторий ​

В корневом .npmrc репозитория настроен только shamefully-hoist = true, registry не зафиксирован, по умолчанию используется https://registry.npmjs.org/. publishConfig в package.json также зафиксирован на публичном репозитории:

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.

bash
pnpm changeset

В интерактивном режиме выберите @lh-ui/vue3, тип bump (major / minor / patch) и описание изменений.

Внимание: changeset'ы в этом репозитории накапливаются. В .changeset/ скопились десятки непотреблённых changeset, и при выполнении changeset version на шаге 2 они потребляются все разом и сливаются в одну версию. Если нужно публиковать партиями, предварительно распределите изменения по git-веткам или перенесите часть файлов changeset вручную, чтобы контролировать темп.

Шаг 2: повысить номер версии, сгенерировать CHANGELOG ​

bash
pnpm changeset:version

Команда выполняет:

  • расчёт нового номера версии по наивысшему уровню bump в changeset'ах и запись в package.json
  • генерацию CHANGELOG.md на основе всех changeset'ов
  • удаление потреблённых .changeset/*.md (в config.json задано commit: false, авто-коммита не происходит)

После выполнения обязательно проверьте вручную:

bash
git status              # убедитесь, что changeset'ы потреблены, CHANGELOG сгенерирован
git diff package.json   # убедитесь, что номер версии соответствует ожиданиям

Шаг 3: публикация ​

bash
pnpm changeset:publish

Команда внутри себя выполняет pnpm publish в следующем порядке:

  1. запуск prepublishOnly → pnpm build (полная сборка ESM / CJS / UMD / типы / стили)
  2. упаковка по publishConfig и отправка в публичный репозиторий npm
  3. создание и отправка git-тега (формат @lh-ui/vue3@<version>)

Поскольку publishConfig.access равно public, scoped-пакет тоже будет публично виден — дополнительно указывать --access public не нужно.

Шаг 4: отправка изменений (выполняет человек) ​

bash
git push --follow-tags

Самопроверка перед публикацией ​

Перед публикацией посмотрите на фактическое содержимое пакета через dry-run:

bash
npm pack --dry-run

Убедитесь, что в выводе:

  • присутствуют только три каталога es/, lib/, dist/
  • нет src/, packages/, docs/, tests/, scripts/, ai/
  • размер разумен (UMD-сборка целиком около 600 КБ, полные стили около 700 КБ — это ожидаемый диапазон)

Проверка после публикации ​

bash
# 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 ​

bash
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.tgz

packages/ — статический каталог; достаточно переиспользовать конфигурацию nginx существующего сайта, новый location не нужен:

nginx
# Существующий location сайта документации уже покрывает префикс /lhui/vue3/,
# а packages/ как его подкаталог доступен автоматически — достаточно,
# чтобы Content-Type для .tgz отдавался корректно (по умолчанию octet-stream подходит)
location /lhui/vue3/ {
    alias /home/webuser/nginx/lh-ui/vue3/;
    autoindex off;
}

3. Установка с частного сервера ​

Три равнозначных варианта на выбор:

bash
# 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:

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. Упаковка ​

bash
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/, иначе префиксное сопоставление пропустит регулярное выражение):

nginx
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 уровня проекта или пользователя:

ini
@lhgb:registry=https://www.lhgb.top/lhgb

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

bash
pnpm add @lhgb/vue3
# или
npm install @lhgb/vue3
# или
yarn add @lhgb/vue3

4. Отношение к публичному пакету ​

@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 «эффектом снежного кома».

Откат ​

bash
# Пометить версию как устаревшую (рекомендуется: не затрагивает пользователей, уже установивших пакет)
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 с номером версии, что старая версия всё ещё устанавливается.

Красота традиций — основа кода