在前幾天的美國紐約,微軟舉行了Connect(); //2015大會。通過這次大會,我們可以很高興的看到微軟的確變得更加開放也更加務(wù)實了。當(dāng)然,會上放出了不少新產(chǎn)品和新功能,其中就包括了VS Code的beta版本。而且微軟更進(jìn)一步,已經(jīng)在github將VS Code的代碼開源了。除了這些讓人興奮的消息,我們還應(yīng)該注意到VS Code提供了對拓展的支持。
所以本文就來聊一聊使用TypeScript開發(fā)VS Code拓展的話題吧。

本文所使用的拓展的應(yīng)用商店頁面:
https://marketplace.visualstudio.com/items/JiadongChen.LicenseHeader
github頁面:
https://github.com/chenjd/VSCode-StandardHeader
"萬事開頭,Hello World"。所以我們就從一個Hello World作為起點(diǎn),開始一步一步構(gòu)建自己的VScode的拓展。
在開發(fā)vscode的拓展之前,我們先要確保電腦上已經(jīng)安裝了Node.js。之后,我們便可以利用微軟所提供的基于Yeoman的模板生成器來生成vscode拓展的模板了。
npm install -g yo generator-code
之后,我們只需要在終端中運(yùn)行yo code命令,即可以進(jìn)入創(chuàng)建拓展模板的引導(dǎo)過程。
yo code
在引導(dǎo)過程中將TypeScript選擇為開發(fā)語言,并且填完一些基本信息之后,我們的第一個vscode拓展便創(chuàng)建完成了。
那么,yo code命令主要為我們做了一些什么事情呢?
下面便是我們的拓展項目的完整目錄:
.├── .gitignore //配置不需要加入版本管理的文件├── .vscode // VS Code的整合│ ├── launch.json│ ├── settings.json│ └── tasks.json├── .vscodeignore //配置不需要加入最終發(fā)布到拓展中的文件├── README.md├── src // 源文件│ └── extension.ts // 如果我們使用js來開發(fā)拓展,則該文件的后綴為.js├── test // test文件夾│ ├── extension.test.ts // 如果我們使用js來開發(fā)拓展,則該文件的后綴為.js│ └── index.ts // 如果我們使用js來開發(fā)拓展,則該文件的后綴為.js├── node_modules│ ├── vscode // vscode對typescript的語言支持。│ └── typescript // TypeScript的編譯器├── out // 編譯之后的輸出文件夾(只有TypeScript需要,JS無需)│ ├── src│ | ├── extension.js│ | └── extension.js.map│ └── test│ ├── extension.test.js│ ├── extension.test.js.map│ ├── index.js│ └── index.js.map├── package.json // 該拓展的資源配置文件├── tsconfig.json // ├── typings // 類型定義文件夾│ ├── node.d.ts // 和Node.js關(guān)聯(lián)的類型定義│ └── vscode-typings.d.ts // 和VS Code關(guān)聯(lián)的類型定義└── vsc-extension-quickstart.md
此時,我們只需要點(diǎn)擊在VS Code的Debug區(qū)域的Start按鈕即可。

在接下來開啟的一個處于拓展開發(fā)模式的新的VS Code中,我們只需要在命令面板中輸入Hello World便可以激活這個模板拓展,彈出一個Hello World的消息彈窗。

那么,VS Code到底是如何加載并運(yùn)行拓展的呢?我們又應(yīng)該如何開發(fā)拓展供自己甚至是分享給更多的人更好的使用VS Code呢?
作為拓展項目的資源配置文件,package.json不僅僅描述了該拓展的信息還描述了拓展的功能。需要說明的是,當(dāng)VS Code啟動時,拓展的package.json文件便會被讀取,并且VS Code還會對package.json文件中的contributes部分的內(nèi)容做處理。這一點(diǎn)和拓展的源文件extension.ts有所區(qū)別。VS Code并不會在啟動時便加載拓展的源代碼。
下面我們就來看一看我們剛剛生成的這個拓展項目中的package.json文件的內(nèi)容吧。
{ "name": "Standard-Header", "displayName": "Standard-Header", "description": "standard-header", "version": "0.0.1", "publisher": "JiadongChen", "engines": { "vscode": "^0.10.1" }, "categories": [ "Other" ], "activationEvents": [ "onCommand:extension.sayHello" ], "main": "./out/src/extension", "contributes": { "commands": [{ "command": "extension.sayHello", "title": "Hello World" }] }, "scripts": { "vscode:PRepublish": "node ./node_modules/vscode/bin/compile", "compile": "node ./node_modules/vscode/bin/compile -watch -p ./" }, "devDependencies": { "typescript": "^1.6.2", "vscode": "0.10.x" }}
我們可以看到,package.json描述了該拓展的一些基本信息,例如拓展的名稱name、拓展的描述信息description以及拓展的版本號version和發(fā)布者的信息publisher等等。順帶提一句,直接通過提高版本號的方式就可以使用拓展發(fā)布工具來更新已經(jīng)發(fā)布到VS Code應(yīng)用商店的拓展版本。
除了這些,我們甚至還可以在package.json文件中配置一些拓展在VS Code的應(yīng)用商店中的展示信息,例如拓展在商店中的種類:categories、拓展的icon圖:icon以及拓展在應(yīng)用市場主頁的一些展示信息:galleryBanner等等。
..."icon": "res/icon.png","galleryBanner": { "color": "#5c2d91", "theme": "dark"},"categories": [ "Other"],...

