持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
【若川视野 x 源码共读】第16期 | 一行代码统一规范 包管理器 点击了解本期详情一起参与。
今天阅读的库是:only-allow
这个库是用来限制项目包管理器,从而实现统一包管理器规范
使用场景
在vue的源码中,我们知道vue使用的是pnpm来做包管理器,那么他是怎么统一整个项目都使用这个包管理器呢,我们看下源码
在他的package.json中有一段代码
// package.json
/* ...省略 */
"scripts": {
/* ...省略 */
"preinstall": "node ./scripts/preinstall.js"
}
// preinstall.js
if (!/pnpm/.test(process.env.npm_execpath || '')) {
console.warn(
`\u001b[33mThis repository requires using pnpm as the package manager ` +
` for scripts to work properly.\u001b[39m\n`
)
process.exit(1)
}
这段代码大致就是如果不是使用pnpm执行脚本就会抛出异常
那么,有没有一种方法,不用每次创建项目都需要创建一个文件来对包管理器做规范化呢
only-allow的出现解决了这个问题
如果使用pnpm,则可以编写如下代码:
{
"scripts": {
"preinstall": "npx only-allow pnpm"
}
}
源码分析
我们来看下这个库是怎么实现的,从package.json中得知,入口为bin.js
源码中引用了这两个依赖
// 获取当前包管理器
const whichPMRuns = require('which-pm-runs')
// 装饰控制台输出
const boxen = require('boxen')
#!/usr/bin/env node
// 获取当前包管理器
const whichPMRuns = require('which-pm-runs')
// 装饰控制台输出
const boxen = require('boxen')
const argv = process.argv.slice(2)
// 检测用户输入的包管理器名称 比如:npx only-allow pnpm
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)
}
// 获取使用的包管理器
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)
}
代码比较精简,就是获取当前node环境中的包管理名称和设定的名称做对比,如果不一致则抛出异常
接下来,我们来看下which-pm-runs的实现 源码地址
'use strict'
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)
}
}
传入当前环境的包管理信息,做字符串分割,返回一个对象
{name: "pnpm", version: "7.9.5"}
总结
通过vue和only-allow库的研究,使用一些工具和手段来约束团队,从而实现项目包管理器的规范化
而这些使用这些工具,能够帮助我们更加便捷的实现规范化流程,使得项目流程上更加统一和工程化。