开发一个自己的 vscode 插件

前言

目前所在的前端项目已经有几年的迭代了,一些文件中既使用了传统的普通函数,又使用了箭头函数写法。这种混合写法看起来很烦,强迫症要犯了,一个一个改又太麻烦,不如就写一个 VSCode 插件:将项目中的传统函数转换为箭头函数,而普通函数和箭头函数的 this 指向不同,当函数中有用到 this 时,就跳过自己手动修改。

记录一下自己的第一个 VSCode 插件。找实习的时候又能多面一分钟了😭

准备

安装包

bash 复制代码
# 安装开发插件需要的包
npm install -g yo generator-code

# 安装插件发布工具
npm install -g vsce

初始化

输入以下命令

bash 复制代码
yo code

填写所开发插件的信息 等待完成我们将得到以下文件

其中里面最重要的两个文件为:

  • extension.js
  • package.json

demo

简单写个demo,主要就是修改package.json 以及extension.js这个插件入口文件

extension.js

js 复制代码
const vscode = require('vscode');

/**
 * 插件被激活时触发,所有代码总入口
 */
exports.activate = function(context) {
	console.log('测试test-demo');
	// 注册命令: 这里定义了一个名为 "test-demo.helloWorld" 的命令。当用户在 VSCode 中执行这个命令时,调用注册命令的回调函数。
	context.subscriptions.push(vscode.commands.registerCommand('test-demo.helloWorld', function () {
		vscode.window.showInformationMessage('test-demo:  helloWorld!');
	}));
};

package.js

js 复制代码
{
  "name": "test-demo",
  "displayName": "test-demo",
  "description": "将普通函数转为箭头函数",
  "version": "0.0.1",
  "engines": {
    "vscode": "^1.50.0"
  },
  "categories": [
    "Other"
  ],
  "activationEvents": [],
  "main": "./extension.js",
  "contributes": {
    // 注册一个名为 test-demo.helloWorld 的命令,命令的标题为 "test"
    "commands": [{
      "command": "test-demo.helloWorld",
      "title": "test"
    }]
  },
  "devDependencies": {
    "@types/vscode": "^1.50.0",
    "@types/mocha": "^10.0.3",
    "@types/node": "18.x",
    "eslint": "^8.52.0",
    "glob": "^10.3.10",
    "mocha": "^10.2.0",
    "typescript": "^5.2.2",
    "@vscode/test-electron": "^2.3.6"
  }
}

调试

在 VSCode 中按下 F5 会进入调试状态,这时候会自动新开一个标题为 扩展开发宿主 VSCode 界面(在这就称它为新界面),在该界面中我们可以看到刚刚写的插件的效果。

在新界面中按下 command + shift + p (windows 应该是 ctrl + shift + p),在里面输入我们插件注册命令的标题

按下回车就能看到新界面中我们注册命令的效果

在旧界面中可以看到console.log()的效果

开发

看到 demo 能够成功实现,信心大增,直接进入正题。

梳理下大致思路:

  • 获取当前活动的文本编辑器的代码,将它传递给一个函数转换,这里将函数命名为 convertToArrowFunction,然后将转换后的代码保存回文件中
  • convertToArrowFunction 函数负责将输入的 js 代码进行转换,内部我决定使用 babel 进行代码转换,传递一个自定义的 babel 插件。
  • 新建一个 convert-function-to-arrow.js 文件写入我们的自定义插件

convert-function-to-arrow.js

在 convert-functions-to-arrow.js 中我们定义了 Babel 插件的规则。这个插件的原理是使用 Babel 提供的工具遍历 AST,识别和转换函数声明和函数表达式,将它们转换为相应的箭头函数。

Babel 插件由一个导出的函数构成,该函数接受一个 babel 参数,包含 Babel 提供的相关工具。在这个函数中,它返回一个对象,包含一个名为 visitor 的属性,用于定义转换规则。visitor 对象包含两部分:FunctionDeclaration 和 FunctionExpression。它遍历 AST 中的函数声明和函数表达式。在 FunctionDeclaration 中,它首先获取函数体,然后检查函数体是否包含 this 关键字。如果函数体包含 this,则不进行转换。如果不包含,它将函数声明转换为一个常量声明,将函数体替换为箭头函数。在 FunctionExpression 中,它执行类似的操作,将函数表达式转换为箭头函数。

代码如下:

