初次嘗試了一下vscode插件開發(fā),寫了一個(gè)前端工具箱作為日常方便使用,記錄一下
在vscode插件里面搜索:前端工具箱定拟∮谖ⅲ或打開該網(wǎng)址安裝即可 https://marketplace.visualstudio.com/items?itemName=poetries.fe-tools
搭建開發(fā)環(huán)境
我們先準(zhǔn)備開發(fā)環(huán)境。我使用的操作系統(tǒng):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插件項(xiàng)目,然后需要回答一些簡單的配置問題
yo code
# What type of extension do you want to create?
# 創(chuàng)建那一種類型的擴(kuò)展延窜?
# What's the name of your extension?
# 擴(kuò)展的名稱恋腕?
# What's the identifier of your extension?
# 擴(kuò)展的標(biāo)示?
# What's the description of your extension?
# 擴(kuò)展的描述
# Initialize a git repository?
# 初始化git倉庫
# Which package manager to use?
# 使用那一種包管理器
運(yùn)行插件
使用 VS Code 打開項(xiàng)目逆瑞,在編輯器內(nèi)部荠藤,按F5,編譯并打開一個(gè)“擴(kuò)展開發(fā)宿主機(jī)”窗口運(yùn)行調(diào)試插件获高。為了敘述方便哈肖,把新打開的窗口稱為運(yùn)行窗口,舊窗口稱為編輯窗口念秧。在新窗口的命令面板(
Ctrl+Shift+P
) 運(yùn)行 Hello World 命令淤井。看到右下角的 Hello World 通知信息了嗎摊趾?恭喜你已經(jīng)運(yùn)行了一個(gè)自己編寫的插件币狠!
調(diào)試插件
使用 VS Code 調(diào)試擴(kuò)展插件很容易。這里演示一下如何設(shè)置斷點(diǎn)砾层。在編輯窗口打開 extension.js 文件漩绵, 點(diǎn)擊編輯器行號(hào)左側(cè)的邊欄設(shè)置斷點(diǎn)。在運(yùn)行窗口 命令面板輸入 Hello World 命令運(yùn)行插件肛炮,命中斷點(diǎn)止吐。
調(diào)試webview
按F5打開調(diào)試模式,在webview頁面铸董,按
command+shift+p
選擇open webview
項(xiàng)目解析
接下來我們來深入研究一下 helloworld 插件祟印。 helloworld 的功能很簡單,就是用戶可以在命令面板執(zhí)行 Hello World 命令粟害,輸出 Hello World 信息
從實(shí)現(xiàn)的角度來看蕴忆,helloworld 插件做了三件事:
- 注冊激活事件
onCommand:extension.helloWorld
:插件在extension.helloWorld
觸發(fā)時(shí)被激活。 - 注冊貢獻(xiàn)點(diǎn)
contributes.commands:extension.helloWorld
:在命令面板中使能hello world
命令悲幅,并將其綁定到extension.helloworld
套鹅。 - 調(diào)用
VS Code API commands.registerCommand
給注冊的命令extension.helloWorld
綁定處理函數(shù)站蝠。
基本概念
簡單解釋一下上面提到的三個(gè)概念:激活事件、貢獻(xiàn)點(diǎn)和接口:
-
激活事件卓鹿,譯自 Activation Events菱魔,在配置清單 package.json 中靜態(tài)聲明,其實(shí)就是 JSON 數(shù)組
activationEvents
的值吟孙。當(dāng)激活事件發(fā)生時(shí)澜倦,聲明的擴(kuò)展將被激活。以下是目前所有可用激活事件:onLanguage
杰妓、onCommand
藻治、onDebug:onDebugInitialConfigurations
、onDebugResolve
巷挥、workspaceContains
桩卵、onFileSystem
、onView
倍宾、onUri
雏节、onWebviewPanel
、*高职; -
貢獻(xiàn)點(diǎn)钩乍,譯自
Contribution Points
,在配置清單package.json
中靜態(tài)聲明初厚,貢獻(xiàn)點(diǎn)其實(shí)就是VS Code 的可以擴(kuò)展的功能點(diǎn)件蚕。以下是目前所有可用的貢獻(xiàn)點(diǎn):configuration
、configurationDefaults
产禾、commands
、menus
牵啦、keybindings
亚情、languages
、debuggers
哈雏、breakpoints
楞件、grammars
、themes
裳瘪、snippets
土浸、jsonValidation
、views
彭羹、viewsContainers
黄伊、problemMatchers
、problemPatterns taskDefinitions
派殷、colors
还最、typescriptServerPlugins
墓阀、resourceLabelFormatters
、contributes.configur
拓轻。 - VS Code 接口:可以在擴(kuò)展代碼中調(diào)用的一組 JavaScript API斯撮。鏈接中列舉了所有可用的API,熟悉基本的扶叉,其他的用到的時(shí)候按需查找就行了勿锅。
一般來說,插件都會(huì)使用到這三個(gè)概念:激活事件枣氧、貢獻(xiàn)點(diǎn)和 VS Code API粱甫。接下來我們分析一下 HelloWorld 示例的源代碼,看看它是如何使用這些概念的作瞄。
JavaScript 插件目錄結(jié)構(gòu)
VS Code 插件的目錄結(jié)構(gòu)很簡單茶宵,根據(jù)命名大概就能知道作用。不同項(xiàng)目類型目錄結(jié)構(gòu)可能會(huì)有很大不同宗挥。對于 JavaScript 類型的項(xiàng)目來說乌庶,最重要的就是
package.json
和extension.js
。
清單文件:package.json
每個(gè) VS Code 插件都必須有一個(gè)用來描述插件的清單文件 package.json契耿。VS Code 的清單文件是聲明式的 JSON 格式瞒大,用于聲明插件名(name)、插件展示名(
displayName
)搪桂、描述信息(description
)透敌、版本( version )、引擎( engines )踢械、類別( categories )酗电、依賴( devDependencies )、腳本 (scripts)内列、貢獻(xiàn)點(diǎn)( contributes )撵术、入口文件( main )、激活事件( activationEvents )等话瞧。
下面是 helloworld 插件的清單文件內(nèi)容嫩与,為了便于理解,我加了一些注釋交排。
{
"name": "helloworld", //插件名
"displayName": "helloworld", // 插件市場顯示的插件名划滋,支持中文
"description": "demo", // 插件市場顯示的描述信息
"version": "0.0.1", // 版本號(hào)
// 最低支持的 VS Code 版本
"engines": {
"vscode": "^1.38.0"
},
// 插件市場分類
"categories": [
"Other"
],
// 激活事件
"activationEvents": [
"onCommand:extension.helloWorld"
],
"main": "./extension.js", // 指定入口文件
// 貢獻(xiàn)點(diǎn)
"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
插件的入口文件是在清單文件中指定的埃篓,如果項(xiàng)目比較大处坪,源文件比較多,也可以統(tǒng)一放在 src 目錄里。
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
/* 導(dǎo)入 "vscode" 模塊稻薇,這個(gè)模塊包含 VS Code 的擴(kuò)展接口嫂冻。 */
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
// 第一次執(zhí)行命令時(shí),插件會(huì)被激活塞椎;插件被激活時(shí)桨仿,這個(gè)函數(shù)會(huì)被調(diào)用
// 必須在入口中實(shí)現(xiàn)這個(gè)函數(shù)。
/**
* @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
/* 輸出診斷日志到控制臺(tái) */
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
/*
* 這個(gè)命令 extension.helloWorld 已經(jīng)在 package.json 文件中定義了案狠。
* 現(xiàn)在我們使用 registerCommand 接口給這個(gè)命令綁定實(shí)現(xiàn)服傍。
*/
let disposable = vscode.commands.registerCommand('extension.helloWorld', function () {
// The code you place here will be executed every time your command is executed
/* 每一次執(zhí)行命令,這兒的代碼都會(huì)執(zhí)行 */
// 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
}
一個(gè)插件必須在其主模塊實(shí)現(xiàn)并導(dǎo)出
activate()
和deactivate()
函數(shù)骂铁。
-
activate()
函數(shù) 初始化插件吹零。當(dāng)任何指定的激活事件發(fā)生時(shí),VS Code 會(huì)調(diào)用并且只調(diào)用它一次拉庵。 -
deactivate()
函數(shù) 清理插件灿椅。如果清理過程是異步的,deactivate()
函數(shù)必須返回一個(gè) Promise 對象钞支。如果清理運(yùn)行同步茫蛹,則deactivate()
函數(shù)返回undefined
。
Webview
插件可以分為多種烁挟,比如主題樣式類型的插件婴洼,圖標(biāo)插件,語言支持類型的插件撼嗓。Webview類型的插件只是Vscode插件的一個(gè)大類柬采。大致的實(shí)現(xiàn)大家可以參考文檔,文檔的示例使用的是html字符串且警,但這不適合復(fù)雜的Webview的開發(fā)粉捻。在GameNews這個(gè)插件中,模版部分振湾,我使用了vue以及pug杀迹。
// 靜態(tài)資源的目錄。絕對路徑押搪,并且使用了vscode-resource協(xié)議
// vscode-resource:/Users/Desktop/game-news/views
const webviewDir = path.join(context.extensionPath, 'views');
// 創(chuàng)建一個(gè)Webview的面板
const panel = vscode.window.createWebviewPanel(
viewType,
title,
vscode.ViewColumn.One,
{
enableScripts: true, // 允許運(yùn)行js腳本,默認(rèn)是關(guān)閉的
retainContextWhenHidden: true, // webview不可見時(shí)浅碾,腳本就會(huì)被掛起
// 指定允許加載的本地資源的根目錄
localResourceRoots: [vscode.Uri.file(webviewDir)]
}
);
// 模版文件
const tpl = path.join(webviewDir, 'index.pug');
// 通過pug渲染模版文件大州,到webview上
panel.webview.html = pug.renderFile(tpl, options);
本地資源的使用
Webview中,我們會(huì)需要使用本地的css垂谢,js文件厦画。雖然可以使用行間js或者行間樣式,但是總歸不太好。使用本地文件根暑,就會(huì)涉及的靜態(tài)文件路徑的問題力试,在VScode中,我們需要使用絕對路徑排嫌。并且是vscode-resource協(xié)議的路徑畸裳。
const webviewDir = path.join(context.extensionPath, 'views');
// 靜態(tài)資源的絕對目錄
let URI = vscode.Uri.file(path.join(webviewDir, 'js', 'vue.js'))
// 使用vscode-resource協(xié)議頭
// 然后這個(gè)URL就可以使用在我們的webview的模版中了
URI = URI.with({ scheme: 'vscode-resource' });
Webview與插件通信
Webview相當(dāng)于一個(gè)網(wǎng)頁,而網(wǎng)頁是無法調(diào)用一些本地功能的淳地。但是插件本身是運(yùn)行在node環(huán)境的怖糊,而已我們可以通過插件實(shí)現(xiàn)一些在網(wǎng)頁中無法完成的功能。Webview如果通知插件呢颇象?這涉及到了Webview于網(wǎng)頁的通信機(jī)制伍伤。
下面是GameNews插件的例子,我通過事件將游戲新聞的url遣钳,發(fā)送給插件扰魂。插件會(huì)調(diào)用系統(tǒng)的命令,使用本地的瀏覽器打開url蕴茴。
// webview
// webview中劝评,一個(gè)內(nèi)置的全局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
打包、發(fā)布和升級(jí)
如何讓別人也能使用自己開發(fā)的插件呢荐开?這和移動(dòng)應(yīng)用開發(fā)一樣付翁,有兩種方式:
- 把它發(fā)布到 VS Code 插件市場,這樣其他人就可以找到晃听、下載和使用你的插件百侧。
- 或者,可以將插件打包為可安裝的
vsix
格式能扒,并與其他用戶共享佣渴。
vsce,簡寫自 Visual Studio Code Extensions初斑, 是用于打包辛润、發(fā)布和管理 VS Code 插件的命令行工具
先安裝 Node.js
,然后運(yùn)行 npm install -g vsce
安裝 vsce
见秤。在插件的根目錄下運(yùn)行 vsce package
打包插件砂竖,運(yùn)行 vsce publish
發(fā)布插件。
npm install -g vsce
vsce create-publisher poetry # 這一步先創(chuàng)建一個(gè)發(fā)布賬號(hào)鹃答,需要用到token乎澄,看下面步驟獲取token
vsce package #打包插件 .vsix 格式
vsce publish #發(fā)布到 MarketPlace
發(fā)布插件到 VS Code
插件市場,需要注冊開發(fā)者賬號(hào)测摔。有關(guān)如何發(fā)布插件的內(nèi)容很簡單置济,可以參考官方文檔這一部分的內(nèi)容:https://code.visualstudio.com/api/working-with-extensions/publishing-extension
在Visual Studio Team Services 創(chuàng)建一個(gè)賬號(hào)
根據(jù)賬號(hào)的名字訪問主頁解恰,例如我的名字是bingou-ms,主頁鏈接就是
創(chuàng)建Personal Access Token
需要將Accounts設(shè)置為All accessible accounts
那么如何升級(jí)已經(jīng)發(fā)布到插件市場的插件呢浙于?修改/增加版本號(hào)护盈,然后再執(zhí)行
vsce publish
即可。
安裝vsix文件
可以直接安裝vsce package的vsix文件羞酗,方便在本地進(jìn)行調(diào)試腐宋。
code --install-extension vsix文件名