源码共读之路-01-only-allow

425 阅读5分钟

1.前言

最近参加源码共读的小组,每周一份源码学习笔记。

预计阅读时间:4分钟,你可以收获:

  1. 代码层面规范包管理器,理解代码卡控的好处。
  2. 了解小工具 only-allow 的代码实现逻辑。
  3. 了解 npm 脚本执行器钩子,pre or post
  4. 了解 process 的部分属性作用

2.场景

在前端工程化大行其道的如今,包的依赖安装已成为同学们最常接触的工作内容,一般大家会通过文档或约束达成共识,静默的使用某一个包管理工具。

但是,如果某一天,团队中的某个同学使用其他包管理工具进行依赖的安装,且提交了。那么很大可能会直接影响到同时在该分支工作的其他同学,带来不必要的精力损耗。

所以我们需要通过代码层面的规范,尽可能减少因为意外情况带来的损失。

3.环境准备

3.1. 安装 Visual Studio Code 编辑器

这里关于编辑器的安装,就不过多介绍了,可以点击这里进行查看。

3.2. 安装 Git 环境

Git 传送门

3.3. node.js

Node.js 传送门

3.3. 克隆代码

# 克隆官方仓库
git clone https://github.com/pnpm/only-allow.git
cd only-allow
# 需要先行安装 pnpm 包管理器,
# npm i -g pnpm
pnpm i

我们可以看到以下的目录结构

fefadfc5381045d0869dc2112324722b.png

到此,相关环境准备完成。

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 中添加限制

43ff9057b7e04b17a69f53b0c5b245ed.png

在开始的位置打上断点

4e222a3634744d2aadd23ecf99c3e16e.png

这里记得开启 VS Code 的 auto attach,不了解的同学可以查看若川老师的 新手向:前端程序员必学基本技能——调试JS代码

5.3. 调试

打开控制台,输入

npm i 

调试过程已经可以看到需要的信息。 包含有 实际的包管理器 和 从参数中限制的类型。

259a40b11bb9402f94b5537afb02da7c.png

剩下的就是走完判断流程即可。

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 通过获取系统环境运行时的信息,和预设好的参数信息进行对比,来限制预期外包管理器的使用。

源码共读小组,感兴趣的同学可以添加若川老师微信 ruochuan12,大家一起共同学习。