實現自動掃描工作區npm包並同步cnpm

2023-09-14 06:03:16

省流版: npx cnnc

為避免包名重複,取了2個單詞的首尾,cnpm sync

前言

在開發一個多npm包的專案時,時常會一次更新多個包的程式碼,再批次釋出到 npm 映象源後。

由於國內網路環境的原因,大部分都會使用淘寶的映象源進行依賴安裝,為了確保釋出後,通過淘寶源能夠順利的安裝,通常會手動同步一下

cnpm sync vue react

但在一些大型的 monorepo 的多包工程裡,手動輸入包名是一件非常繁瑣的事情,所以準備把輸入的過程簡化一下,改成自動掃描工作區的包名,然後自動同步。

進而有了這個工具

工具的使用

直接通過 npx 執行即可,將自動掃描所有的包

npx cnnc

範例結果 如下

當然也同樣支援手動傳入要更新的包

npx cncc vue react

如果使用頻率較高,也可全域性安裝npm i -g cnnc

這樣可以直接通過cnnccs命令呼叫

實現原理

核心程式碼不到20行,下面詳細的拆解一下,便於學習與理解

主要分為3部分

  • 工作區的包掃描
  • 過濾出合法的包
  • 呼叫 cnpm 同步

工作區的包掃描

主要目的就是掃描工作區所有的 package.json 檔案,然後提取出包名(不包含 node_modules,build 等目錄下的檔案)

這裡可以 fs.readdirSync 實現一個遞迴的掃描,也可以用fast-glob,圖方便我這裡選擇後者,也是目前目錄掃描用得較廣泛的一個包

const fg = require('fast-glob')

const pkgNames = []

// 通過glob 取所有package.json
fg.sync('./**/package.json', {
  ignore: [
    '**/node_modules',
    '**/dist',
    '**/build',
    '**/test',
    // 省略更多的無關目錄...
  ],
  absolute: true
}).forEach((file) => {
  const { name } = require(file)
  pkgNames.push(name)
})

通常工作區裡有很多無關的目錄,比如node_modulesbuilddisttest等,這些目錄下的package.json都不需要同步,所以可以通過ignore引數來忽略掉,避免不必要的掃描(否則 node_modules 套 node_modules 會增加掃描時間,部分目錄是軟鏈的話也會導致掃描路徑的異常)

過濾出合法的包

有些package.json會包含 "private": true 內容,表明為私有的包,不會發布到npm映象源,所以需要過濾掉

// 省略其它程式碼
globResult.forEach((file) => {
  const { name, private } = require(file)
  if (!private) {
    pkgNames.push(name)
  }
})

呼叫 cnpm 同步

最後一步就是呼叫cnpm sync命令,這裡可以通過child_process模組來實現

通過spawn方法,可以直接呼叫命令列命令,然後通過stdio: 'inherit'將命令列的輸出直接列印到終端中

const { spawn } = require('child_process')
const { promisify } = require('util')
function CnpmSync(...names) {
  return promisify(spawn)('npx', ['cnpm', 'sync', ...names], {
    cwd: __dirname,
    stdio: 'inherit'
  })
}

為防止使用者沒有全域性安裝cnpm,這裡通過npx cnpm sync的方式來呼叫,這樣就不需要使用者自己安裝了

同時可以將cnpm作為包dependencies依賴安裝,通過cwd: __dirname引數,將指令執行目錄指定為當前目錄,這樣npx cnpm執行時,就會去cncc目錄的node_modules下找到cnpm命令,從而實現呼叫,不需要重複的在全域性進行依賴的安裝,大大提升指令執行速度

最後

工具原理很簡單,解決的問題也非常明確,希望能夠幫助讀者省下幾分鐘的時間,提升開發的幸福度


當然工具還有很多可優化的點,比如先通過對比 npm 和 cnpm 的版本號,如果一致就不需要同步了,這樣可以大大加快同步的速度

目前由於網路原因從 npm 映象源拉包版本資訊相對較慢,所以本期沒有加這個功能,讀者如果有更好的建議,歡迎評論區交流

同時可以將這個指令放在 "npm postpublish" 勾點中,這樣釋出後自動觸發同步,更加省心


完整原始碼見:GitHub