项目统一规范包管理器

news2024/9/22 19:45:09

一般来说每个团队都会统一规定项目内只使用一个包管理器,譬如: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 不同版本的差异

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/69282.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot自动装配原理分析,看完你也能手写一个starter组件

什么是 SpringBoot 2012 年 10 月&#xff0c;一个叫 Mike Youngstrom 的人在 Spring Jira 中创建了一个功能请求&#xff0c;要求在 Spring Framework 中支持无容器 Web 应用程序体系结构&#xff0c;提出了在主容器引导 Spring 容器内配置 Web 容器服务。这件事情对 SpringBo…

Linux 进程间通信

目录 进程间通信的必要性 进程间通信的技术背景 进程间通信的本质理解&#xff1a; 管道IPC&#xff1a;匿名管道 示意图 匿名管道的本质原理&#xff1a; demo示例代码&#xff1a; pipe 系统调用 注意&#xff1a; 管道读写的4种情况&#xff1a; 管道的特点&…

H5UI库和二维码

一、H5UI库 1、使用方法&#xff1a; ​ &#xff08;1&#xff09;页面中引入css文件 ​ h5ui.css &#xff08;h5ui.min.css&#xff09; ​ &#xff08;2&#xff09;页面中引入js文件 ​ jquery.min.js ​ h5ui.min.js 2、组件的用法 ​ &#xff08;1&#xff09…

为您的高速SPI添加强大和可靠的隔离交流

介绍 串行外设接口&#xff08;SPI&#xff09;是工业设备中常用于数字处理器核心和外围设备之间通信的一种协议。然而&#xff0c;为了安全使用&#xff0c;有必要对外围设备和核心进行电隔离。虽然隔离和SPI都是成熟的技术&#xff0c;但将两者接口并不像预期的那么简单。 …

SAP ABAP——数据类型(五)【LIKE系列关键字】

&#x1f4ac;个人网站&#xff1a;【芒果个人日志】​​​​​​ &#x1f4ac;原文地址&#xff1a;SAP ABAP——数据类型&#xff08;五&#xff09;【LIKE系列关键字】 - 芒果个人日志 (wyz-math.cn) &#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税…

【git】简洁实用教程

虽然之前有git的笔记了&#xff0c;但是操作和命令太多&#xff0c;有点冗余&#xff0c;下面整理出最常见的一些场景和git需求。 零、Git速查表 好习惯&#xff1a;每次提交后和开发代码前&#xff0c;都应该pull下 常见命令&#xff1a; git clone拉取服务器代码&#xff0…

深度解读 | 如何构建以指标为核心的ABI平台?

在上期一文中&#xff0c;我们了解到BI不同发展阶段运行模式及遇到的问题。“报表阶段”是以报表粒度进行管理&#xff0c;数据和报表完全耦合在一起&#xff0c;在不同报表间产生数据和指标的冗余和重复&#xff0c;形成报表爆炸、技术债&#xff0c;导致数据不可信、分析不敏…

Windows 7下安装oracle12c报错:O/S-Error:(OS 1385)

查看报错日志&#xff1a;C:\Program Files\Oracle\Inventory\logs\ installActions2015-04-21_09-29-15AM.log, 提示查看&#xff1a; D:\app\Administrator\cfgtoollogs\netca\trace_OraDB12Home1-150421 11上午1616.log &#xff0c; 打开该log&#xff0c;在尾部发现如下错…

LaTeX页眉页脚自定义【有图有代码】

LaTeX页眉页脚自定义【有图有代码】一、自定义页眉页脚示例【双页文档】\fancyhead \fancyfoot1、代码讲解2、自定义代码3、页眉和页脚的装饰线4、总页数二、自定义页眉页脚示例【单页文档】\rhead \rfoot三、\pagestyle{}介绍四、设置当前页面样式\thispagestyle{}平时在写报告…

中级软件设计师备考上午题总结

中级软件设计师备考上午题总结 前言 10月末11月初备考了中级软件设计师&#xff0c;备考时间总计20天整&#xff0c;由于预留的备考时间并不多&#xff0c;上午题复习策略主要是以看别人整理好的笔记为主&#xff0c;不懂的地方以看zst_2001的视频为辅&#xff0c;最后预留了…

