💯What?维护新老项目频繁切换node版本太恼火?开发一个vscode插件自动切换版本,从此告别烦恼

前言

哈喽大家好!我是嘟老板 ,由于手上负责好几个项目,新老不一,基本上每次开发前都要切换 node 版本,以保证项目正常启动,但凡一不留神忘记了,就会白白浪费几分钟时间,本来是坐等服务启动,结果迎来了一大堆报错。为了彻底解决这类问题,我特地开发了一个 vscode 插件 - auto-nvm,再也不用担心忘记切换了,真香。

阅读本文您将收获:

  1. auto-nvm 设计背景、思路及实现过程。
  2. auto-nvm 插件完整开发过程。
  3. 等等...

why auto-nvm

背景

其实标题已经说的很清楚了,目前负责了太多的前端项目,有老有新,每次交替开发时,都要先切换 node 版本,不然就分分钟报错给你看。

现在"年纪大了",不想频繁的手动切换版本,更不想经过漫长的等待,因 node 版本导致服务启动失败,就想着能不能每次打开项目自动切换 node 版本。

由于一直以来都在用 nvm 管理 node 环境,所以就从 nvm 入手,借助 nvm 的能力实现自动切换。

规划

目前没打算做的太复杂,大致规划以下两点:

  1. (核心)打开前端项目自动切换 node 版本
  2. 提供 Use Node Version 命令,支持手动切换 node 版本。

截至发文,auto-nvm 已迭代几个版本,功能更完善,欢迎使用。

开发流程

初始化项目

使用 Yeomanvscode 插件生成器 工具初始化插件工程。

终端输入以下命令,回车执行:

bash 复制代码
npm install --global yo generator-code
yo code

问答环节结束后即可完成创建。

初始工程目录结构如下。

清除 src/extension.ts 中无用代码及注释,精简如下:

javascript 复制代码
import * as vscode from "vscode";

export function activate(context: vscode.ExtensionContext) {
  console.log('auto-nvm is now active');
}

export function deactivate() {}

(核心)自动切换 node 版本

设计思路

  1. 若想实现自动切换,首先要明确每个项目所需的 node 版本,那怎么才能知道需要哪个版本呢?答案是配置文件 ,恰好 nvm 支持 .nvmrc,帮我们省去了读取配置的过程。
  2. .nvmrc 中配置 node 版本,如 v18.12.0,执行 nvm use 命令后,会切换版本至 v18.12.0
  3. auto-nvm 插件激活后,自动在每个打开的终端执行 nvm use 命令,即可切换。

上代码

executeNvmUse 工具函数

创建一个 executeNvmUse 工具函数,用来在 vscode 终端执行 nvm use 命令。

js 复制代码
/**
 * 终端 t 发送 nvm use
 */
function sendNvmUserText(t: vscode.Terminal) {
  t.sendText("nvm use");
}

/**
 * 为 vscode 每个打开的终端执行 "nvm use",切换 node 版本
 */
export function executeNvmUse() {
  // 获取打开的终端列表
  const terminals = vscode.window.terminals;
  if (terminals.length) {
    terminals.forEach(sendNvmUserText);
  }
  // 监听终端创建事件,创建终端后首先切换 node 版本
  vscode.window.onDidOpenTerminal(sendNvmUserText);
}
调用 executeNvmUse

src/extension.ts 中引入 executeNvmUse 函数,并在 activate 函数内调用,表示插件激活后执行 nvm use

js 复制代码
import * as vscode from "vscode";
import { executeNvmUse } from "./utils";

export function activate(context: vscode.ExtensionContext) {
  console.log('extension "auto-nvm" is now active!');
  executeNvmUse();
}
操作演示

到这基本的自动切换功能就完活了,快捷键 F5 测试一下。

在新窗口中打开一个测试项目,新增 .nvmrc 配置文件并写入 v18

新建终端,发现自动执行了 nvm use 命令,并且切换了 node 版本。

OK,符合预期。

Use Node Version 命令

提供一个 Use Node Version 命令,允许手动切换 node 版本。

设计思路

若用户本地环境没有安装 .nvmrc 配置的 node 版本,则自动切换会失败,这就需要用户手动操作切换。

  1. crtl+shift+p(window)cmd+shift+p(mac) 搜索 Use Node Version 命令回车执行
  2. 弹出输入框允许用户输入版本号。
  3. 回车确认并切换,终端自动执行 nvm use [version]

截至发文,Use Node Version 功能已更新,会自动获取用户本地已安装的 node 版本,供选择,无需手动输入;且提供安装其他版本入口,供用户按需安装。

操作流程如下:

上代码

src 目录下新增 register-command 文件,专门用于维护命令注册函数。

创建 registerUseVersionCommand 函数,编写注册 use-version 命令的代码。

js 复制代码
import * as vscode from "vscode";
import { executeNvmUse } from "./utils";

// 匹配 nvm use 可用的 node 版本写法
const nvmNodeVersionRegexp = /^(v)?(0|[1-9]\d{0,1})(\.(0|[1-9]\d*)){0,2}$/;
/**
 * 注册 use-version 命令
 */
