在多人协作的项目中,因每个人的习惯不同,使用的包管理工具也不一样,可能会有些「妖怪」没有注意 lock 文件设置,这样会使原本的 lock 文件失效,随即可能会带来某些因为版本而不兼容的问题。
所以在实际的开发中,我们需要有一定的规范,通过工程化的强约束去杜绝这种错误的发生。
了解 npm hooks
npm 在自定义命令时,可以使用 pre or post 钩子进行一些额外的操作,例如:
"predev": "echo 'pre dev start'"
"dev": "node infex.js"
"postdev": "echo 'post dev start'"
在执行 npm run dev 时,会先去查找该命令是否有 pre 命令,如果有就先执行该命令,成功后再执行原命令,如果此命令成功结束了,然后去查找该任务是否有 post 命令,如果有就执行该命令。
当然,这也同样适用于 npm 自身的行为,例如 install 命令
判断 npm 客户端
因为 js 文件通过 node 去解释执行,我们完全可以扫描进程找到对应的信息,在 preinstall 时,执行自己的 shell 文件进行限制。
有没有其他的方式呢? 我们不妨看看 使用 npm 客户端的时候会向环境变量中注入些什么东西吧
const fs = require('fs');
fs.writeFileSync('process.json', JSON.stringify(process.env, null, 4));
从文件中我们可以找到 "npm_config_user_agent": "npm/6.14.12 node/v12.22.1 darwin arm64",有点类似于 navigator.userAgent
无论是 yarn 或者 npm 等包管理器,都会向环境变量中注入npm_config_user_agent 携带自身信息。
我们来看看 vite 是怎么进行限制的
"preinstall": "npx only-allow pnpm"
而 only-allow 的包又使用了 which-pm-runs,我们再往上看看,他是怎么判断 npm 客户端的。
'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('/')
return {
name: pmSpec.substr(0, separatorPos),
version: pmSpec.substr(separatorPos + 1)
}
}
找到了,瞧,他就是通过包管理器会向环境变量中注入信息来判断的,和咱们"不谋而合"
参考