1.前言
最近参加源码共读的小组,每周一份源码学习笔记。
预计阅读时间:4分钟,你可以收获:
- 代码层面规范包管理器,理解代码卡控的好处。
- 了解小工具 only-allow 的代码实现逻辑。
- 了解 npm 脚本执行器钩子,
preorpost。 - 了解 process 的部分属性作用
2.场景
在前端工程化大行其道的如今,包的依赖安装已成为同学们最常接触的工作内容,一般大家会通过文档或约束达成共识,静默的使用某一个包管理工具。
但是,如果某一天,团队中的某个同学使用其他包管理工具进行依赖的安装,且提交了。那么很大可能会直接影响到同时在该分支工作的其他同学,带来不必要的精力损耗。
所以我们需要通过代码层面的规范,尽可能减少因为意外情况带来的损失。
3.环境准备
3.1. 安装 Visual Studio Code 编辑器
这里关于编辑器的安装,就不过多介绍了,可以点击这里进行查看。
3.2. 安装 Git 环境
3.3. node.js
3.3. 克隆代码
# 克隆官方仓库
git clone https://github.com/pnpm/only-allow.git
cd only-allow
# 需要先行安装 pnpm 包管理器,
# npm i -g pnpm
pnpm i
我们可以看到以下的目录结构
到此,相关环境准备完成。
4. 前置知识
4.1. npm 钩子
这里直接放官网的描述:
只需创建另一个具有匹配名称的脚本,并在它们的开头添加“pre”或“post”,就可以在
package.json的脚本中定义前置或后置的脚本内容。
{
"scripts": {
"precompress": "{{ executes BEFORE the `compress` script }}",
"compress": "{{ run command to compress files }}",
"postcompress": "{{ executes AFTER `compress` script }}"
}
}
简单理解就是在执行自定义脚本的生命周期中,在开始和结束存在一个入口,允许我们添加自己的前后置操作。
本文中提及的 only-allow ,通过使用 preinstall 在执行安装命令前加入相关的期望卡控。
4.2. process
process 对象是 Node 的一个全局对象,提供当前 Node 进程的信息。它可以在脚本的任意位置使用,不必通过require命令加载。该对象部署了EventEmitter接口。
4.2.1. process.exit()
process.exit 方法用来退出当前进程。它可以接受一个数值参数,如果参数大于0,表示执行失败;如果等于0表示执行成功。
4.2.2. process.argv
process.argv 属性返回一个数组,由命令行执行脚本时的各个参数组成。它的第一个成员总是 node,第二个成员是脚本文件名,其余成员是脚本文件的参数。
我们写个 test.js 查看下实际输出:
# test.js
console.log(process.argv)
# shell
node test.js
会输出一下内容:
PS D:\my_test\ReadingSourceCode\only-allow> node test.js a b c d
Debugger listening on ws://127.0.0.1:4736/90caf438-5529-4122-953d-4f891877ca98
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached.
[
'C:\\Program Files\\nodejs\\node.exe',
'D:\\my_test\\ReadingSourceCode\\only-allow\\test.js',
'a',
'b',
'c',
'd'
]
Waiting for the debugger to disconnect...
根据这个信息,我们就可以在 package.json 中设置期望的包管理工具,后续进行展示。
4.2.3. process.env
process.env 属性返回一个对象,包含了当前Shell的所有环境变量。
我们将通过这个属性来获取当前包管理工具的信息。
如果你希望比较全面的了解该对象,请前往阮一峰老师的博客进一步阅读。 process 对象
5. only-allow 源码
5.1. 用法介绍
Force a specific package manager to be used on a project 强制在一个项目使用一个特定的包管理
如果你想强制使用 npm, add:
{
"scripts": {
"preinstall": "npx only-allow npm"
}
}
如果你想强制使用 pnpm, add:
{
"scripts": {
"preinstall": "npx only-allow pnpm"
}
}
如果你想强制使用 yarn, add:
{
"scripts": {
"preinstall": "npx only-allow yarn"
}
}
5.2. 断点
通过观察 package.json 我们知道入口是 bin.js 文件,在 scripts 中添加限制
在开始的位置打上断点
这里记得开启 VS Code 的 auto attach,不了解的同学可以查看若川老师的 新手向:前端程序员必学基本技能——调试JS代码
5.3. 调试
打开控制台,输入
npm i
调试过程已经可以看到需要的信息。 包含有 实际的包管理器 和 从参数中限制的类型。
剩下的就是走完判断流程即可。
5.4. 完整代码
#!/usr/bin/env node
const whichPMRuns = require('which-pm-runs')
const boxen = require('boxen')
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)
}
// 获取期望的包管理参数信息
// 对应 package.json - scripts - node bin.js pnpm 的 pnpm
const wantedPM = argv[0]
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)
}
// 这里是获取运行时包管理的信息
const usedPM = whichPMRuns()
if (usedPM && usedPM.name !== wantedPM) {
// 设置提示边框属性
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 '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)
}
6. 总结
通过本文,我们了解了 npm 的脚本钩子和 process 的简单应用。only-allow 通过获取系统环境运行时的信息,和预设好的参数信息进行对比,来限制预期外包管理器的使用。
- 学习文章来源: 若川老师-从 vue3 和 vite 源码中,我学到了一行代码统一规范团队包管理器的神器
源码共读小组,感兴趣的同学可以添加若川老师微信 ruochuan12,大家一起共同学习。