我写了一个根据项目自动切换node版本的插件,再也不用手动使用命令切换了
背景事情是这样的,我最近在学习Next.js,启动Next.js项目需要node版本不低于v18.17.0,然而我们公司里的老项目要求node版本不能高于v16.20.0版本。于是我上班的时候使用的版本是v16.20.0,下班学习Next使用的版本是v20.0.0。
最开始切换node版本工具,我使用的是n,但是每次上班或下班启动项目时,总是会忘记切换版本,导致启动报错,这让我觉得很麻烦,于是我打算写一个能根据项目自动切换node版本的插件。
n和nvm实现原理n实现原理n将所有版本的Node.js都保存在一个目录中(默认是/usr/local/n/versions),每个版本的Node.js被保存在一个以版本号命名的子目录中。
切换版本就是把/usr/local/n/versions/{版本号}/bin/node二进制文件复制到/usr/local/bin目录下。
「所以n切换版本是全局的,不能按目录设置node版本。」
/usr/local/n/versions目录
image.pngnvm实现原理安装:当你使用 nvm 安装特定版本的 Node.js 时,它会从 Node.js 的官方网站下载预编译的二进制包,然后将这个包解压到 ~/.nvm/versions/node 目录下的一个以版本号命名的子目录中。这意味着每个版本的 Node.js 都有各自独立的安装位置。
切换版本:当你使用 nvm use version 命令切换 Node.js 版本时,nvm 实际上是修改了 PATH 环境变量,将选定版本的 Node.js 二进制文件所在路径添加到 PATH 最前面。这样,当你在 shell 中输入 node 或 npm 命令时,就会调用选定版本的 Node.js 或 npm。
脚本加载:为了在新的 shell 会话中自动使用 nvm ,需要在用户的 bash 或 zsh 配置文件(如 ~/.bashrc 或 ~/.zshrc)中,添加 sourcing nvm.sh 的代码行。这样可以在启动新 shell 时加载 nvm 环境。
「通过这种方式,nvm 能够在不同的 shell 会话中使用各自的 Node.js 和 npm 版本,且版本间相互独立。」
~/.nvm/versions/node目录
image.pngnode脚本实现思路写一个node脚本,从项目根目录读取package.json里的nodeVersion属性,如果存在,使用n管理工具切换版本,然后在启动命令前执行这个脚本。
具体实现因为这个方案有问题,所以只实现了个demo版本。
const{spawn}=require('child_process');
const{readFileSync}=require('fs');
constpath=require('path');
const{cwd}=require('process');
//从项目根目录读取package.json里的nodeVersion,如果存在,使用n管理工具切换版本
letpackageJson=readFileSync(path.join(cwd(),'/package.json')).toString();
if(packageJson){
packageJson=JSON.parse(packageJson);
}
if(packageJson.nodeVersion){
//执行n命令
spawn('n',[packageJson.nodeVersion]);
}
在项目根目录下package.json文件中定义node版本
image.png修改启动项目命令
image.png小结这种方式需要给每个命令前加上切换版本的命令,需要也可以,但是太不优雅了,改的东西也比较多。如果能在所有npm run之前执行切换版本脚本就好了,找了很多方法,并且也看了npm run-script源码,没有找到办法,所以放弃了这条路。
vscode插件实现思路上面方案行不通,我就想了另外一个方案,一般我们启动项目都是在vscode中,所以如果能在用户打开终端时,获取当前项目里定义的node版本,自动把当前node版本切换成对应版本就行了。切换版本方案最开始想到的是用node执行命令切换,但是这样有一个问题,只能全局切换,因为使用nvm use临时切换不行,然而全局切换会影响其他项目,这个方案也不行。
查了一些资料,vscode插件开发中,可以给打开的终端发送想要执行的命令,然后终端默认执行。因为在当前终端中执行的切换命令,所以不会影响全局。
image.png具体实现创建vscode插件项目npminstallyo-g
yocode
代码实现
//extension.js
//Themodule'vscode'containstheVSCodeextensibilityAPI
//Importthemoduleandreferenceitwiththealiasvscodeinyourcodebelow
const{existsSync,readFileSync}=require('fs');
const{join}=require('path');
constvscode=require('vscode');
const{exec}=require('child_process');
//判断某个命令是否存在shell中
functioncommandExistsInShell(shell,command,callback){
letexecCommand=`type${command}`;
if(shell.includes('zsh')){
execCommand=`source~/.zshrctype${command}`;
}
exec(execCommand,{shell},(error,stdout,stderr)={
if(error){
console.warn(`Error:${error.message}`);
returncallback(false);
}
if(stderr){
console.warn(`Stderr:${stderr}`);
returncallback(false);
}
callback(true);
}
functionactivate(){
//监听打开的terminal
vscode.window.onDidOpenTerminal((terminal)={
//获取工作区目录
if(!vscode.workspace.workspaceFolders){
return;
}
//获取工作区目录路径
constpath=vscode.workspace.workspaceFolders[0].uri.fsPath;
//获取package.json
constpackageJsonFilePath=join(path,'/package.json');
//检查打开的项目中是否有package.json
if(!existsSync(packageJsonFilePath)){
return;
}
//读取package.json
letpackageJsonString=readFileSync(
packageJsonFilePath,
'utf8'
).toString();
if(!packageJsonString){
return;
}
try{
//解析package.json
constpackageJson=JSON.parse(packageJsonString);
//检查是否有nodeVersion
if(!packageJson.nodeVersion)return;
const{nodeVersion}=packageJson;
//检查当前打开的shell中nvm是否存在
//@ts-ignore
const{shellPath}=terminal.creationOptions;
commandExistsInShell(shellPath,'nvm',(exists)={
if(exists){
//检查版本是否存在,兼容zsh和fish终端
letcommand=`source~/.nvm/nvm.shnvmls${nodeVersion}`;
if(shellPath.includes('fish')){
command=`nvmls${nodeVersion}`;
}
exec(command,{shell:shellPath},(error,stdout,stderr)={
//如果当前版本不存在,安装版本
if(error){
vscode.window
.showErrorMessage(
`${nodeVersion}版本不存在,是否需要安装?`,
'是',
'否'
)
.then((value)={
if(value==='是'){
//安装版本,并切换
terminal.sendText(`nvminstall${nodeVersion}`,true);
}
return;
}
if(stderr){
vscode.window
.showErrorMessage(
`${nodeVersion}版本不存在,是否需要安装?`,
'是',
'否'
)
.then((value)={
if(value==='是'){
//安装版本,并切换
terminal.sendText(`nvminstall${nodeVersion}`,true);
}
return;
}
if(stdout){
//切换版本
terminal.sendText('nvmuse'+packageJson.nodeVersion,true);
}
}else{
vscode.window
.showErrorMessage(
'nvm命令不存在,请先安装。安装教程:',
'查看安装教程',
'否'
)
.then((value)={
if(value==='查看安装教程'){
vscode.env.openExternal(
vscode.Uri.parse('https://github.com/nvm-sh/nvm')
}
}
}catch(error){}
}
//thismethodiscalledwhenyourextensionisdeactivated
functiondeactivate(){}
module.exports={
activate,
deactivate,
};
效果展示
Kapture 2024-01-24 at 22.32.47.gif最后插件已经上传到vscode插件市场了,需要的可以前往https://marketplace.visualstudio.com/items?itemName=dbfu321.auto-switch-node-version这个地址下载使用,或者到插件市场搜索auto-switch-node-version安装。
使用插件前需要先安装nvm,nvm安装教程可以到这里查看。
代码仓库地址:https://github.com/dbfu/auto-switch-node-version
点击关注公众号,”技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线