开发一个自己的 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 中使用了

效果

关机 下班 跑路

相关推荐
Kika写代码35 分钟前
【微信小程序】4|搜索框-历史搜索 | 我的咖啡店-综合实训
前端·微信小程序·小程序·notepad++
egekm_sefg2 小时前
一个基于Rust适用于 Web、桌面、移动设备等的全栈应用程序框架
开发语言·前端·rust
冴羽2 小时前
Solid.js 最新官方文档翻译(13)—— Context(上下文)
前端·javascript·react.js
ObjectX前端实验室2 小时前
交互式md文档渲染实现
前端·github·markdown
励志成为大佬的小杨3 小时前
c语言中的枚举类型
java·c语言·前端
前端熊猫4 小时前
Element Plus 日期时间选择器大于当天时间置灰
前端·javascript·vue.js
傻小胖4 小时前
React 组件通信完整指南 以及 自定义事件发布订阅系统
前端·javascript·react.js
JaxNext4 小时前
开发 AI 应用的无敌配方,半小时手搓学英语利器
前端·javascript·aigc
万亿少女的梦1684 小时前
高校网络安全存在的问题与对策研究
java·开发语言·前端·网络·数据库·python
Python私教4 小时前
Vue3中的`ref`与`reactive`:定义、区别、适用场景及总结
前端·javascript·vue.js