如何限制node项目中的包管理器?only-alow 源码分析

324 阅读2分钟

为什么需要统一包管理器

目前前端并没有统一的包管理器,整个管理器圈子是比较混乱的,对于npm,yarn,pnpm等都有各自维护依赖的方式,如果一个大型项目同时使用多种pacakge manager将很难维护,且容易导致线上问题

为了解决这个问题需要限制一个项目中的包管理器种类,但是npm并没有这样的能力,因此目前大部分有需求的项目使用only-allow完成限制功能

only-alow简单使用

贴一下官方文档里的使用方式

{
  "scripts": {
    "preinstall": "npx only-allow pnpm"
  }
}

only-allow通过命令行入参获取package manager白名单,在preinstall阶段完成package manager的校验,如果校验不通过无法进入install阶段

源码分析

only-allow如何限制包管理呢,下面来看一下源码实现

获取包管理器白名单

const argv = process.argv.slice(2)
if (argv.length === 0) {
  console.log('Please specify the wanted package manager: only-allow <npm|cnpm|pnpm|yarn>')
  process.exit(1)
}
const wantedPM = argv[0]

在执行npx only-allow pnpm时解析入参即可获取到包管理器名称(wantedPM),如果入参为空会报错

入参合法性检验

if (wantedPM !== 'npm' && wantedPM !== 'cnpm' && wantedPM !== 'pnpm' && wantedPM !== 'yarn') {
  console.log(`"${wantedPM}" is not a valid package manager. Available package managers are: npm, cnpm, pnpm, or yarn.`)
  process.exit(1)
}

only-allow会对入参进行检验,如果不是npm/pnpm/yarn/cnpm就会报错

这一步校验还是很合理的,如果用户填了一个不存在的pakcage manager,这个项目就没有人可以安装依赖了(考虑很全面,用户体验良好)。

获取当前运行的包管理器

通过which-pm-runs获取用户当前使用的npm包,这个包的实现也比较简单(这个包每周居然有200w+的下载量)

module.exports = function () {
  if (!process.env.npm_config_user_agent) {
    return undefined
  }
  return pmFromUserAgent(process.env.npm_config_user_agent)
}

function pmFromUserAgent (userAgent) {
  const pmSpec = userAgent.split(' ')[0]
  const separatorPos = pmSpec.lastIndexOf('/')
  const name = pmSpec.substring(0, separatorPos)
  return {
    name: name === 'npminstall' ? 'cnpm' : name,
    version: pmSpec.substring(separatorPos + 1)
  }
}

通过process.env.npm_config_user_agent获取当前使用的包管理器,这列对cnpm有额外的判断,看一下就好了

输出提示信息

if (usedPM && usedPM.name !== wantedPM && !isInstalledAsDependency) {
  const boxenOpts = { borderColor: 'red', borderStyle: 'double', padding: 1 }
  switch (wantedPM) {
    case 'npm':
      console.log(boxen('Use "npm install" for installation in this project', boxenOpts))
      break
    // some code
  }
  process.exit(1)
}

这里只是简单的判断和输出了,boxen是一个在terminal输出方框的库,感兴趣可以看一下

总结一下

only-allow在preinstall阶段完成对package manager的判断,如果不符合配置则抛出error,提示用户无法进入install阶段

test.png