初次尝试了一下vscode插件开发,写了一个前端工具箱作为日常方便使用,记录一下
image
在vscode插件里面搜索:前端工具箱。或打开该网址安装即可 https://marketplace.visualstudio.com/items?itemName=poetries.fe-tools
搭建开发环境
我们先准备开发环境。我使用的操作系统:mac,首先确保安装了VS Code、Node.js 和 Git:
code -v
node -v
npm -v
git --version
https://code.visualstudio.com/api/get-started/your-first-extension
npm install -g yo generator-code
使用yo code指令初始化VSCode插件项目,然后需要回答一些简单的配置问题
yo code
# What type of extension do you want to create?
# 创建那一种类型的扩展?
# What's the name of your extension?
# 扩展的名称?
# What's the identifier of your extension?
# 扩展的标示?
# What's the description of your extension?
# 扩展的描述
# Initialize a git repository?
# 初始化git仓库
# Which package manager to use?
# 使用那一种包管理器
运行插件
使用 VS Code 打开项目,在编辑器内部,按F5,编译并打开一个“扩展开发宿主机”窗口运行调试插件。为了叙述方便,把新打开的窗口称为运行窗口,旧窗口称为编辑窗口。在新窗口的命令面板(
Ctrl+Shift+P) 运行 Hello World 命令。看到右下角的 Hello World 通知信息了吗?恭喜你已经运行了一个自己编写的插件!
image
调试插件
使用 VS Code 调试扩展插件很容易。这里演示一下如何设置断点。在编辑窗口打开 extension.js 文件, 点击编辑器行号左侧的边栏设置断点。在运行窗口 命令面板输入 Hello World 命令运行插件,命中断点。
image
调试webview
按F5打开调试模式,在webview页面,按
command+shift+p选择open webview
image
image
项目解析
接下来我们来深入研究一下 helloworld 插件。 helloworld 的功能很简单,就是用户可以在命令面板执行 Hello World 命令,输出 Hello World 信息
从实现的角度来看,helloworld 插件做了三件事:
- 注册激活事件
onCommand:extension.helloWorld:插件在extension.helloWorld触发时被激活。 - 注册贡献点
contributes.commands:extension.helloWorld:在命令面板中使能hello world命令,并将其绑定到extension.helloworld。 - 调用
VS Code API commands.registerCommand给注册的命令extension.helloWorld绑定处理函数。
基本概念
简单解释一下上面提到的三个概念:激活事件、贡献点和接口:
-
激活事件,译自 Activation Events,在配置清单 package.json 中静态声明,其实就是 JSON 数组
activationEvents的值。当激活事件发生时,声明的扩展将被激活。以下是目前所有可用激活事件:onLanguage、onCommand、onDebug:onDebugInitialConfigurations、onDebugResolve、workspaceContains、onFileSystem、onView、onUri、onWebviewPanel、*; -
贡献点,译自
Contribution Points,在配置清单package.json中静态声明,贡献点其实就是VS Code 的可以扩展的功能点。以下是目前所有可用的贡献点:configuration、configurationDefaults、commands、menus、keybindings、languages、debuggers、breakpoints、grammars、themes、snippets、jsonValidation、views、viewsContainers、problemMatchers、problemPatterns taskDefinitions、colors、typescriptServerPlugins、resourceLabelFormatters、contributes.configur。 - VS Code 接口:可以在扩展代码中调用的一组 JavaScript API。链接中列举了所有可用的API,熟悉基本的,其他的用到的时候按需查找就行了。
一般来说,插件都会使用到这三个概念:激活事件、贡献点和 VS Code API。接下来我们分析一下 HelloWorld 示例的源代码,看看它是如何使用这些概念的。
JavaScript 插件目录结构
image
VS Code 插件的目录结构很简单,根据命名大概就能知道作用。不同项目类型目录结构可能会有很大不同。对于 JavaScript 类型的项目来说,最重要的就是
package.json和extension.js。
清单文件:package.json
每个 VS Code 插件都必须有一个用来描述插件的清单文件 package.json。VS Code 的清单文件是声明式的 JSON 格式,用于声明插件名(name)、插件展示名(
displayName)、描述信息(description)、版本( version )、引擎( engines )、类别( categories )、依赖( devDependencies )、脚本 (scripts)、贡献点( contributes )、入口文件( main )、激活事件( activationEvents )等。
下面是 helloworld 插件的清单文件内容,为了便于理解,我加了一些注释。
{
"name": "helloworld", //插件名
"displayName": "helloworld", // 插件市场显示的插件名,支持中文
"description": "demo", // 插件市场显示的描述信息
"version": "0.0.1", // 版本号
// 最低支持的 VS Code 版本
"engines": {
"vscode": "^1.38.0"
},
// 插件市场分类
"categories": [
"Other"
],
// 激活事件
"activationEvents": [
"onCommand:extension.helloWorld"
],
"main": "./extension.js", // 指定入口文件
// 贡献点
"contributes": {
"commands": [{
"command": "extension.helloWorld",
"title": "Hello World"
}]
},
// 脚本
"scripts": {
"test": "node ./test/runTest.js"
},
// 依赖,包含版本信息
"devDependencies": {
"@types/glob": "^7.1.1",
"@types/mocha": "^5.2.6",
"@types/node": "^10.12.21",
"@types/vscode": "^1.38.0",
"eslint": "^5.13.0",
"glob": "^7.1.4",
"mocha": "^6.1.4",
"typescript": "^3.3.1",
"vscode-test": "^1.2.0"
}
}
插件入口文件:extension.js
插件的入口文件是在清单文件中指定的,如果项目比较大,源文件比较多,也可以统一放在 src 目录里。
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
/* 导入 "vscode" 模块,这个模块包含 VS Code 的扩展接口。 */
const vscode = require('vscode');
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
// 第一次执行命令时,插件会被激活;插件被激活时,这个函数会被调用
// 必须在入口中实现这个函数。
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
/* 输出诊断日志到控制台 */
console.log('Congratulations, your extension "helloworld" is now active!');
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
/*
* 这个命令 extension.helloWorld 已经在 package.json 文件中定义了。
* 现在我们使用 registerCommand 接口给这个命令绑定实现。
*/
let disposable = vscode.commands.registerCommand('extension.helloWorld', function () {
// The code you place here will be executed every time your command is executed
/* 每一次执行命令,这儿的代码都会执行 */
// Display a message box to the user
vscode.window.showInformationMessage('Hello World!');
});
context.subscriptions.push(disposable);
}
exports.activate = activate;
// this method is called when your extension is deactivated
function deactivate() {}
module.exports = {
activate,
deactivate
}
一个插件必须在其主模块实现并导出
activate()和deactivate()函数。
-
activate()函数 初始化插件。当任何指定的激活事件发生时,VS Code 会调用并且只调用它一次。 -
deactivate()函数 清理插件。如果清理过程是异步的,deactivate()函数必须返回一个 Promise 对象。如果清理运行同步,则deactivate()函数返回undefined。
Webview
插件可以分为多种,比如主题样式类型的插件,图标插件,语言支持类型的插件。Webview类型的插件只是Vscode插件的一个大类。大致的实现大家可以参考文档,文档的示例使用的是html字符串,但这不适合复杂的Webview的开发。在GameNews这个插件中,模版部分,我使用了vue以及pug。
// 静态资源的目录。绝对路径,并且使用了vscode-resource协议
// vscode-resource:/Users/Desktop/game-news/views
const webviewDir = path.join(context.extensionPath, 'views');
// 创建一个Webview的面板
const panel = vscode.window.createWebviewPanel(
viewType,
title,
vscode.ViewColumn.One,
{
enableScripts: true, // 允许运行js脚本,默认是关闭的
retainContextWhenHidden: true, // webview不可见时,脚本就会被挂起
// 指定允许加载的本地资源的根目录
localResourceRoots: [vscode.Uri.file(webviewDir)]
}
);
// 模版文件
const tpl = path.join(webviewDir, 'index.pug');
// 通过pug渲染模版文件,到webview上
panel.webview.html = pug.renderFile(tpl, options);
本地资源的使用
Webview中,我们会需要使用本地的css,js文件。虽然可以使用行间js或者行间样式,但是总归不太好。使用本地文件,就会涉及的静态文件路径的问题,在VScode中,我们需要使用绝对路径。并且是vscode-resource协议的路径。
const webviewDir = path.join(context.extensionPath, 'views');
// 静态资源的绝对目录
let URI = vscode.Uri.file(path.join(webviewDir, 'js', 'vue.js'))
// 使用vscode-resource协议头
// 然后这个URL就可以使用在我们的webview的模版中了
URI = URI.with({ scheme: 'vscode-resource' });
Webview与插件通信
Webview相当于一个网页,而网页是无法调用一些本地功能的。但是插件本身是运行在node环境的,而已我们可以通过插件实现一些在网页中无法完成的功能。Webview如果通知插件呢?这涉及到了Webview于网页的通信机制。
下面是GameNews插件的例子,我通过事件将游戏新闻的url,发送给插件。插件会调用系统的命令,使用本地的浏览器打开url。
// webview
// webview中,一个内置的全局api
const vscode = acquireVsCodeApi()
vscode.postMessage({
command: 'preview',
text: url
})
// 插件
panel.webview.onDidReceiveMessage(message => {
switch (message.command) {
case 'preview':
// 打开浏览器
open(message.text);
return;
}
}, undefined, context.subscriptions);
更多参考文档:https://code.visualstudio.com/api/extension-guides/webview
打包、发布和升级
如何让别人也能使用自己开发的插件呢?这和移动应用开发一样,有两种方式:
- 把它发布到 VS Code 插件市场,这样其他人就可以找到、下载和使用你的插件。
- 或者,可以将插件打包为可安装的
vsix格式,并与其他用户共享。
vsce,简写自 Visual Studio Code Extensions, 是用于打包、发布和管理 VS Code 插件的命令行工具
先安装 Node.js ,然后运行 npm install -g vsce 安装 vsce。在插件的根目录下运行 vsce package 打包插件,运行 vsce publish 发布插件。
npm install -g vsce
vsce create-publisher poetry # 这一步先创建一个发布账号,需要用到token,看下面步骤获取token
vsce package #打包插件 .vsix 格式
vsce publish #发布到 MarketPlace
发布插件到 VS Code 插件市场,需要注册开发者账号。有关如何发布插件的内容很简单,可以参考官方文档这一部分的内容:https://code.visualstudio.com/api/working-with-extensions/publishing-extension
-
在Visual Studio Team Services 创建一个账号
-
根据账号的名字访问主页,例如我的名字是bingou-ms,主页链接就是
-
创建Personal Access Token
image
image
需要将Accounts设置为All accessible accounts
image
那么如何升级已经发布到插件市场的插件呢?修改/增加版本号,然后再执行
vsce publish即可。
安装vsix文件
可以直接安装vsce package的vsix文件,方便在本地进行调试。
code --install-extension vsix文件名










网友评论