最近我们的技术项目需要做一个vscode extension,功能非常典型,增加snippets,并且鼠标滑动到相应的属性上悬浮出一个链接,方便跳转查看信息,最后将这个extension发布到了vscode Marketplace,这里记录一下是怎么做的~
创建Extension
首先,我们先用脚手架生成一个extension项目,遵从vscode官方来进行创建
这里有一些选项供大家选择,整体还是很简单的
使用yo创建的插件项目自带一个command命令,打开项目install依赖后,我们按下F5走插件的调试任务,其实跑的是.vscode中的launch.json,这里可以这一个job跑了preLaunchTask,输出在outFiles里
在tasks.json中能看到有watch这个task,kind是build并且有isDefault,所以在调试时,会跑起watch来输出dist代码供给新窗口的vscode
增加Snippets
snippets是便利的代码段,比如我们可以打clg轻松得就出一个console.log
我们假设这里要实现一个输入weather输出一个weather组件,并且鼠标悬浮到组件上出一个链接,让用户可以看到更详尽的天气信息
首先我们在根目录下创建一个snippets的文件夹,在其中增加一个weather.json,在package.json中增加对应的snippet路径
// snippets/weather.json
{
"weather snippets": {
// 匹配输入的关键字
"prefix": "weather",
// 具体生成什么代码
"body": [
"<weather",
"country='$0'",
"city='$1'",
],
"description": ""
}
}
// package.json
{
"contributes": {
"snippets": [
{
"language": "javascript",
"path": "./snippets/weather.json"
}
]
}
}
现在调试extension,你就可以看到你新生成的snippet了!
碎碎念:
- snippets中无法对输入的关键字也就是prefix做正则match,如果你有超多种,只能使用数组列举
- snippets中没有提供变量来告诉开发者,用户实际选择了哪一个对应的snippet,对应第一个问题。比如我的prefix为
["good_weather", "bad_weather"],我无法知道用户实际选择了哪一个snippet,这样就导致我在实际需求中无法生成对应的代码
因为第二个问题对我来说是致命的,于是我选择了一种不太优雅但是能解决问题的方式,根据模板和需要生成的组合,生成snippets并在package.json中自动插入对应的路径
let fs = require("fs");
let path = require("path");
// 一个返回模板的函数
const generate = require("./generate-template");
// 生成哪些数据
const CONFIG = require("./generate-data-config");
var cbDataPackage = require("../../package.json");
let preUrl = "./snippets/generate/";
function writeAFile(data, fileName) {
let str = `export default ${JSON.stringify(generate(data), null, "\t")}`;
let _path = preUrl + fileName;
return new Promise((resolve) => {
fs.mkdir(path.resolve(preUrl), { recursive: true }, (err) => {
if (err) {
resolve(err);
} else {
fs.writeFile(_path, str, function (err) {
if (err) {
console.error("写入文件失败:", err);
}
resolve(err);
});
}
});
});
}
// 生成snippets
CONFIG.forEach((item) => {
writeAFile(item, `${item}.js`);
});
function writePackageJson() {
cbDataPackage.contributes.snippets = CONFIG.map((d) => ({
language: "javascript",
path: `${preUrl}${d}.js`,
})
fs.writeFile("./package.json", JSON.stringify(cbDataPackage), function (err) {
console.error(err);
});
}
// package.json注入
writePackageJson();
增加悬浮命令
可以看到把鼠标移动到Promise上后,可以看到一个悬浮框,这个效果是怎么实现的呢?
我们来根据代码进行分析
// extension.ts
function provideHover(
document: vscode.TextDocument,
position: vscode.Position,
_token: vscode.CancellationToken
) {
// 当前鼠标悬浮的行
const line = document.lineAt(position.line).range;
// 拿到当行所有文本
const word = document.getText(line);
// 如果当行中有weather,显示hover
if (/weather/.test(word)) {
return new vscode.Hover(
// 如果要写markdown的话,记得包在MarkdownString中
new vscode.MarkdownString(
`更多天气信息请查看\ ${WEATHER_LINK}}`
)
);
}
}
export function activate(context: vscode.ExtensionContext) {
// 增加subscription
context.subscriptions.push(
vscode.languages.registerHoverProvider("javascript", {
provideHover,
})
);
}
增加hover的代码完工了~但是打开调试窗口却没有生效,这是因为activate是有对应的生命周期来去进行触发的,钩子是定义在package.json里,根据查看vscode所有的钩子,我们可以确定要的生命周期为onStartupFinished
"activationEvents": [
"onStartupFinished"
]
现在再进行调试,我们就可以看到出现的悬浮框了!
发布
功能都实现了,可以发布了!现在vscode 发布已经非常简单了,一些教程中使用的Azure生成key已经没有必要了
首先我们需要install vsce
npm install -g vsce
cd # 你的代码路径
vsce package
如果这个时候报了Make sure to edit the README.md file before you publish your extension的错,记得把README中This is the README of your extension这一行删掉
这样子,我们就打出了.vsix文件
在生成.vsix后,我们可以先在本地测试一下,节省打包后有错误的时间成本,双击就可以安装,安装后vscode右下角会提示reload,reload后就可以体验我们的extension了
测试完毕后,我们准备一个microsoft的账号到进入Marketplace aka.ms/vscode-crea…
选择New extension > Visual Studio Code,把.vsix扔进去(这个上传接口经常崩,不知道是不是我网络的问题
这边需要注意的是,你打包的代码中package.json的publisher得和你Marketplace中的extension name一致
在上传成功后,需要等待3-5分钟,就可以在Marketplace中看到你的应用啦
tips
不要将snippets之类的资源放在src中,放在根目录的snippets文件夹里
虽然乍一看放在src中,再由package.json指过去,调试环境是可以调出snippet的
但是打包后,由于src文件夹在vsix包中是不存在的,所以就自然而然的跪了。。
并且在开发时,找到了一个挺不错的入门教程,提供给大家~ github.com/sxei/vscode…