🤒 问题
当遇到多个项目每个项目依赖的 Node.js 版本不相同时,我们需要手动用 nvm use
切换版本号,太麻烦还容易忘记。只要重复做的事情就要问问能否自动化。
我们想要的效果是:cd
到某个项目,自动切换 Node.js 版本。
nvm 自动切换 macOS 支持但不支持 Windows,且定义在 package.json 中的版本号也无法切换。
索性自己写一个!
🏗️ 实现
一般版本号会存在两个地方:.nvmrc 或 package.json 的 engines
字段。
.nvmrc:
22
package.json:
{
"name": "foo",
...
"engines": {
"node": ">=22.0.0"
},
...
}
思路:我们可以重写 cd
命令,在 Linux 下可以使用 alias。
📁 覆写 cd
命令
.zshrc:
cd() {
builtin cd "$@" && change_node_version_per_project
}
builtin cd
表示使用内置命令"$@"
将cd
所有参数传给内置cd
命令,相当于 js 的...args
,如此我们并没有破坏cd
的功能,而是对其进行了增强。
🎯 实现 change_node_version_per_project
change_node_version_per_project() {
local nvmrc_path="./.nvmrc"
if [[ -f "$nvmrc_path" ]]; then
local node_version=$(grep -oP '\d+(\.\d+)?(\.\d+)?' .nvmrc | head -n1)
echo '---------------------------------------'
echo "node_version in .nvmrc is $node_version"
echo '---------------------------------------'
nvm use "$node_version" || use_from_pkg_json
else
# echo "No .nvmrc file found in the current directory."
use_from_pkg_json
fi
}
Best Practices:局部变量使用
local
是好习惯避免定义全局变量
- 优先从当前目录的
.nvmrc
获取版本号,通过正则表达式匹配,并且只取第一个 (head -n1
)。 nvm use "$node_version" || use_from_pkg_json
:用||
的用意是如果版本号切换报错,则兜底去package.json
获取版本号。- 如果不存在
.nvmrc
则去package.json
获取版本号use_from_pkg_json
。
📦 实现 use_from_pkg_json
use_from_pkg_json() {
if [[ -f "./package.json" ]]; then
local node_version=$(grep -A 2 engines package.json | grep -oP '[0-9]+' | head -n1);
echo '---------------------------------------------'
echo "engines.node in package.json is $node_version";
echo '---------------------------------------------'
# local pkg_json_path="package.json"
# local node_version=$(jq -r '.engines.node' "$pkg_json_path" | cut -d' ' -f1)
if [ -z "$node_version" ]; then
echo "No node version specified in package.json."
else
nvm use "$node_version"
fi
fi
}
grep -A 2 engines package.json
:从 package.json 中匹配engines
:使用grep -A 2
(A
表示After
)即从匹配处往下多获取两行
匹配示例如下:
"engines": {
"node": ">=22.0.0"
},
if [ -z "$node_version" ]
: 如果匹配结果为空则打印未找到,否则使用nvm use xxx
切换版本号。
至此我们的功能完整实现了。
💐 效果
如果某个项目没有配置 nvmrc 但是指定了 engines:cd dir_with_package_json_and_engines
---------------------------------------------
engines.node in package.json is 16
---------------------------------------------
Now using node v16.20.2 (64-bit)
如果有 nvmrc:cd dir_with_nvmrc
---------------------------------------
node_version in .nvmrc is 22
---------------------------------------
Now using node v22.7.0 (64-bit)