工欲善其事,必先利其器
vscode无疑是前端开发中十分高效的开发工具,vscode的插件在商店里也是应有尽有,大家都知道,各种各样的插件都会对我们的开发起到增效提速的辅助作用。那么我们是否能自己来开发插件应用到我们自己的vscode给我们或者团队来增加开发质感和效率呢。下文我们就将一起探索vscode插件开发思路及流程,我会在本文中开发一款插件,它支持根据框架中package.json文件中dependencies引入的node_modules进行对依赖包的索引跳转。
开发准备
npm install -g yo generator-code
首先我们通过npm安装好插件脚手架后,执行
yo code
根据配置提示来进行手动选择配置,如插件的名称,描述内容,以及是否使用ts,使用webpack,选择包管理工具,选择git仓库。
当这些我们配置好后,会生成插件开发代码目录结构,我们可以先看一下
|-- src
|-- test //插件单测文件
|-- extension.js //插件入口文件
|-- CHANGELOG.md //修改日志,发布后会展示
|-- package-lock.json
|-- package.json
|-- README.md //插件说明 README,发布后会展示
|-- tsconfig.json
|-- tslint.json
|-- vsc-extension-quickstart.md //插件开发说明
开发分析
准备完成后,为了先验证下插件代码构建正常,在VSCode中F5运行(或运行和调试选择开始)如果你可以看到VSCode又启动了一个窗口运行插件项目,通过快捷打开文件命令shift+ctrl+p输入Hello World,如果在右下角能看到Hello World的提示信息就说明我们已经成功运行了插件,只是该初始插件仅支持通过手动打开该插件名才可运行并且运行时仅是在vscode进行一个弹窗提示,不要急,我们可以通过配置,将我们开发的插件通过各种想要的途径启动并且实现我们想要的任何功能。
原窗口为我们的插件代码编辑窗口,我们可以在这里debugger断点,使用console,在运行和调试页面都可以使用,和浏览器控制台的功能是一样的,方便我们调试代码。 新窗口并且标识扩展开发宿主则为已模拟运行当前开发的插件的vscode页面,在这里可模拟使用测试我们开发的插件的功能。
开始开发
核心文件为
extension.js 是插件的入口文件
package.json包含插件的配置信息(插件命令、快捷键、菜单均在此配置)
我们一起来根据开篇提到的node_modules检索跳转插件开发来了解文件内容,配置与开发流程 首先在extension.ts中
import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
export function activate(context: vscode.ExtensionContext) {
// 注册如何实现跳转到定义,第一个参数表示仅对json文件生效
const definitionProvider = vscode.languages.registerDefinitionProvider(['json'], {
provideDefinition(document, position, token) {
// 当前文件完整路径
const filePath = document.fileName;
if (!filePath.endsWith("package.json")) return;
// 当前文件所在目录
const workDir = path.dirname(filePath);
let pkgName: any = document.getText(document.getWordRangeAtPosition(position, /[\'\"](.*?)[\'\"]/g));
pkgName = pkgName.replace(/,|\s|\'|\"/gi, '');
if (!pkgName) return
// 更改 Node.js进程到package.json文件工作目录
process.chdir(workDir);
const destPath = path.resolve('node_modules\\', pkgName);
// 判空
if (destPath && fs.existsSync(destPath)) {
// new vscode.Position(0, 0) 表示跳转到某个文件的第一行第一列
return new vscode.Location(
vscode.Uri.file(destPath),
new vscode.Position(0, 0)
);
}
}
})
const hoverProvider = vscode.languages.registerHoverProvider('json', {
provideHover: function (document, position) {
const filePath = document.fileName;
if (!filePath.endsWith("package.json"))
return;
const workDir = path.dirname(filePath);
let pkgName: any = document.getText(document.getWordRangeAtPosition(position, /[\'\"](.*?)[\'\"]/g));
pkgName = pkgName.replace(/,|\s|\'|\"/gi, '');
if (!pkgName) return
process.chdir(workDir);
let destPath = path.resolve('node_modules\\', pkgName);
destPath = destPath.replace(/\\/g,'/')
let packageContent =fs.readFileSync(`${destPath}/package.json`, 'utf-8');
let content = JSON.parse(packageContent)
return new vscode.Hover(`* **哈哈**:我是自定义弹窗\n* **名称**:${content.name}\n* **版本**:${content.version}\n* **许可协议**:${content.license}`);
}
})
context.subscriptions.push(definitionProvider, hoverProvider);
}
export function deactivate() {}
主要开发思路是通过捕捉到鼠标当前选定位置中的字符也就是对应的node_modules包名后,拼接处理好对应的依赖包路径后修改当前vscode的页面跳转到项目根目录下node_modules文件夹下对应依赖名称的文件来完成检索跳转,在对于鼠标当前位置的字符进行获取时存在难点需要大家注意,这里遇到类似“xxx-xxx-xxx”的依赖名称时,默认是拾取不到“-”字符后面的内容,不谨慎处理解决也会导致跳转出现问题。 另还有一个功能为鼠标悬浮在依赖名称时会弹出自定义弹窗显示自己关注的东西,如当前版本协议信息等等,这里也是通过vscode提供的弹窗api来实现。
接下来在package.json文件中:
{
"name": "npm-yeyuan",
"displayName": "NPM-yeyuan",
"description": "NPM-yeyuan",
"publisher": "yeyuan",
"version": "0.0.1",
"engines": {
"vscode": "^1.54.0"
},
"categories": [
"Other"
],
// 在此处配置当打开json文件时启动插件,activationEvents会有各种场景触发插件启动包括默认启动的功能,想了解的可以专门去查找下
"activationEvents": [
"onLanguage:json"
],
// 插件安装时图标配置
"icon": "logo.png",
//代码全逻辑主入口
"main": "./dist/extension.js",
"contributes": {
// 当在文件打开命令框中输入对应命令后启动对应名称插件方法,此处也有多种启动插件功能,包括键盘快捷键配置
"commands": [
{
"command": "mySearchNpm.yeyuan",
"title": "mySearchNpm.yeyuan"
}
]
},
"scripts": {
"vscode:prepublish": "yarn run package",
"compile": "webpack",
"watch": "webpack --watch",
"package": "webpack --mode production --devtool hidden-source-map",
"compile-tests": "tsc -p . --outDir out",
"watch-tests": "tsc -p . -w --outDir out",
"pretest": "yarn run compile-tests && yarn run compile && yarn run lint",
"lint": "eslint src --ext ts",
"test": "node ./out/test/runTest.js"
},
"devDependencies": {
"@types/vscode": "^1.54.0",
"@types/glob": "^8.0.1",
"@types/mocha": "^10.0.1",
"@types/node": "16.x",
"@typescript-eslint/eslint-plugin": "^5.49.0",
"@typescript-eslint/parser": "^5.49.0",
"eslint": "^8.33.0",
"glob": "^8.1.0",
"mocha": "^10.1.0",
"typescript": "^4.9.4",
"ts-loader": "^9.4.2",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1",
"@vscode/test-electron": "^2.2.2"
}
}
写在最后
vscode插件开发可以实现的功能方向非常多,比如单词翻译,中文自动转化驼峰英文命名,甚至代码模版生成,自定义转化,等等等等。这些会大大增加我们的开发效率,让我们更关注于代码开发本身,而不是频繁的为了重复低效率的琐事降低注意力与效率。