當(dāng)然,更重要的內(nèi)容是activationEvents、contributes以及scripts和main這幾項內(nèi)容。其中scripts項的內(nèi)容是使用TypeScript進(jìn)行開發(fā)時所特有的,主要的作用是用來提供對ts文件進(jìn)行編譯的相關(guān)信息。而main項則指向了將ts源文件編譯后所生成的js文件。
正如上文所說,VS Code默認(rèn)狀況下并不會在啟動時立刻執(zhí)行拓展中的代碼。因此,為了使拓展能夠被激活,我們需要在package.json文件中定義activationEvents項的內(nèi)容。例如上例中,activationEvents的定義如下:
..."activationEvents": [ "onCommand:extension.sayHello"],...
意思是當(dāng)“onCommand:extension.sayHello”事件被觸發(fā)之后,拓展會被激活。那么在VS Code中,激活事件都有哪些種類呢?下面我們就來歸一下類。
根據(jù)文件所使用的語言:onLanguage:${language}
當(dāng)打開的文件是使用onLanguage所規(guī)定的語言時,拓展會被激活。
例如:
..."activationEvents": [ "onLanguage:python"]...
根據(jù)所輸入的命令:onCommand:${command}
當(dāng)在onCommand中規(guī)定的命令被觸發(fā)時,拓展會被激活。在上文生成的Hello World模板中,我們就可以看到。
..."activationEvents": ["onCommand:extension.sayHello"]...
根據(jù)文件夾:workspaceContains:${toplevelfilename}
"activationEvents": [ "workspaceContains:package.json"],無限制:*
..."activationEvents": [ "*"]...
由于沒有限制,因此在VS Code一啟動時便會激活該拓展。因此,這種不加以條件限制就激活拓展的方式并不是十分推薦的。大家最好謹(jǐn)慎使用。
在package.json文件中的contributes項中,同樣包含很多種類。如果需要?dú)w類的話,可以分為以下幾個類型。
但是本文限于篇幅,將只關(guān)注commands和keybindings這兩種。
commands
還以上文中的Hello World為例,我們在commands項中定義了命令的title以及title所對應(yīng)的具體命令。如下所示:
"contributes": { "commands": [{ "command": "extension.sayHello", "title": "Hello World" }]},
此時一旦安裝了該拓展,我們就可以在VS Code中的命令面板(我在Mac上的快捷鍵是Shift+cmd+p)中找到“Hello World”,輸入便會觸發(fā)extension.sayHello這條命令,而上文中的拓展激活事件項activationEvents中如果定義的內(nèi)容是"onCommand:extension.sayHello",則激活事件被觸發(fā),拓展的代碼被激活。
keybindings
當(dāng)然,和commands對應(yīng)的,我們還可以通過在package.json中定義keybindings項,通過綁定快捷鍵的方式觸發(fā)命令。這樣操作起來更加便捷,例如下文中我們自己開發(fā)一個插入標(biāo)準(zhǔn)頁眉的拓展時,使用的便是綁定快捷鍵的方式。
"contributes": { "keybindings": [{ "command": "extension.insertHeader", "key": "shift+cmd+1", "when": "editorTextFocus" }]},
如果我們在VS Code中安裝了定義了快捷鍵觸發(fā)的拓展,則打開VS Code的KeyBoard ShortCut就可以看到拓展中定義的快捷鍵和它對應(yīng)的命令了。
通過上一小節(jié)的內(nèi)容,我們就能很清楚的理解上文中那個模板拓展的運(yùn)行過程了。
VS Code首先會檢測到拓展并且讀取拓展的package.json文件的內(nèi)容并將package.json文件中的contributes項應(yīng)用到VS Code中。這樣,我們就可以根據(jù)contributes項中的內(nèi)容,或者是在命令面板中輸入contributes項中定義的commands,或者是使用contributes項中所定義的快捷鍵keybindings來觸發(fā)extension.sayHello命令。
一旦extension.sayHello觸發(fā),VS Code會創(chuàng)建一個叫做onCommand:extension.sayHello的激活事件。
與此同時,所有在自己的package.json文件中將activationEvents設(shè)置為onCommand:extension.sayHello的拓展會被激活。并且會根據(jù)package.json文件中main項的內(nèi)容,將./out/src/extension.js文件加載到javaScript VM中。接下來,VS Code會調(diào)用在extension.js文件中的active函數(shù),在active函數(shù)中,我們需要提供“extension.sayHello”這個函數(shù)的具體實現(xiàn)并執(zhí)行。
好了,了解了VS Code拓展的基本知識之后我們就可以開始著手開發(fā)自己的拓展了,這個拓展的目的是向源文件添加License頁眉。
既然要打造自己的VS Code,那么自己喜歡的一些操作習(xí)慣自然希望能夠用在VS Code上。而插入頁眉便是這樣一個簡單的小功能。
我們首先來看一看在上文中那個Hello World模板拓展的源文件即extension.ts文件的基本內(nèi)容。
import * as vscode from 'vscode';export function activate(context: vscode.ExtensionContext) { var disposable = vscode.commands.registerCommand('extension.sayHello', () => { ...
vscode.window.showInformationMessage('Hello World!');
...
});}首先,我們自然要引入vscode命名空間下的API,以獲得控制VS Code的能力。
其次,我們注意到了拓展的源文件需要export一個叫做activate的函數(shù),當(dāng)拓展的package.json文件中activationEvents所定義的事件被觸發(fā)時,VS Code會調(diào)用activate函數(shù)。
最后,我們可以看到我們使用vscode的API注冊了一個叫做“extension.sayHello”的命令,并且提供了它的具體實現(xiàn),按照模板中的邏輯,“extension.sayHello”命令的邏輯是在窗口中顯示一個內(nèi)容為“Hello World”的信息消息。具體的效果在本文一開始的部分各位已經(jīng)看到了。
那么接下來就十分簡單了,我們首先新建一個叫做HeaderGenerator的類,用來執(zhí)行插入頁眉的任務(wù)。
class HeaderGenerator { private _disposable: Disposable; public insertHeader() { // Get the current text editor let editor = window.activeTextEditor; if (!editor) { return; } // Define header content var header = "License Header"; // Get the document var doc = editor.document; // Insert header editor.edit((eb) => { eb.insert(doc.positionAt(0), header); }); } dispose() { this._disposable.dispose(); }}
插入頁眉的具體執(zhí)行是當(dāng)前窗口的editor(TextEditor類)的edit方法,通過利用TextEditorEdit類的insert方法實現(xiàn)對當(dāng)前的文檔doc(TextDocument類)插入新的內(nèi)容。
之后,我們只需在extension.ts文件中的activate函數(shù)中實現(xiàn)調(diào)用HeaderGenerator類的insertHeader方法即可。
import * as vscode from 'vscode'; import {window, commands, Disposable, ExtensionContext, TextDocument} from 'vscode';export function activate(context: vscode.ExtensionContext) { console.log('Congratulations, your extension "standard-header" is now active!'); let headerGen = new HeaderGenerator(); var disposable = vscode.commands.registerCommand('extension.insertHeader', () => { headerGen.insertHeader(); }); context.subscriptions.push(headerGen); context.subscriptions.push(disposable);}
當(dāng)然,為了增加快捷鍵“shift+cmd+1”的支持,我們還需要在package.json中修改contributes的內(nèi)容:
"contributes": { "keybindings": [{ "command": "extension.insertHeader", "key": "shift+cmd+1", "when": "editorTextFocus" }]},
之后,讓我們先進(jìn)入拓展開發(fā)模式看一下效果。使用快捷鍵shift+cmd+1,我們可以看到在VS Code的窗口中插入了頁眉(截圖中的頁眉內(nèi)容我已經(jīng)換成了MIT協(xié)議)。

好了,到此我們的小小的在源文件中插入頁眉的拓展就完成了,下面就讓我們來使用安裝、甚至是發(fā)布到VS Code的應(yīng)用商店讓大家一起分享我們的勞動成果吧。
為了不必再每次都要進(jìn)入拓展開發(fā)模式才能“使用”我們的拓展,我們就必須讓自己的VS Code安裝這個拓展。
事實上在本地安裝供自己的拓展是十分簡單并且方便的事情。VS Code會在.vscode/extensions文件夾中獲取本地的拓展。而.vscode/extensions文件夾所在的位置我們可以總結(jié)如下:
我們只需拷貝一份我們的拓展到.vscode/extensions文件夾中,VS Code在啟動時便能夠檢查到該拓展了。
當(dāng)然,除了自己使用自己開發(fā)的拓展之外,我們還可以將拓展發(fā)布到VS Code的應(yīng)用商店。此時我們就要借助一個拓展發(fā)布工具——vsce了。
首先是安裝vsce:
npm install -g vsce
之后我們還需要到Visual Studio Team Services注冊并登陸,以獲取Personal access Token。
一旦獲取了Personal Access Token,我們就可以使用vsce創(chuàng)建一個發(fā)布者賬號了。
vsce create-publisher
緊接著,登陸并發(fā)布:
vsce login vsce publish發(fā)布成功之后,我們就可以在VS Code的應(yīng)用商店中看到自己的拓展了。

并且在VS Code的命令面板中,我們也可以使用命令安裝:
ext install

好啦,行文至此,使用TypeScript拓展你自己的VS Code講的已經(jīng)差不多了。希望各位多多交流~
|
新聞熱點(diǎn)
疑難解答