目前所在的前端项目已经有几年的迭代了,一些文件中既使用了传统的普通函数,又使用了箭头函数写法。这种混合写法看起来很烦,强迫症要犯了,一个一个改又太麻烦,不如就写一个 VSCode 插件:将项目中的传统函数转换为箭头函数,而普通函数和箭头函数的 this 指向不同,当函数中有用到 this 时,就跳过自己手动修改。
记录一下自己的第一个 VSCode 插件。找实习的时候又能多面一分钟了😭
准备
安装包
初始化
输入以下命令
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
{ "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),在里面输入我们插件注册命令的标题
开发
看到 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 文件
成功实现效果,有 this 的地方不转换。
安装插件
接下来就要把我们的插件倒出来安装到 VSCode 中了
安装 vsce,之前应该安装过了
npm install vsce -g
打包生成 vsix 文件:
bash复制代码vsce package
暂无评论内容