【源码学习】 第⑨期 | 团队成员npm、yarn、pnpm混用?教你一行代码规范包管理器
- 本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
- 第16期 | 一行代码统一规范 包管理器
前言
好的作品背后都通常有好的团队支撑,并且在日常开发中难免会遇到团队协作的问题。正所谓无规矩不成方圆,想要团队快速高效完成进度,必要的代码规范少不了,如果你的团队成员也混用npm、yarn、pnpm,那就快来学学一行代码规范包管理器吧~
收获清单
- npm命令钩子
- 一行代码规范包管理器
- 调试源码
- only-allow原理
调试准备
1.npm脚本命令钩子
npm install 顺序
1. `preinstall`
2. `install`
3. `postinstall`
更多npm命令钩子也可以参照 npm docs
2.一行代码规范包管理器实现
仔细看过vite源码的小伙伴应该不会陌生下面这个命令,vite的 package.json就有下面这个命令,如果只是关注实现的小伙伴其实看到这里就可以了,但我们的宗旨是知其然才能知其所以然,从命令可以看出这行代码主要依靠only-allow包实现,关键only-allow包源码只有40行左右,下面就让我们正式进入调试代码准备吧~
{
"scripts": {
"preinstall": "npx only-allow pnpm"
}
}
3.下载only-allow源码
git clone https://github.com/pnpm/only-allow.git
cd only-allow
# npm i -g pnpm
pnpm i
代码调试
1. 养成调试前先看使用说明书 README.md 的好习惯
2.从package.json找主文件入口
3.开启断点调试
//方式一:终端输入
node bin.js pnpm
// 方式二: package.json 添加script命令,如:
"scripts": {
"preinstall": "node bin.js pnpm"
}
调试截图
源码分析
1.引入依赖
// 检测执行进程的包管理器
const whichPMRuns = require('which-pm-runs')
// 在终端中创建方框
const boxen = require('boxen')
1.1 whichPMRuns源码分析
'use strict'
module.exports = function () {
// process.env.npm_config_user_agent 获取当前执行的是包管理器的名称和版本
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)
}
}
2.获取用户指定的包管理器
// 获取进程参数
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]
// 指定包管理器不是npm、cnpm、pnpm、yarn,退出进程
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)
}
3. 根据指定包管理器执行装包命令
// 当前使用的包管理器
const usedPM = whichPMRuns()
// 当前进程的路径
const cwd = process.env.INIT_CWD || process.cwd()
// 是否已经安装依赖
const isInstalledAsDependency = cwd.includes('node_modules')
// 未安装依赖并且当前进程的包管理器与指定包管理器不一致,根据指定的包管理器弹出装包错误提示并退出进程
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
case 'cnpm':
console.log(boxen('Use "cnpm install" for installation in this project', boxenOpts))
break
case 'pnpm':
console.log(boxen(`Use "pnpm install" for installation in this project.
If you don't have pnpm, install it via "npm i -g pnpm".
For more details, go to https://pnpm.js.org/`, boxenOpts))
break
case 'yarn':
console.log(boxen(`Use "yarn" for installation in this project.
If you don't have Yarn, install it via "npm i -g yarn".
For more details, go to https://yarnpkg.com/`, boxenOpts))
break
}
process.exit(1)
}
总结
今天动手调试了only-allow源码,并逐步分析了only-allow源码的实现,在此总结一下原理:其实就是利用node.js的process模块获取当前进程的包管理,若跟指定包管理器冲突就报错提示并退出进程,日常开发中我们也可以利用process模块获取进程信息,再执行相应的操作。only-allow整体实现算简单,使用上也比较方便,get这个技能就可以让其它人不敢乱用包管理器了~
转载自:https://juejin.cn/post/7142397455597109279