手把手带你开发一个自己的 vscode 插件

作者描述了如何开发一个VSCode插件,用于检测并自动将项目中的传统函数转换为箭头函数,同时保留不含`this`的函数。使用Babel插件处理代码转换,并演示了从创建插件到调试和发布的整个过程。
摘要由CSDN通过智能技术生成

作者:baozj

https://juejin.cn/post/7298285602041151498

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

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

准备

安装包

# 安装开发插件需要的包
npm install -g yo generator-code

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

初始化

输入以下命令

yo code

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

6348cdef35ebdae95e3c67f06e519063.jpeg其中里面最重要的两个文件为:

  • 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
{
  "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 界面(在这就称它为新界面),在该界面中我们可以看到刚刚写的插件的效果。

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

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

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

e19c21aaef3cf96047b6404faaee9e39.jpeg
image.png

开发

看到 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 中,它执行类似的操作,将函数表达式转换为箭头函数。

代码如下:

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 函数进行转换,然后将更新后的代码保存回文件中。

代码如下:

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

"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 文件d9f6e394127b86ab8779efa488caa6c5.jpeg输入测试代码190121ce205a3d0f53a2ca5888c2d132.jpeg按下 commadn + shift + p,输入命令 "Convert Functions to Arrow Functions",点击回车a929e74bb9a594b875e5da9c98afd93e.jpeg成功实现效果,有 this 的地方不转换。55d3b5347ac9ef5a5047d0de895c6296.jpeg

安装插件

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

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

npm install vsce -g

打包生成 vsix 文件:

bash
复制代码
vsce package

10165ad7bceeda45c3e48bf773083417.jpeg安装

103671ca70b262575c39aebdb36a1e87.jpeg
image.png

bb177961660717802daaa22a45de7765.jpeg然后就可以在 VSCode 中使用了

效果

f98dfc8baeb99f393be1c06b1812aa8a.png
 
 
 
 
 
 
 
 
 
 
 
 
 
 

<END>

点这里👇关注我,记得标星呀~

往期精选:

推荐这个牛逼神器 !

GPT国内直接使用,低调使用 !

GPT中文网站

f53629c1512c80eb691fa7a08754ab58.gif

国内同ChatGPT直接进行对话,支持GPT4.0 和 AI绘图

https://aigc.cxyquan.com

2c11f19f3ec70da2d2a8539df315e29e.png

感谢你的分享,点赞,在看三  7bb735b7e6b7401d8fcff4f485da32f0.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值