- what 一个能限制当前项目使用的包管理器的npm包
- why 用于规范团队开发流程,避免成员之间开发时,因为使用不同的包管理器而引发的一些问题
- how
"scripts": {
"preinstall": "npx only-allow 你希望的包管理器"
}
- 源码解析
源码不长就36行代码,每行代码的解析都以注释的形式给出
#!/usr/bin/env node
const whichPMRuns = require('which-pm-runs') // 根据 process.env.npm_config_user_agent 获取当前是啥包管理器
const boxen = require('boxen') // 可以在控制台输出特定样式的矩形,相当于一个输出美化的工具
// 获取用户输入的参数,这里第一个一般是node 第二个是 当前运行脚本的名称 其余的都是用户输入的参数
const argv = process.argv.slice(2)
// 用户未输入直接退出
if (argv.length === 0) {
console.log(
'Please specify the wanted package manager: only-allow <npm|pnpm|yarn>'
)
process.exit(1)
}
// 获取用户希望使用的包管理器
const wantedPM = argv[0]
// 判断用户希望的包管理器是否合法, 不合法直接退出
// 这里是否可以将合法的包管理器定义为枚举 或者定义成常量数组然后 arr.some一下语义性与维护性会更好
if (wantedPM !== 'npm' && wantedPM !== 'pnpm' && wantedPM !== 'yarn') {
console.log(
`"${wantedPM}" is not a valid package manager. Available package managers are: npm, pnpm, or yarn.`
)
process.exit(1)
}
// 根据 whichPMRuns 获取当前用户实际使用的包管理器
const usedPM = whichPMRuns()
// 对 usedPM 做一次异常处理,并且判断实际使用的包管理器是否与用户希望的一致
if (usedPM && usedPM.name !== wantedPM) {
// 定义格式化输出的样式
const boxenOpts = { borderColor: 'red', borderStyle: 'double', padding: 1 }
// 根据不同类型的包管理器,给出不同的提示
// 这里的代码能否改为ts的枚举,这样可以避免打错字母或者漏分支等低级错误
switch (wantedPM) {
case 'npm':
// 这里的代码过于冗余,基本一样的代码写了3份,坏味道比较浓
// 能否在分支中只定义需要提示的文案,最后统一console.log
console.log(
boxen('Use "npm 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)
}
- ts 改良版
看源码过程中发现很多地方可以进行优化,就顺手使用ts进行了一次简单重构
#!/usr/bin/env node
import whichPMRuns from 'which-pm-runs'
import boxen, { Options, BorderStyle } from 'boxen'
/** 合法的包管理工具 */
enum LegalPMEnum {
npm = 'npm',
pnpm = 'pnpm',
yarn = 'yarn',
}
const argv = process.argv.slice(2)
if (argv.length === 0) {
console.log('Please specify the wanted package manager: only-allow <npm|pnpm|yarn>')
process.exit(1)
}
const wantedPM = argv[0] as LegalPMEnum
const LegalPMArr = [LegalPMEnum.npm, LegalPMEnum.pnpm, LegalPMEnum.yarn]
if (LegalPMArr.every(item => item !== wantedPM)) {
console.log(`"${wantedPM}" is not a valid package manager. Available package managers are: npm, pnpm, or yarn.`)
process.exit(1)
}
const usedPM = whichPMRuns()
if (usedPM && usedPM.name !== wantedPM) {
let errMsg = ''
switch (wantedPM) {
case LegalPMEnum.npm:
errMsg = 'Use "npm install" for installation in this project'
break
case LegalPMEnum.pnpm:
errMsg = `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/`;
break
case LegalPMEnum.yarn:
errMsg = `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/`
break;
default:
const n: never = wantedPM
}
const boxenOpts: Options = { borderColor: 'red', borderStyle: BorderStyle.Double, padding: 1 }
console.log(boxen(errMsg,boxenOpts))
process.exit(1)
}