简介
关于vscode
VSCode是微软出的一款轻量级代码编辑器,免费而且功能强大,以功能强大、提示友好、不错的性能和颜值俘获了大量开发者的青睐,对JavaScript和NodeJS的支持非常好,自带很多功能,例如代码格式化,代码智能提示补全等。再强大的IDE也不会面面俱到,这样只会让IDE太臃肿,vscode的很多强大功能都是基于插件实现的,IDE只提供一个最基本的框子和最基本功能,由插件来丰富和扩展它的功能。
什么是vscode插件
因为vscode本身都是用浏览器实现的,所以其插件不用说肯定也是基于HTML+JS等前端技术实现,从形式上看就是一个类似于npm包的vsix文件,只不过按照一些特殊规范来实现一些特殊功能。
如何开发一个vscode插件
1.安装官方脚手架
npm install -g yo generator-code
选择配置
生成文件目录为
其中extension.js是项目的主入口
package.json里面配置项目的命令
2.package.json解释以及执行HelloWorld
我们先看一个例子
{
"name": "wx-command",
"displayName": "wx-command",
"description": "微信小程序文件助手",
"version": "0.0.2",
"engines": {
"vscode": "^1.36.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:extension.wxPage",
"onCommand:extension.wxComponents"
],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "extension.wxPage",
"title": "wx page"
},
{
"command": "extension.wxComponents",
"title": "wx components"
}
],
"menus": {
"explorer/context": [
{
"command": "extension.wxPage"
},
{
"command": "extension.wxComponents"
}
]
},
"snippets": [
{
"language": "vue",
"path": "./snippets/ts.json"
}
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"pretest": "npm run compile",
"test": "node ./out/test/runTest.js"
},
"devDependencies": {
"@types/glob": "^7.1.1",
"@types/mocha": "^5.2.6",
"@types/node": "^10.12.21",
"@types/vscode": "^1.36.0",
"glob": "^7.1.4",
"mocha": "^6.1.4",
"tslint": "^5.19.0",
"typescript": "^3.3.1",
"vscode-test": "^1.0.2"
}
}
看起来和我们平时的项目没有什么区别,但是多了一个contributes的配置,这个也是我们所有命令的配置入口
结合实现一个helloword来加深下认识
首先在package.json里的contributes进行配置
{
// 扩展的激活事件
"activationEvents": [
"onCommand:extension.sayHello"
],
// 入口文件
"main": "./src/extension",
// 贡献点,vscode插件大部分功能配置都在这里
"contributes": {
"commands": [
{
"command": "extension.sayHello",
"title": "Hello vscode"
}
]
}
}
在activationEvents配置我们要激活的事件,(可以直接配置为*激活所有命令)然后contributes-->commands里面自定义命令,sayHello,命令 然后在extensions里实现具体功能
const vscode = require('vscode');
/**
* 插件被激活时触发,所有代码总入口
* @param {*} context 插件上下文
*/
exports.activate = function(context) {
console.log('恭喜,您的扩展“vscode-plugin-demo”已被激活!');
// 注册命令
context.subscriptions.push(vscode.commands.registerCommand('extension.sayHello', function () {
vscode.window.showInformationMessage('Hello vscode 弹窗!');
}));
};
/**
* 插件被释放时触发
*/
exports.deactivate = function() {
console.log('您的扩展“vscode-plugin-demo”已被释放!')
};
其中activate和deactivate 是插件的两个生命周期名,分别在插件插入和释放时候执行
vscode.commands.registerCommand是注册命令的API,执行后会返回一个Disposable对象,所有注册类的API执行后都需要将返回结果放到context.subscriptions中去。
vscode.window.showInformationMessage是插件的弹窗方法
最终实现效果 调试后,command+shift+p打开vscode命令执行 输入自定义命令Hello vscode-可见执行弹窗
3. 模版文件的自动生成
预期效果,模仿微信开发者工具右键菜单生成文件,并自动填充模版
先看package.json里面的配置
"activationEvents": [
"onCommand:extension.wxPage",
"onCommand:extension.wxComponents"
],
"contributes": {
"commands": [
{
"command": "extension.wxPage",
"title": "wx page"
},
{
"command": "extension.wxComponents",
"title": "wx components"
}
],
"menus": {
"explorer/context": [
{
"command": "extension.wxPage"
},
{
"command": "extension.wxComponents"
}
]
},
和刚才一样在contributes里的commands里面进行我们的命令配置
然后在menus配置菜单执行
几个api
-
explorer/context 是key值,定义这个菜单出现在哪里;
- 资源管理器上下文菜单 - explorer/context
- 编辑器上下文菜单 - editor/context
- 编辑标题菜单栏 - editor/title
- 编辑器标题上下文菜单 - editor/title/context
-
when控制菜单合适出现;
-
command定义菜单被点击后要执行什么操作;
大致思路就是根据不同的命令,writeFileSync生成文件并写入提前设置的模版
然后看下具体实现
const vscode = require("vscode");
const fs = require("fs");
const path = require("path");
const files_1 = require("./files");
const { page, components } = files_1.files("index");
const fileTypes = ["js", "wxss", "wxml", "json"];
function wxCommandHander(type, e) {
const stat = fs.statSync(e.fsPath);
const dir = path.normalize(e.fsPath);
if (stat.isDirectory()) {
try {
fileTypes.map((i) => __awaiter(this, void 0, void 0, function* () {
const data = new Uint8Array(Buffer.from(type === "page" ? page[i] : components[i]));
fs.writeFileSync(`${dir}/index.${i}`, data);
}));
vscode.window.showInformationMessage(`create ${type} success!`);
}
catch (error) {
vscode.window.showErrorMessage("create page files failed");
}
}
else {
vscode.window.showErrorMessage("please choose a folder");
}
}
function activate(context) {
console.log('Congratulations, your extension "wx" is now active!');
let disposable = vscode.commands.registerCommand("extension.wxPage", (e) => __awaiter(this, void 0, void 0, function* () {
wxCommandHander("page", e);
}));
context.subscriptions.push(disposable);
disposable = vscode.commands.registerCommand("extension.wxComponents", (e) => {
wxCommandHander("components", e);
});
context.subscriptions.push(disposable);
}
exports.activate = activate;
function deactivate() { }
exports.deactivate = deactivate;
file.js里面就是配置的填充模版
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
*
* @param name file name
*/ exports.files = function (name) {
const page = {
js: `
/**
* ${name}.js
*/
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})`,
wxss: `/**${name}.wxss**/`,
json: `
/**
* ${name}.json
* */
{
"usingComponents": {}
}`,
wxml: `<!--${name}.wxml-->
<text>${name}</text>`
};
return {
page,
components
};
};
//# sourceMappingURL=files.js.map
执行效果,调试后,在一个文件夹目录下右键执行
4.自动补全
const vscode = require('vscode');
const util = require('./util');
const snippetsList = require('./utilList.js')
/**
* 自动提示实现,这里模拟一个很简单的操作
* 当输入 this.dependencies.xxx时自动把package.json中的依赖带出来
* 当然这个例子没啥实际意义,仅仅是为了演示如何实现功能
* @param {*} document
* @param {*} position
* @param {*} token
* @param {*} context
*/
function provideCompletionItems(document, position, token, context) {
const line = document.lineAt(position);
const projectPath = util.getProjectPath(document);
const localDependencies = snippetsList.util
// 只截取到光标位置为止,防止一些特殊情况
const lineText = line.text.substring(0, position.character);
// 简单匹配,只要当前光标前的字符串为`this.dependencies.`都自动带出所有的依赖
if (/util\.$/g.test(lineText)) {
let atest = ['test']
return localDependencies.map(dep => {
return new vscode.CompletionItem(dep.name, vscode.CompletionItemKind.Field);
})
}
}
/**
* 光标选中当前自动补全item时触发动作,一般情况下无需处理
* @param {*} item
* @param {*} token
*/
function resolveCompletionItem(item, token) {
return null;
}
module.exports = function (context) {
// 注册代码建议提示,只有当按下“.”时才触发
context.subscriptions.push(vscode.languages.registerCompletionItemProvider('javascript', {
provideCompletionItems,
resolveCompletionItem
}, '.'));
};
其中vscode.languages.registerCompletionItemProvider为新的api,接受三个参数
- 执行的文件类型
- 提供提示的函数
- 触发词
5.代码提示
代码提示其实是利用代码更改vscode的自定义代码片段 使用方式 新建一个vue.json文件
{
"console.打印": {
"prefix": "colo",
"body": [
"console.log($0)"
],
"description": "console打印"
},
"console.打印2": {
"prefix": "ajax",
"body": [
"$.ajax({",
" url: '$1',",
" method: '${2:POST}',",
" datatype: 'json',",
" success: data => {",
" $3;",
" },",
" error: err => {",
" $4;",
" }",
"})"
],
"description": "ajax模块"
},
"大区": {
"prefix": "adress-s",
"body": [
"<el-form-item label='所属大区' :prop='$1'>",
" <el-select v-model='$2' clearable placeholder='请选择所属大区'>",
" <el-option label='东北大区 :value='$3' />",
" <el-option label='华北大区 :value='$4' />",
" </el-select>",
"</el-form-item>"
],
"description": "大区"
}
}
其中prefix为触发词 body为生成体
"contributes": {
"snippets": [
{
"language": "vue",
"path": "./snippets/vue.json"
}
],
},
插件开发完成后的工作
插件开发完成后需要进行打包以及共享
开发完成后,我们有三种方式进行使用
方法一:直接把文件夹发给别人,让别人找到vscode的插件存放目录并放进去,然后重启vscode,一般不推荐;
方法二:打包成vsix插件,然后发送给别人安装,如果你的插件涉及机密不方便发布到应用市场,可以尝试采用这种方式;
方法三:注册开发者账号,发布到官网应用市场,这个发布和npm一样是不需要审核的。
介绍下第二种,本地打包成vsix包,别人使用的时候直接发给他们。然后接收的人在插件里面安装
安装方法
打包时候需要安装打包插件
npm i vsce -g
打包命令
vsce package
打包的时候可能提醒我们,没有定义开发者,这时候就需要用到我们之前说的packagejson 里面的publisher配置,这个是需要注册的。下面说下注册流程
注册逻辑
要发布到应用市场首先得有应用市场的publisher账号;
而要有发布账号首先得有Azure DevOps组织;
而创建组织之前,首先得创建Azure账号;
创建Azure账号首先得有Microsoft账号;
是不是有点晕,梳理一下:
一个Microsoft账号可以创建多个Azure组织;
一个组织可以创建多个publisher账号;
同时一个组织可以创建多个PAT(Personal Access Token,个人访问令牌);
第一个网址 login.live.com/,注册Microsof…
第二个网址 aka.ms/SignupAzure… ,如注册Azure,注册这个提示输入刚才我们注册的Microsoft账号,按步骤注册
注册成功后生成个人钥匙
注意以下,一定要选择full access,名字时间自己定义
生成token后,注意保存,这个你一旦退出,网站也不会保存,
现在我们有了账号,也有了token 在我们的项目目录下
vsce create-publisher 你的名字(随便)
最后写入你的token
可以通过vsce ls-publishers 查看已经添加的发布者
然后在项目的packagejson里面添加publisher写发布者
再执行
vsce package
在项目目录下就可以生成后缀名为vsix的插件了。