js 复制代码
module.exports = function (babel) {
  const { types: t } = babel;

  return {
    visitor: {
      FunctionDeclaration(path) {
        // 获取函数体
        const body = path.get("body");
        // 检查函数体是否包含'this'关键字
        if (checkForThis(body.node.body)) {
          return;
        }
        // 转换为箭头函数
        path.node.type = "VariableDeclaration";
        path.node.kind = "const";
        path.node.declarations = [t.variableDeclarator(path.node.id, t.arrowFunctionExpression(path.node.params, body.node))];
      },
      FunctionExpression(path) { 
        // 获取函数体
        const body = path.get("body");
        // 检查函数体是否包含'this'关键字
        if (checkForThis(body.node.body)) {
          return;
        }
        // 转换为箭头函数
        path.replaceWith(t.arrowFunctionExpression(path.node.params, body.node));
      },
    },
  };

  // 检查函数体是否包含'this'关键字
  function checkForThis(node) {
    let hasThis = false;

    function check(node) {
      if (t.isThisExpression(node)) {
        hasThis = true;
      } else {
        for (const key in node) {
          if (node.hasOwnProperty(key) && typeof node[key] === 'object' && node[key] !== null) {
            check(node[key]);
          }
        }
      }
    }

    check(node);
    return hasThis;
  }
};

extension.js

extension.js 是 VSCode 插件的入口文件,负责激活插件、注册命令和处理转换操作。当用户执行命令 "Convert Functions to Arrow Functions"(我们在package.json中自定义的命令标题) 时,它会获取当前活动的文本编辑器中的代码,将代码传递给 convertToArrowFunctions 函数进行转换,然后将更新后的代码保存回文件中。

代码如下:

js 复制代码
const vscode = require('vscode');  // 导入 VSCode 模块
const fs = require('fs');  // 导入文件系统模块
const babel = require('@babel/core');  // 导入 Babel 核心模块
const convertFunctionsToArrowPlugin = require('./convert-functions-to-arrow');  // 导入自定义的 Babel 插件

function activate(context) {
  const disposable = vscode.commands.registerCommand('extension.convertToArrowFunctions', () => {
    const editor = vscode.window.activeTextEditor;  // 获取当前活动的文本编辑器
    if (!editor) {
      vscode.window.showInformationMessage('未找到活动文本编辑器。');  // 显示信息消息
      return;
    }

    const doc = editor.document;  // 获取当前编辑器的文档
    const text = doc.getText();  // 获取文档的文本内容
    const updatedText = convertToArrowFunctions(text);  // 调用转换函数处理文本

    if (updatedText !== text) {  // 如果文本有变化
      fs.writeFileSync(doc.uri.fsPath, updatedText);  // 将更新后的文本写回文件
      vscode.window.showInformationMessage('函数已转换为箭头函数。');  // 显示成功消息
    } else {
      vscode.window.showInformationMessage('无需转换的函数。');  // 显示无需转换的消息
    }
  });

  context.subscriptions.push(disposable);  // 将命令订阅添加到上下文
}

function convertToArrowFunctions(text) {
  const babelResult = babel.transformSync(text, {
    plugins: [convertFunctionsToArrowPlugin],  // 使用自定义 Babel 插件进行转换
  });

  return babelResult.code || text;  // 返回转换后的代码,或原始代码
}

module.exports = {
  activate,
};

package.json

由于用到了 babel,需要在 package.json中加入依赖,记得 install

json 复制代码
  "dependencies": {
    "@babel/core": "^7.15.8",
    "@babel/preset-env": "^7.15.8"
  }

代码如下:

js 复制代码
{
  "name": "convert-functions-to-arrows",
  "displayName": "Convert Functions to Arrows",
  "description": "将普通函数转为箭头函数",
  "publisher": "baozj",
  "version": "1.0.0",
  "engines": {
    "vscode": "^1.60.0"
  },
  "categories": ["Other"],
  "activationEvents": ["onCommand:extension.convertToArrowFunctions"],
  "main": "./extension.js",
  "contributes": {
    "commands": [
      {
        "command": "extension.convertToArrowFunctions",
        "title": "Convert Functions to Arrow Functions"
      }
    ]
  },
  "dependencies": {
    "@babel/core": "^7.15.8",
    "@babel/preset-env": "^7.15.8"
  }
}

调试

按下 F5 进入新界面,新建一个 .js 文件 输入测试代码 按下 commadn + shift + p,输入命令 "Convert Functions to Arrow Functions",点击回车 成功实现效果,有 this 的地方不转换。

安装插件

接下来就要把我们的插件倒出来安装到 VSCode 中了

安装 vsce,之前应该安装过了

bash 复制代码
npm install vsce -g

打包生成 vsix 文件:

bash 复制代码
vsce package

安装

然后就可以在 VSCode 中使用了

效果

关机 下班 跑路

相关推荐
Csvn2 小时前
性能监控
前端
Csvn3 小时前
构建工具
前端
FRing033 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
kyriewen6 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒6 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫6 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus7 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude
孟陬8 小时前
Foobar 技术周刊#159:当看不懂代码时,如何高效排障调试。脏页陷阱:一条只读查询,写入数 TB 数据。推测解码:大模型加速利器
前端·人工智能·后端
Zhao-Jichao8 小时前
AI Prompting for Everyone 课程笔记 - P17 图像生成 Imaging Generation
前端
Highcharts.js9 小时前
智能数据分析组件Orbit 正式发布与快速上手体验教程
前端·人工智能·信息可视化·数据分析系统·highcharts·orbit·智能可视化