【Web技術】746- VSCode 插件開發入門教程


本來連接:https://hellogithub2014.github.io/2019/06/09/vscode-plugin-development/javascript

以前一直覺得開發VS code插件是一件很難的事情,後來工做上須要搞一個效率小工具,就試着找了些資料來入門,發現其實就入門和開發一些簡單功能的插件來講難度仍是很低的。由於vscode自己是基於electron開發的,因此整體來講開發插件就是在寫node代碼,額外再加一些編輯器api,插件發佈的過程和npm包的發佈很相似。html

vscode官方提供的腳手架還幫忙加上了調試配置,調試很是方便。下面就來講下具體步驟,在學習的過程當中參考了一些博客,放在了最後面。前端

環境準備

這個很簡單,我就直接拷貝過來了。vue

  • nodejs: 建議使用 LTS 版本
  • npm: 建議最新版本
  • yeoman : npm install -g yo
  • generator-code : npm install -g generator-code

另外小TIPS,咱們平時直接安裝的插件所在目錄是~/.vscode/extensions,有興趣的能夠看看這些插件是怎麼實現的。java

腳手架

安裝的yo能夠直接生成一個Hello World版本的插件目錄。執行node

yo code

即會提示一些問題,按照我的喜愛填寫便可,最後會生成樣板代碼:git

.
├── CHANGELOG.md                 插件變動記錄
├── README.md
├── extension.js                 插件入口main文件
├── jsconfig.json                編輯器關於js的配置
├── package.json                 全局配置
├── test                         測試代碼文件夾
│   ├── extension.test.js
│   └── index.js
├── vsc-extension-quickstart.md  新手介紹
└── yarn.lock

其中的quickstart.md是新手引導,裏面包含了對文件的做用解析、如何運行插件、測試插等等,推薦去看一看,咱們在下面也會介紹一些。除此以外在package.json裏也包含了不少很是重要的信息:github

{
  "name""hello-world", // 插件名
  "displayName""hello-world",
  "description""hello world", // 插件描述
  "version""0.0.1",
  "engines": {
    "vscode""^1.35.0" // 運行插件須要vscode最低版本
  },
  "categories": ["Other"],
  "activationEvents": ["onCommand:extension.helloWorld"], // 如何激活插件:在命令面板(Command+Shift+P吊起)輸入helloWorld. 注意command名須要在contributes.commands中有配置
  "main""./extension.js", // 插件入口
  "contributes": {
    "commands": [
      // 此數組表示插件支持的全部命令
      {
        "command""extension.helloWorld", // 命令對應的Command,須要和代碼裏保持一致
        "title""Hello World" // 命令的顯示名稱
      }
    ]
  },
  "scripts": {
    // 正常的npm script
    "postinstall""node ./node_modules/vscode/bin/install",
    "test""node ./node_modules/vscode/bin/test"
  },
  "devDependencies": {
    // 依賴包
    "typescript""^3.3.1",
    "vscode""^1.1.28",
    "eslint""^5.13.0",
    "@types/node""^10.12.21",
    "@types/mocha""^2.2.42"
  }
}

啓動、調試插件

啓動運行

腳手架生成的其實就是一個node應用,直接按F5便可運行。對配置感興趣的也能夠查看根目錄下的.vscode/launch.jsonweb

跑起來之後默認會新開一個vscode窗口,而後會發現什麼都沒有發生,這是由插件的啓動方式決定的,配置於package.json裏的activationEvents項。經常使用的有:算法

  • onLanguage   在打開特定語言類型的文件後激活
  • onCommand    在執行特定命令後激活

因爲咱們的插件是配置的onCommand啓動,而且指定的命令名是Hello World,因此咱們在新開的vscode窗口中按下快捷鍵Command+Shift+P後再找到Hello World,選中並執行便可。

最後順利的話,編輯器右下角會彈出Hello World!。

若是細心的話,還會在源窗口的控制檯的調試控制檯tab 中看到以下輸出:

Congratulations, your extension "hello-world" is now active!

這個就是由插件的真正代碼部分輸出的了。咱們接下來看看extension.js的內容:

// vscode編輯器api入口
const vscode = require('vscode');

