Skip to content

發佈指南 ​

本文件說明如何把 @lh-ui/vue3 發佈到 npm 公共儲存庫,以及如何把它託管到私有伺服器(tarball 直鏈與 registry 中繼資料兩種方式)。

發佈支援手動與 CI 自動雙通道:本地執行 changeset 命令,由人確認版本號與變更說明後再發包(下文「發佈流程」);推送到 main 且 .changeset/** 有變動時,GitHub Actions 會自動執行 version + publish(見「GitHub Actions 自動發佈」)。

前置準備 ​

1. npm 帳號與 scope 所有權 ​

  • 註冊 npm 帳號,開啟兩步驗證(2FA)。

  • 確認你的帳號擁有 @lh-ui 這個 scope 的發佈權限:scope 是先到先得的,首次發佈 @lh-ui/* 套件的帳號即成為該 scope 的 owner。

  • 本地登入:

    bash
    npm whoami          # 確認當前登入帳號
    npm login           # 未登入時按提示完成登入 + 2FA

2. 確認 registry 指向公共儲存庫 ​

儲存庫根 .npmrc 只配了 shamefully-hoist = true,沒有寫死 registry,預設走 https://registry.npmjs.org/。package.json 的 publishConfig 也鎖定了公共儲存庫:

json
"publishConfig": {
  "access": "public",
  "registry": "https://registry.npmjs.org/"
}

不要在儲存庫根 .npmrc 裡寫私有 registry 位址——那會把發包也導向私有源。臨時切換 registry 請用專案外的使用者級 ~/.npmrc 或命令列參數。

3. 一次發包包含什麼 ​

files 白名單只發佈建構產物:es/(ESM + 類型 + 元件樣式)、lib/(CJS)、dist/(UMD + 全量樣式)。原始碼、文件、測試、腳本都透過 .npmignore 排除。執行發佈命令時 prepublishOnly 會自動先跑一遍 pnpm build,所以不用手動先建構。

發佈流程 ​

第 1 步:寫 changeset ​

每個使用者可見的改動都應該有一條 changeset。如果本次改動已經寫過了,跳到第 2 步。

bash
pnpm changeset

按互動提示選擇 @lh-ui/vue3、bump 類型(major / minor / patch)和變更說明。

注意:本儲存庫的 changeset 是累積的。 當前 .changeset/ 下堆積了數十條未消費的 changeset,執行第 2 步的 changeset version 時會一次性全部消費、合併成同一個版本。如果你想分批發佈,需要先用 git 分支或手動挪走部分 changeset 檔案來控制節奏。

第 2 步:升版本號、產生 CHANGELOG ​

bash
pnpm changeset:version

這條命令會:

  • 按 changeset 的最高 bump 級別計算新版本號,寫入 package.json
  • 彙總所有 changeset 產生 CHANGELOG.md
  • 刪除已消費的 .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 tag(格式 @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 全量包約 600KB,全量樣式約 700KB,屬預期範圍)

發佈後驗證 ​

bash
# 1. npm 上能看到新版本
npm view @lh-ui/vue3
npm view @lh-ui/vue3 versions

# 2. 新建沙盒專案實測三種模組格式
pnpm create vite verify-pkg --template vue-ts
cd verify-pkg && pnpm add @lh-ui/vue3

在沙盒專案裡逐一驗證:

驗證項寫法
完整引入(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 會把 scope 裡的 @lh-ui/ 轉成 lh-ui-vue3-(斜槓變連字符)。也可以用 npm pack --dry-run 提前確認。

2. 上傳到伺服器 ​

沿用現有 nginx 站臺的目錄約定(文件站部署在 /home/webuser/nginx/lh-ui/vue3/),在其下新增 packages/ 目錄,按版本分目錄存放:

/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/ 作為其子目錄自動可存取,只需確保
# .tgz 的 Content-Type 能被下載(nginx 預設 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 hash:團隊協作時鎖定檔案可正確重現安裝,無需存取 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 不同),npm pack 產出 tarball,計算 integrity(sha512)與 shasum(sha1),拼裝 registry 中繼資料 JSON,輸出到 private-registry/:

private-registry/
├── @lhgb/vue3              # 中繼資料 JSON(無副檔名)
└── tarballs/@lhgb/vue3/
    └── lhgb-vue3-1.0.0.tgz

常用參數:

  • --dry-run:只列印將產生的檔案清單與中繼資料,不落盤,用於發包前核對
  • --incremental:讀取已有中繼資料再合併新版本,避免覆寫歷史版本

2. 部署到伺服器 ​

把 private-registry/ 的內容上傳到伺服器目錄,並套用 scripts/nginx-private-registry.conf.example 的 location(與文件站 /lhui/vue3/ 同一套 Nginx,獨立 location):

/home/webuser/nginx/registry/
├── @lhgb/vue3
└── tarballs/@lhgb/vue3/
    └── lhgb-vue3-1.0.0.tgz

Nginx 設定的關鍵是 default_type application/json——中繼資料檔案沒有副檔名,不強制宣告類型客戶端會按純文字解析失敗。完整設定見 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
  • 對外開放、希望被 unpkg / jsdelivr CDN 命中的情境用 @lh-ui/vue3

5. 注意事項 ​

  • 中繼資料要增量更新:每次發包後用 --incremental 合併新版本,直接覆寫會丟失歷史版本中繼資料,舊版本將無法安裝。
  • tarball 不可移動:中繼資料裡的 tarball URL 是絕對路徑,檔案位置與 URL 必須一一對應。
  • 同樣必須 https:pnpm / npm / yarn 預設拒絕 http 位址。
  • 不要把 @lhgb registry 寫進儲存庫根 .npmrc:根 .npmrc 只保留 shamefully-hoist = true,私服位址寫到使用者級 ~/.npmrc,避免汙染發包鏈路。

GitHub Actions 自動發佈 ​

除手動流程外,.github/workflows/release.yml 提供自動發佈通道:

  • 觸發條件:推送到 main 且 .changeset/** 或 package.json 有變動;或儲存庫 Actions 頁面手動觸發(workflow_dispatch)。
  • 行為:跑 pnpm build + pnpm verify:dts 後執行 changesets/action 的 version + publish;沒有待發佈的 changeset 時什麼都不做,所以掛在 push 上是安全的。
  • 所需 secret:在儲存庫 Settings → Secrets and variables → Actions 設定 NPM_TOKEN——在 npm 產生 Granular Access Token,勾選 @lh-ui 組織的 publish 權限。

手動與自動通道可以並存:本地 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)的快取會在數小時到一天內失效,復原後可在沙盒專案用帶版本號的 URL 驗證舊版本是否仍可安裝。