当前位置: 首页 > news >正文

项目统一规范包管理器

一般来说每个团队都会统一规定项目内只使用一个包管理器,譬如:npm、yarn、pnpm等,我们可以在文档中或者项目根目录REDEM.md中进行描述来形成共识,但毕竟是文档,并不能真正的进行约束,如果有项目成员没有看文档描述,而使用了不同的包管理器,则可能会因为lock file 失效而导致项目无法正常运行,针对这种情况就有了 only-allow 这款解决该问题的工具

这篇不说该工具的使用,而是去实现一个改包的源码,因为改包比较小,代码量也不是很大,知道核心就可以了。源码GitHub地址:pnpm/only-allow

我们想要统一使用同一个包管理器,就是在成员拉下代码后,npm install 之前需要做一些事情,比如团队统一使用pnpm,如果成员使用 npm install 就给他抛出错误,并且终止npm install

首先我们要知道一个钩子:preinstall, preinstall可以在运行npm install之前执行某个命令,node原生中的 process.exit(code)  code非0时终止运行。

首先第一步我们在package.json中添加以下代码

"scripts": {
  "preinstall": "node check-npm.js pnpm"
}

也就是当我们npm install 之前 会去执行 check-npm.js脚本 ,后面的pnpm是需要我们必须传递的参数,也就是我们渴望该项目统一使用什么包管理器

我们可以通过nodejs中的process.argv获取到我们传递的参数(包管理器),如下 

process.argv.slice(2)[0] //pnpm

如果没有传递参数我们,我们应该打印出一条日志进行提示,并终止运行

const argv = process.argv.slice(2)

if(argv.length === 0) {
  const name = PACKAGE_MANAGER_LIST.join('|')
  console.log(`Please specify the wanted package manager: only-allow <npm|cnpm|yarn|pnpm>`)
  process.exit(1)
}

如果用户乱传参数显然也是不行的,我们也应打印出一条日志给与提示,并终止运行

const PACKAGE_MANAGER_LIST = ['npm', 'cnpm', 'yarn', 'pnpm']

const argv = process.argv.slice(2)

const wantedPM = argv[0]

if(!PACKAGE_MANAGER_LIST.includes(wantedPM)) {
  const name = PACKAGE_MANAGER_LIST.join(',')
  console.log(`"${wantedPM}" is not a valid package manager. Available package managers are: ${name}.`)
  process.exit(1)
}

上面两种情况考虑完之后,就是要考虑我们如何才能知道用户是使用的什么包管理器进行安装依赖的呢,答案就是我们可以通过 process.env.npm_config_user_agent 来获取,下面给大家看下该值到底是个什么东西

 

它其实就是个字符串,我们使用空格进行split切割取第一个 就可以拿到我们使用的包管理器和对应包管理器的版本 ,这样我们就可以写个方法简单封装一下,来返回当前使用的包管理器和当前包管理器的版本 

function getPackageManagerByUserAgent(userAgent) {
  if(!userAgent) {
    throw new Error(`'userAgent' arguments required`)
  }
  const spec = userAgent.split(' ')[0]
  const [name, version] = spec.split('/')

  return { name, version }
}

最后就是我们的完整代码

check-npm.js 

const PACKAGE_MANAGER_LIST = ['npm', 'cnpm', 'yarn', 'pnpm']

// 获取我们传递的参数<[npm|cnpm|yarn|pnpm]>
const argv = process.argv.slice(2)

// 没有传递参数给与提示并终止运行
if(argv.length === 0) {
  const name = PACKAGE_MANAGER_LIST.join('|')
  console.log(`Please specify the wanted package manager: only-allow <${name}>`)
  process.exit(1)
}

// 我们传递的参数值<npm|cnpm|yarn|pnpm>
const wantedPM = argv[0]

// 乱传参数给与提示并终止运行
if(!PACKAGE_MANAGER_LIST.includes(wantedPM)) {
  const name = PACKAGE_MANAGER_LIST.join(',')
  console.log(`"${wantedPM}" is not a valid package manager. Available package managers are: ${name}.`)
  process.exit(1)
}

// 当前使用的包管理器
const usedPM = getPackageManagerByUserAgent(process.env?.npm_config_user_agent).name

// 当前使用的包管理器和我们约束的不一样 抛出一条错误日志并终止运行
if(usedPM !== wantedPM) {
  console.error(`You are using ${usedPM} but wanted ${wantedPM}`)
  process.exit(1)
}

function getPackageManagerByUserAgent(userAgent) {
  if(!userAgent) {
    throw new Error(`'userAgent' arguments required`)
  }
  const spec = userAgent.split(' ')[0]
  const [name, version] = spec.split('/')

  return { name, version }
}

好了,我们已经实现了only-allow的功能了

问题: 

preinstall 钩子理论上应该在安装依赖前触发,但是经验证 ,npm和yarn调用preinstall的时机并不一样,npm 仅仅在 npm install 时运行,而 npm insatll <package-name> 则不会,但yarn则会在 yarn install 和 yarn add <pk-name>时都会运行,所以如果想用这种方式限制npm使用,可能无法达到预期

preinstall 从字面意思理解是在install之前执行。但是到了 NPM7.0版本之后就有所不同,preinstall就有了bug,实际上是先install再执行的preinstall。pnpm不知道从哪个版本开始也跟NPM7.0+一样。但是pnpm6.21版本开始新增了 pnpm:devPreinstall 脚本,所以使用pnpm可以考虑将preinstall换成pnpm:devPreinstall 即可达到NPM7.0以下版本的效果。具体参考:NPM preinstall 不同版本的差异

相关文章:

  • 04 Vue 注册plgins的多种形式
  • 【C语言程序设计】实验 4
  • Java中Map集合体系的基本使用和常用API
  • 【在Vue脚手架项目中使用axios】
  • mysql分库分表后,分页查询问题解决方案
  • 改进蝠鲼觅食优化算法(Matlab代码实现)
  • 【AI学习笔记】Error: ffmpeg error (see stderr output for detail)
  • 世界杯征文活动 | 神奇!一段JavaScript代码生成会动的足球
  • 职场生涯亮红灯要注意这些
  • 一文掌握 Go 文件的写入操作
  • 一文读懂Linux内存分配策略
  • [附源码]Python计算机毕业设计Django学习互助辅助系统
  • 论文投稿指南——中国(中文EI)期刊推荐(第2期)
  • 一个redux使用案例模板
  • 超详细的水果FL Studio21最新版更新全功能详细介绍!80项更新与改进!
  • CENTOS上的网络安全工具(十四)搬到Docker上(2)?
  • 微服务框架 SpringCloud微服务架构 21 RestClient 操作文档 21.1 新增文档
  • APP自动化测试系列之Appium介绍及运行原理
  • Nginx学习笔记
  • 蜣螂优化算法Dung beetle optimizer附matlab代码
  • 电加热油锅炉工作原理_电加热导油
  • 大型电蒸汽锅炉_工业电阻炉
  • 燃气蒸汽锅炉的分类_大连生物质蒸汽锅炉
  • 天津市维修锅炉_锅炉汽化处理方法
  • 蒸汽汽锅炉厂家_延安锅炉厂家
  • 山西热水锅炉厂家_酒店热水 锅炉
  • 蒸汽锅炉生产厂家_燃油蒸汽发生器
  • 燃煤锅炉烧热水_张家口 淘汰取缔燃煤锅炉
  • 生物质锅炉_炉
  • 锅炉天然气_天燃气热风炉