JDBC Java对数据库增删改查(完整案例)

目录 一.综合上述7个步骤&#xff0c;实现向student表中插入一条数据。 1、注册驱动 2 、获取数据库连接对象 3、获取发送SQL语句对象 4、编写SQL语句&#xff0c;SQL语句最好是先在SQLyog里面写一遍并运行一下&#xff0c;保证SQL语句没有语法 错误&#xff0c;这里sid是…

C语言百日刷题第十二天

前言 今天是刷题第12天&#xff0c;放弃不难&#xff0c;但坚持一定很酷~ 临近期末&#xff0c;刷几套模拟题 C语言百日刷题第十二天前言选择题判断题编程题选择题 1.设a1;b2;c3;d4;则表达式a<b?a:c<d? a:d的结果是____。 A、3 B、1 C、4 D、2 正确选项&#xf…

Linux多线程(一):什么是线程?

文章目录一、前言二、什么是线程&#xff1f;三、线程是如何实现的&#xff1f;四、基本概念梳理五、后记一、前言 什么是线程&#xff1f;操作系统书籍上可能会给你这样的解释与定义&#xff1a; 线程是在进程内部运行的执行流线程比进程的执行力度更细&#xff0c;线程的调…

年底无情被裁,我面试大厂的这几个月…

2022年接近尾声&#xff0c;“金九十”今年也变成了“铜九铁十”。 大厂不断缩招&#xff0c;不容忽视的疫情影响&#xff0c;加上不断攀升的毕业生人数&#xff0c;各种需要应对的现实问题让整个求职季难上加难。 在这个异常残酷的求职季&#xff0c;很多人的困惑、面临的问…

VM系列模块基本信息

外形尺寸&#xff1a; VM501/604/608 30.0mmX26.0mmX4.3mm 贴插封装-20 VM511/614/618 60.0mmX36.0mmX4.8mm 直插-22 VM704 30.0mmX26.0mmX6.0mm 直插-20 VM704S 32.0mmX32.0mmX15.0mm 直插-20 数字接口&#xff1a;UARTI2C UART&#xff1a;TTL/R…

03-SpringBoot进阶

知识回顾 知识目标 1、SpringBoot单元测试【掌握】 2、SpringBoot 整合 MybatisPlus【重点】 3、SpringBoot添加分页插件【掌握】 4、SpringBoot定义拦截器【掌握】 5、SpringBoot使用类型转换器【掌握】 6、文件上传【掌握】 7、SpringBoot异常处理【掌握】 8、SpringBoot定…

Navicat 16 和表空间 | 第 一 部分

优点 你知道 Navicat 16 支持表空间吗&#xff1f;表空间是表&#xff08;以及索引、大型对象和长数据&#xff09;的存储结构&#xff0c;它将数据库中的数据组织成与在文件系统上存储数据的位置相关的逻辑存储组。它的主要功能是联接物理存储层和逻辑存储层。通过将表分配给表…

c盘空间怎么扩大?

电脑系统主要存储在C盘&#xff0c;用户还可能会将一些软件、文件夹存储在C盘&#xff0c;所以电脑C盘必须拥有足够充足的空间&#xff0c;为了大家更好地使用电脑&#xff0c;这里小编带来的就是电脑扩大C盘空间的教程。 1、右击桌面的计算机图标&#xff0c;然后选择管理! 2、…

过滤器的使用

过滤器的使用过滤器介绍过滤器的使用配置过滤器过滤器路径的配置规则前置、后置、环绕过滤器过滤器链过滤器的优先级过滤器介绍 过滤器(Filter)是位于客户端与服务器资源之间的一道过滤技术&#xff0c;可以在客户端请求到达目标资源之前进行预处理业务。 过滤器作用 执行多个…

【Java实战】系统设计需要注意的细节

目录 一、前言 二、设计规约 1.【强制】存储方案和底层数据结构的设计获得评审一致通过&#xff0c;并沉淀成为文档。 2.【强制】在需求分析阶段&#xff0c;如果与系统交互的 User 超过一类并且相关的 UseCase 超过 5 个&#xff0c;使用用例图来表达更加清晰的结构化需求。…