/**
 * 今生命週期方法在插件激活時執行
 * @param {vscode.ExtensionContext} context
 */

function activate(context{
  // console的各類方法都是輸出在`調試控制檯`tab下
  console.log('Congratulations, your extension "hello-world" is now active!');

  // registerCommand用於註冊命令並提供具體邏輯,命令名須要和package.json裏寫的一致。
  // 回調函數在命令被觸發時執行。
  let disposable = vscode.commands.registerCommand('extension.helloWorld'function({
    // 在編輯器右下角展現一個message box
    vscode.window.showInformationMessage('Hello World!');
  });

  // 將registerCommand的返回值放入subscriptions能夠自動執行內存回收邏輯。
  context.subscriptions.push(disposable);
}
exports.activate = activate;

// 當插件被設置爲無效時執行今生命週期鉤子
function deactivate({}

module.exports = {
  activate,
  deactivate,
};

以上就是此插件的完整邏輯了,配置註釋是很簡單的。能夠看到主要就是兩個生命週期函數,另外搭配一些編輯器api就完成了。

調試

腳手架已經貼心的幫咱們加了調試配置,咱們只用添加斷點便可:

Command 配置

上面提到了生成一個command只須要 2 步,先是利用vscode.commands.registerCommand註冊一個,而後再到package.json裏的contributes.commands中配置便可。圍繞command還能夠作一些其餘事情,最多見的就是配置右鍵菜單和快捷鍵。

右鍵菜單

表示右鍵的菜單裏出現指定command,配置方法:

"contributes":{
  "menus": {
    "editor/context": [
      {
        "when""editorHasSelection && resourceFilename =~ /.js|.vue|.ts/", // 出現時機,當編輯器中有選中文本同時文件名後綴是js/vue/ts
        "command""extension.starling_textSearch", // 須要在`contributes.commands`存在此命令
        "group""6_Starling" // 命令所在的組,右鍵菜單能夠分組,組與組之間存在分隔線
      },
    ]
  }
}

快捷鍵

有了快捷鍵後,就不用每次在命令面板裏查找並運行命令了,一樣是在package.json中配置:

"contributes": {
  "keybindings": [
    {
      "command""extension.starling_textSearch",
      "key""ctrl+f11", // 在Windows上的快捷鍵
      "mac""cmd+f11", // 在mac上的快捷鍵
      "when""editorTextFocus" // 出現時機, 當編輯器焦點在某個文本中
    }
  ],
}

發佈

主要參考的是官方文檔

首先須要安裝vsce工具:

npm install -g vsce

本地打包將插件打包成.vsix文件。

vsce package

會在項目根目錄生成hello-world-0.0.1.vsix,而後在編輯器的插件面板選擇從VSIX安裝便可:

發佈到插件市場

  • 須要獲取一個token,參考官方文檔
  • 利用token建立一個publisher,這是在插件市場的用戶
vsce create-publisher (publisher name)
  • 本地登陸此用戶
vsce login (publisher name)
  • 發佈插件
vsce publish

順利的話在控制檯會提示發佈成功,而後過幾分鐘就能夠在插件市場搜到本身的插件啦!😄

版本升級

當插件內容發生變動時,從新發布時最好更新版本號,vsce能夠遵循語義化版本指定升級大(major)/小(minor)/補丁(patch)版本,也能夠直接指定版本號。例如只升級小版本:

vsce publish minor

若是插件代碼在gitlab上,由於倉庫在內網,須要事先將README裏的圖片替換爲公網cdn上的路徑。

snippets

snippets是代碼片斷,能夠理解爲代碼快捷鍵,在輸入不多量觸發代碼後便可聯想出一大坨關聯代碼,很是方便。對於js、ts、vue均可以在插件市場找到很是多的snippets插件。

開發snippets只用兩步:

  • 編寫snippets映射文件,它是一個json,例如javascript.json:
{
  "this$t": {
    "prefix""tt'", // 觸發代碼
    "body": [
      // 聯想出來的關聯代碼
      "this.\\$t('${1:key}')" // ${1: key} 是佔位符,聯想出來後會自動聚焦在這裏
    ],
    "description""this.$t" // snippets描述,當有多個匹配的代碼片斷時,能夠用來識別
  }
}
  • 在package.json中配置
"contributes": {
  "snippets": [
    {
      "language""javascript", // 代碼片斷起做用的語言類型
      "path""./src/snippets/javascript.json" // 對應的映射文件
    }
  ]
}

最後就能夠在編輯器看到效果了:

  • 更多細節參考snippets-syntax

插件默認配置

不少插件是須要一些額外配置才能工做的,設置默認配置一樣在package.json裏:

"contributes": {
  "configuration": { // 默認配置
    "type""object",
    "title""",
    "required": [
      "sid"
    ],
    "properties": {
      "includes": {
        "type""Array",
        "default": [
          "json"
        ],
        "description""文件類型過濾器"
      }
    }
  },
}

默認配置是json schema格式,在覆蓋默認配置時若是校驗出錯會有提示。

插件中使用getConfiguration來讀取配置:

function getConfig() {
  const config = vscode.workspace.getConfiguration();
  const includes: string[] | undefined = config.get('includes'); // 獲取指定配置項

  return {
    includes: includes || [],
  };
}

監聽配置項修改

在用戶安裝了插件後,可能會修改配置,如何實時監聽配置項的修改呢?vscode提供了onDidChangeConfiguration事件監聽。

vscode.workspace.onDidChangeConfiguration(function(event{
  const configList = ['includes'];
  // affectsConfiguration: 判斷是否變動了指定配置項
  const affected = configList.some(item => event.affectsConfiguration(item));
  if (affected) {
    // do some thing ...
  }
});

常見編輯器 api

全部vscode相關api均可以在官網文檔查找,vscode內部也集成了.d.ts文件,編輯器內直接跳轉定義便可。這裏只列舉一些常見的api.

  • messgae

用於展現提示性消息,出如今編輯器右下角,而不是頂部或右上角。

和console相似,提供了普通消息、警告消息、錯誤消息。

vscode.window.showInformationMessage('普通消息');
vscode.window.showWarningMessage('警告消息');
vscode.window.showErrorMessage('錯誤消息');

消息也支持交互按鈕,當選中按鈕時返回的是按鈕自己:

vscode.window.showErrorMessage(`與starling的遠程交互依賴vscode-starling.sid配置項`'打開配置項').then(selection => {
  if (selection === '打開配置項') {
    vscode.commands.executeCommand('workbench.action.openSettings');
  }
});

input box

在編輯器頂部展現一個input輸入框,使用vscode.window.showInputBox,會返回一個Promise:

const text: string | undefined = await vscode.window.showInputBox({
  '最後一步,輸入文案'
})

quick pick

用於從一組選項中選擇一個,相似於select組件。使用vscode.window.showQuickPick,一樣返回一個Promise,resolve時獲得被選中的選項或undefined:

const lang: string | undefined = await vscode.window.showQuickPick(['en''zh''ja'], {
  placeHolder'第一步:選擇語言',
});

每一個選項也能夠是對象類型:

const option: Object | undefined = await vscode.window.showQuickPick([{ id1name'a' }, { id2name'b' }, { id3name'c' }], {
  placeHolder'select an option',
});

output channel

在利用Control + ~打開控制檯後,會出現 4 個tab,從左到右依次是問題、輸出、調試控制檯、終端。output channel就是用於控制輸出 tab的內容,能夠往其中追加文本、追加行、清空,能夠將其當作一個簡單的文件。output channel適用於一次展現大量信息.

使用vscode.window.createOutputChannel建立output channel實例,而後就能夠操做各類api了。

const opc = vscode.window.createOutputChannel('textSearch'); // 能夠有多個OutputChannel共存,使用參數名區分

opc.clear(); // 清空
opc.appendLine('水電費'); // 追加一行
opc.show(); // 打開控制檯並切換到OutputChannel tab

一個例子:

file selector

有些時候須要操做本地文件系統,例如選擇某個文件、將文件保存到指定位置等。

  • 保存文件到指定位置使用showSaveDialog,它會打開文件選擇器彈窗,選擇了保存路徑後點擊肯定會返回選中的路徑,若是點擊取消會返回undefined。
// 讓用戶手動選擇文件的的存儲路徑
const uri = await vscode.window.showSaveDialog({
  filters: {
    zip: ['zip'], // 文件類型過濾
  },
});
if (!uri) {
  return false;
}

writeFile(uri.fsPath); // 寫入文件
  • 文件選擇showOpenDialog一樣會打開文件選擇器彈窗,不過此次是用於選擇文件,若是有選擇文件會返回選中的文件路徑,反之返回undefined。
// showOpenDialog返回的是文件路徑數組
const uris = await window.showOpenDialog({
  canSelectFoldersfalse// 是否能夠選擇文件夾
  canSelectMany: false// 是否能夠選擇多個文件
  filters: {
    json: ['json'], // 文件類型過濾
  },
});

if (!uris || !uris.length) {
  return;
}

handleFiles(uris);

hover

有時候須要在hover到文本上時展現一些提示信息,例如eslint插件在hover到不合規的代碼上時會展現具體違反了哪些規則:

處理hover須要註冊一個hover處理器,vscode會在hover到文本上時自動調用處理器,同時傳遞hover相關的信息。例如一個展現光標所在的單詞hover處理器:

/**
 * document: 打開的文本
 * position:hover的位置
 * token: 用於取消hover處理器做用
 */

async function hover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken{
  const line = document.lineAt(position).text; // 光標所在的行
  // getWordRangeAtPosition獲取光標所在單詞的行列號範圍;getText獲取指定範圍的文本
  const positionWord = document.getText(document.getWordRangeAtPosition(position));

  console.log('光標所在位置的單詞是:', positionWord);
}

// registerHoverProvider的第一個參數數組代表此處理器的做用範圍
const hoverDisposable = vscode.languages.registerHoverProvider(['javascript''vue'], {
  provideHover: hover,
});

context.subscriptions.push(hoverDisposable);

selection

與hover相似,有時候須要處理選中的文本,獲取它是經過vscode.TextEditor實例上的屬性,有兩個相關屬性

  • selections:全部被選中的文本信息
  • selection:第一個被選中的文本信息, 等同於selections[0]

獲取TextEditor的一個方法是經過註冊textEditorCommand,會在回調函數裏提供TextEditor實例,例如展現選中文本:

let command = vscode.commands.registerTextEditorCommand('extension.selection'function(textEditor, edit{
  const text = textEditor.document.getText(textEditor.selection);
  console.log('選中的文本是:', text);
});

context.subscriptions.push(command);

FileSystemWatcher

用於監聽文件是否發生了變化,能夠監聽到新建、更新、刪除這 3 種事件,也能夠選擇忽略其中某個類型事件。建立watcher是利用vscode.workspace.createFileSystemWatcher:

function createFileSystemWatcher(globPattern: GlobPattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): FileSystemWatcher;

例如監聽全部js文件的變更:

const watcher = vscode.workspace.createFileSystemWatcher('*.js'falsefalsefalse);
watcher.onDidChange(e => { // 文件發生更新
  console.log('js changed,' e.fsPath);
});
watcher.onDidCreate(e => { // 新建了js文件
  console.log('js created,' e.fsPath);
});
watcher.onDidDelete(e => { // 刪除了js文件
  console.log('js deleted,' e.fsPath);
});

參考文章

  • https://code.visualstudio.com/api
  • VSCode插件開發全攻略:https://www.cnblogs.com/liuxianan/p/vscode-plugin-overview.html
  • VSCode插件開發急速入門:https://juejin.im/entry/6844903640826642440

1. JavaScript 重溫系列(22篇全)
2. ECMAScript 重溫系列(10篇全)
3. JavaScript設計模式 重溫系列(9篇全)
4.  正則 / 框架 / 算法等 重溫系列(16篇全)
5.  Webpack4 入門(上) ||  Webpack4 入門(下)
6.  MobX 入門(上)  ||   MobX 入門(下)
7. 8 0+篇原創系列彙總

回覆「加羣」與大佬們一塊兒交流學習~

點擊「閱讀原文」查看 80+ 篇原創文章

本文分享自微信公衆號 - 前端自習課(FE-study)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索