如何统一 npm 包管理
在使用 vite3 的时候,会发现其内部的包都会统一采用 yarn 或是 pnpm 进行三方依赖管理,且只允许使用指定的包管理工具进行管理,这是怎么做到的呢?带着疑问,发现了他们使用的包:only-allow (opens new window), 发现其简单的通过比对命令行来实现了包的管控,来看看是怎么做到的吧.
# 前置知识
// 查看使用的管理工具及版本
.npm_config_user_agent:'yarn/1.22.17 npm/? node/v16.13.1 win32 x64';
// 输出:
// npm/6.14.5 node/v14.17.1 win32 x64
// yarn/1.22.10 npm/? node/v14.17.1 win32 x64
.npm_package_name // 当前package.name
.npm_execpath: 'C:\\Users\\xxx\\AppData\\Roaming\\npm\\node_modules\\yarn\\bin\\yarn.js' // 绝对路径地址
.
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 方法一
// package.json
"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)
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
通过判断运行的包管理工具的绝对路径词缀是否含有/npm/pnpm/yarn 来进行是否要继续运行的操作
# 方法二
only-allow 源码
#!/usr/bin/env node
const whichPMRuns = require("which-pm-runs");
const boxen = require("boxen");
/**
* argv返回数组的成员依次是命令行的各个部分,真正的参数实际上是从process.argv[2]开始。
* node argv.js a b c = [ 'node', '/path/to/argv.js', 'a', 'b', 'c' ]
*/
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);
}
// 判断期望的包管理工具是否为yarn/npm/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 ins123stall" 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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
which-pm-runs 也非常简单,接下来往下看:
// which-pm-runs
module.exports = function () {
// 通过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),
};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
编辑 (opens new window)
上次更新: 2022/12/11, 20:19:48