如何設計npm包的開發和發佈流程

最近在把公司內部用的一個庫發佈到內網的npm私服上,僅僅是發佈的話是比較簡單的,但這個庫是由多我的一塊兒維護的,並且npm私服只有一套,因此生產環境和開發環境,用的是同一個,那麼,咱們的需求來了:如何設計npm包的開發流程和自動化發佈流程。 這一套流程咱們想要的達成以下目標javascript

  1. 支持團隊協做,有開發提交代碼,其餘人能及時同步到最新代碼
  2. 可以支持常規迭代和hotfix上線
  3. 同一版本開發、測試、生產環境的引用包的版本號都是一致的
  4. 自動化發佈,減小人工操做

先說下如何搭建npm私服和如何發包,不過這不是咱們這篇要講的重點,因此咱們就簡單介紹java

npm私服搭建

目前比較主流的有 nexusVerdaccio,由於 Verdaccio 要更輕量些,並且也知足咱們的需求,因此咱們選擇它。 Verdaccio 搭建很是簡單,直接使用默認配置就行node

npm install -g verdaccio
or
yarn global add verdaccio
verdaccio
複製代碼

就這樣,私服就搭建完成啦。git

npm包發佈

有了私服,咱們先註冊到本地的npm中 npm set registry http://localhost:4873 而後添加用戶,若是是首次,則會新建用戶 npm adduser --registry http://localhost:4873 最後是發佈 npm publishshell

設定版本號有兩種方式,一種是人工修改 package.json 中的 versionnpm

// package.json
{
  "name": "project",
  "version": "1.0.0",
}
複製代碼

另外一種是經過 npm version 來修改版本號,提供有這以下參數json

npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git]
複製代碼

詳細解釋以下:bash

newversion:自定義版本號,除了已經發布的版本號,想寫啥寫啥
major:升級主版本號 1.0.0 -> 2.0.0
minor:升級次版本號 1.0.0 -> 1.1.0
patch:升級補丁號 1.0.0 -> 1.0.1  
premajor:預備主版本
preminor:預備次版本
prerelease:預發佈版本
複製代碼

在執行npm version後,會產生一條新的提交記錄,好比說執行 npm version 2.0.0完後 ,查看log,會發現一條 commit message 爲 2.0.0 的提交記錄,至於爲啥會生成這條記錄呢?很簡單,由於npm version這行命令實際上是修改了 package.json 中的 version ,修改後並提交,因此就有這條新的提交記錄。要是想自定義提交記錄,能夠這麼寫 npm version 2.0.0 -m "Upgrade to %s for reasons" 其中%s就是修改後的版本號。併發

gitlab CI

咱們打算使用 gitlab CI 來實現自動化發佈,咱們也簡單介紹下 gitlab CI 的一些步驟和配置項。函數

  1. 項目開啓CI,選擇一個公共的 runner,要是沒有,那就只能本身弄一個。
  2. 項目根目錄新建 .gitlab-ci.yml,寫入配置,詳細的配置能夠查看 gtilab官網
# 定義 stages
stages:
 - build

定義 job
job1:
 stage: build
 script:
 - echo 'xxx'
複製代碼
  1. 配置完成

設計階段

咱們要說的重點來啦,經過畫圖的方式來給你們介紹咱們的設計思路。先來設定些約定

分支的約定

項目的分支的規劃,設定三個分支

  1. feature分支:常規功能迭代
  2. master分支:穩定分支
  3. hotfix分支:當有緊急修改時,建立該分支,做爲臨時修復分支,這樣能夠不影響常規功能的開發

版本號的約定

咱們採用 大版本:小版本:次版本號 這種方式,每一次feature分支上的每次提交都觸發此版本號升級,好比當前feature分支的版本號是 1.1.5 那麼下一次提交就會升級爲 1.1.6 併發布npm,小版本號跟着常規需求迭代往上升級,好比說當前是 1.1.8 ,週期性的需求在明天上線,那麼上線後,版本號就升級爲 1.2.0 併發布npm,你們發現 1.1.81.2.0 是一樣的代碼,沒錯,之因此這麼作是由於小版本號對應的是一個週期的常規修改,那麼升級的 1.2.0 就是做爲下一次的常規需求的版本號,這樣一來,此版本號對應的是每一次提交,小版本號對應的是當前的開發階段,這兩個咱們均可以經過CI來觸發修改,不須要人工參與 ,剩下還有個大版本號,這個只有在大改版的狀況下才由人工修改,通常來講升級大版本號的頻率是比較低的,人工來來修改徹底是OK的。

你們會發現每一次提交就觸發 npm version patch & npm publish 感受太頻繁了,但爲了能知足團隊協做,只好作些小小的讓步。因此此版本號在這裏的做用並非用來區分版本的,小版本號纔是真正用來作版本區分的,那麼在引用這個npm就要這麼來控制版本號,舉個栗子

"my-package": "~1.2.0"
複製代碼

鎖定大版本號和小版本號,無論咱們開發過程當中提交了多少次,咱們引用都是最新的。

時序圖

畫了開發、發佈的時序圖,以下。

開發流程時序圖

開發時序圖以下

開發流程

發佈流程時序圖

發佈流程

編碼實現

主要是CI的編碼,以下

# .gitlab-ci.yml
# 定義 stages
stages:
 - publish

# 定義 job
job2:
 stage: publish
 before_script:
 - cd /home/node/MY #進到項目目錄
 - git checkout .
 - git checkout $CI_COMMIT_REF_NAME || git checkout -b $CI_COMMIT_REF_NAME
 - git pull -f -X theirs origin $CI_COMMIT_REF_NAME
 - yarn
 script:
 - node publish.js
複製代碼
// publish.js
var shell = require('shelljs');
var git = require('git-last-commit');
var featureBranchName = 'feature-npm';
// 判斷文本是不是版本號格式
function checkCommitMessage(subject) {
    return /^\d+.\d+.\d+$/g.test(subject)
}

// 獲取最近一次提交,判斷是不是版本號格式,若不是,則進行發佈,
git.getLastCommit(function(err, commit) {
    console.log(commit);
    const { subject, sanitizedSubject } = commit;
    shell.exec('echo $CI_COMMIT_REF_NAME');

    if (!checkCommitMessage(subject)) {
        if (sanitizedSubject.indexOf(`Merge-branch-${featureBranchName}-into-master`) > -1) {
            shell.exec('git checkout .');
            shell.exec(`git checkout ${featureBranchName} || git checkout -b ${featureBranchName}`);
            shell.exec(`git pull -f -X theirs origin ${featureBranchName}`);
            shell.exec('npm version minor');
            shell.exec('npm publish');
            shell.exec(`git push origin ${featureBranchName}`);
        } else {
            shell.exec('npm version patch');
            shell.exec('npm publish');
            shell.exec('git push origin $CI_COMMIT_REF_NAME');
        }
     }
});

複製代碼
// package.json
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prepublish": "build script"
  },
複製代碼

發佈腳本里有個函數 checkCommitMessage 用於判斷最新的提交message是否是版本號格式,由於咱們最後會有一步push的操做,push後會再一次觸發CI,因此爲了防止死循環,咱們經過提交的message做爲是否觸發CI的依據,這麼一來咱們就要規範message的格式,個人建議是按照這個格式 U ${修改的具體的內容}

小結

這個方案不是個普適性的方案,畢竟每一個團隊的開發流程都不同,目前這個方案是適合咱們目前的場景的。若是有小夥伴的場景跟咱們的一致,能夠嘗試下,若是小夥伴們有更好的方案,歡迎一塊兒交流呀~

相關文章
相關標籤/搜索