export function registerUseVersionCommand(context: vscode.ExtensionContext) {
  const commandId = "auto-nvm.use-version";
  const commandHandler = () => {
    // 显示输入框
    vscode.window
      .showInputBox({
        prompt: "enter the node version", // 输入框的提示信息
        placeHolder: "eg. 20, v20, 20.11.0, v20.11.0", // 输入框的占位符
        validateInput: (version) => {
          // 验证输入的函数
          if (!nvmNodeVersionRegexp.test(version)) {
            return "invalid version";
          }
          return null;
        },
      })
      .then((version) => {
        if (version) {
          executeNvmUse(version);
          vscode.window.showInformationMessage(
            `"nvm use ${version}" command has been sent, please check terminals`
          );
        }
      });
  };
  context.subscriptions.push(
    vscode.commands.registerCommand(commandId, commandHandler)
  );
}

注册命令的核心是 vscode.commands.registerCommand(commandId, commandHandler) 这行代码,表示注册一个 IDauto-nvm.use-version ,处理函数为 commandHandler 的命令。

commandHandler 定义了 use-version 的具体行为,当 crtl+shift+p(window)cmd+shift+p(mac) 执行 Use Node Version 命令时,会调用 showInputBox api 弹出一个输入框,供用户输入要切换的 node 版本号,如 20、v20 等;输入过程中,会执行 validateInput 配置的校验函数,以保障用户输入的准确性;用户回车确认后,会调用 executeNvmUse 函数,以在控制台执行 nvm use ${version} 命令,切换 node 版本;最后右下角弹窗提示。

跟着操作的小伙伴可能会发现,咦?executeNvmUse 函数怎么可以传参数了,哈哈,当然是调整过啦,以下是调整后的相关代码:

js 复制代码
/**
 * 终端 t 发送 nvm use
 */
function sendNvmUseText(t: vscode.Terminal, version: string | null = "") {
  t.sendText(`nvm use ${version}`);
}

/**
 * 为 vscode 每个打开的终端执行 "nvm use",切换 node 版本
 */
export function executeNvmUse(version?: string) {
  // 获取打开的终端列表
  const terminals = vscode.window.terminals;
  if (terminals.length) {
    terminals.forEach((t) => sendNvmUseText(t, version));
  }
}

/**
 * 插件 active 时初始执行
 */
export function initNvmUse(context: vscode.ExtensionContext) {
  // 为 vscode 每个打开的终端执行 "nvm use"
  executeNvmUse();
  // 监听终端创建事件,创建终端后首先切换 node 版本
  context.subscriptions.push(vscode.window.onDidOpenTerminal(sendNvmUseText));
}

executeNvmUse 函数改为纯粹的在终端中执行 nvm use,接受 version 参数,用于指定 use 的 node 版本。

新增一个 initNvmUse 函数,用于在 extension.ts 中的 activate 函数内调用。

activate 函数调整如下:

js 复制代码
import * as vscode from "vscode";
import { initNvmUse } from "./utils";
import { registerUseVersionCommand } from "./register-commands";

export function activate(context: vscode.ExtensionContext) {
  console.log("auto-nvm is now active!");
  initNvmUse(context);
  registerUseVersionCommand(context);
}

最后一步,在 package.json 中配置 contributes.commands,以使 Use Node Version 命令在 vscode 的命令面板中可用:

json 复制代码
{
    "contributes": {
        "commands": [
              {
                "command": "auto-nvm.use-version",
                "title": "Use Node Version",
                "description": "use specified version"
              }
        ]
   },
}
操作演示

代码到此告一段落,来看下演示效果:

小优化

现在插件仅会在执行 Use Node Version 命令时激活插件,而 vscode 编辑器打开后通常会有未关闭的终端窗口,这就导致执行 Use Node Version 前,原有的终端窗口不会切换 node 版本。

解决方法也比较简单,在 package.json 中配置 activationEvents 即可,默认为空数组,即执行命令时激活。

若想任意条件都激活插件,可以配置一个包含 星号(*) 的数组。

json 复制代码
"activationEvents": ["*"],

不过通常不建议这么配置,会影响 vscode 性能,需要限制一下,比如 auto-nvm 配置如下,在 vscode 启动完成后激活。

json 复制代码
"activationEvents": [ "onStartupFinished", "workspaceContains:.nvmrc" ],

完活!!!

结语

本文重点介绍了 auto-nvm 整个设计及大致开发过程,旨在帮助同学们加深对于 auto-nvm 特性的理解。如有需要,欢迎安装,反馈,万分感谢!

如您对文章内容有任何疑问或想深入讨论,欢迎评论区留下您的问题和见解。

技术简而不凡,创新生生不息。我是 嘟老板,咱们下期再会。


往期干货

相关推荐
沉默璇年35 分钟前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder41 分钟前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_882727571 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
SoaringHeart1 小时前
Flutter进阶:基于 MLKit 的 OCR 文字识别
前端·flutter
会发光的猪。1 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js
天下代码客2 小时前
【vue】vue中.sync修饰符如何使用--详细代码对比
前端·javascript·vue.js
猫爪笔记2 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
Yang.992 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
前端李易安2 小时前
Webpack 热更新(HMR)详解:原理与实现
前端·webpack·node.js
红绿鲤鱼2 小时前
React-自定义Hook与逻辑共享
前端·react.js·前端框架