VSCode提供了豐富的[API](https://code.visualstudio.com/api/references/vscode-api),可以借助編輯器擴展許多定制功能。
  本次研發了一款名為[Search Method](https://github.com/pwstrick/search-method)的插件,在此記錄整個研發過程。
## 一、準備工作
**1)安裝環境**
  首先是全局安裝 yo 和 generator-code 兩個庫,我本地全局安裝了[cnpm](https://npmmirror.com/),所以用它來安裝。
~~~
npm install yo generator-code -g
~~~
:-: 
  然后使用 yo 命令初始化插件項目。
~~~
yo code
~~~
  回答些問題,但如果在回答 Initialize a git repository 時選擇 yes,那么就會出現報錯。
:-: 
  選擇 no 之后,才會提示安裝成功,這個莫名其妙的問題就處理了好久。
:-: 
  初始化成功后,就會得到一個項目結構(大致如下),建議單獨打開個窗口調試插件。
~~~
|-- test
|-- extension.js // 插件入口文件,插件的邏輯在此完成
|-- CHANGELOG.md
|-- package-lock.json
|-- package.json
|-- README.md // 插件說明 README,發布后會展示
|-- jsconfig.json
|-- .eslintrc.json
|-- vsc-extension-quickstart.md
~~~
  最重要的就是 extension.js 和 package.json,前者會實現插件的核心功能,后者包括插件的配置信息。
**2)調試**
  選擇 run =》 Start Debugging 后,就會自動彈出另一個 VSCode 窗口。

?  在這個窗口中,會默認安裝上正在調試的插件,其實我本來起的插件名字叫 Search Function。
  但是在調試時,按下 Command + Shift + P 打開命令面板,卻無法在此處找到默認的 Hello World 命令。
:-: 
  直到我換了名字后,才能在調試時找到 Hello World,這個坑也花了我好幾個小時。
  還有個問題,就是在在編輯器的 Debug Console 標簽內無法看到打印信息,相當于是在盲調,電腦重啟后,就能看到了,還是重啟大法好。
:-: 
  至此,完成了整個準備工作。
## 二、開發過程
  公司有個 Node 項目,現在有個問題,就是 router 層的代碼無法自動關聯到 service 層的方法聲明。
  下面這段代碼存在于 router 層,common 存在于service 層,它有一個 aggregation() 方法。
  原先鼠標拖到方法處,按住 command 鍵,就能跳轉到聲明處,查看方法實現邏輯,但是現在無法跳轉。?
~~~
const data = await services.common.aggregation({ tableName });
~~~
  因為項目為了不用每次初始化 service 中的類,一下子全部都初始化好了,賦到一個對象中,如下所示。
~~~
Object.keys(dir).forEach((item) => {
services[item] = new dir[item](models);
});
~~~
  這次要開發的插件,其實就是為了解決此問題,提升大家的開發效率。
**1)最終效果**
  在經過多輪深思熟慮的設計之后,確定了要達到的效果,那就是先選中要查看的方法以及文件名稱,然后右鍵找到 Search Services File 菜單,此時就能直接跳轉過去了。
:-: 
**2)菜單配置**
  要想在右鍵顯示這個自定義的菜單,需要在 package.json 中做些配置。
  commands 是默認就存在的,主要是 menus 字段,注冊菜單。
~~~
"contributes": {
"commands": [
{
"command": "search-method.services",
"title": "Search Services File"
}
],
"menus": {
"editor/context": [
{
"command": "search-method.services",
"group": "navigation",
"when": "editorHasSelection"
}
]
}
},
~~~
  editor/context 是指編輯器上下文菜單,在[contributes.menus](https://code.visualstudio.com/api/references/contribution-points#contributes.menus)一欄中,還可以找到其余 menus 的關鍵字,可以都嘗試下。
  editor/context 的值是一個數組,可以配置多個菜單,菜單中的 group 就是菜單所處的位置。
  navigation 就是最上面,還有 1\_modification,9\_cutcopypaste 和 z\_commands[參考下圖](https://code.visualstudio.com/api/references/contribution-points#Sorting-of-groups)。
:-: 
  when 就是觸發條件,editorHasSelection 就是指在編輯器中選中時觸發。
  可選的關鍵字還可以是 editorFocus、inputFocus、editorHasMultipleSelections 等,參考[available contexts](https://code.visualstudio.com/api/references/when-clause-contexts#available-contexts)。
**3)核心邏輯**
  下面這段就是最精簡的 extension.js 代碼了,注冊一個名為 search-method.services 的命令,核心功能會在此回調函數中實現。?
~~~
const vscode = require('vscode');
function activate(context) {
const disposable = vscode.commands.registerCommand(
'search-method.services', (uri) => {
}
context.subscriptions.push(disposable);
}
function deactivate() {}
module.exports = {
activate,
deactivate
}
~~~
  在研發時,以為像下面這樣就能直接得到 webMonitor.js 絕對目錄,但其實此處讀的是插件的根目錄,而不是項目的。
~~~
path.resolve(__dirname, '../services/webMonitor.js')
~~~
  通過回調函數的參數 uri.fsPath 才能得到當前選中的代碼所處的絕對位置。下面是完整的插件邏輯。
~~~
1 const vscode = require('vscode');
2 const path = require('path');
3 const fs = require('fs');
4 const { Uri, window, Position, Range, Selection } = vscode;
5 const disposable = vscode.commands.registerCommand(
6 "search-method.services",
7 (uri) => {
8 // 獲取編輯器對象
9 const editor = window.activeTextEditor;
10 if (!editor) {
11 return;
12 }
13 // 當前選中的代碼所處的絕對位置
14 const dirPath = uri.fsPath;
15 // services的絕對目錄
16 const serviceDir = path.resolve(dirPath, "../../services");
17 // 獲取選中文本
18 const doc = editor.document;
19 const selection = editor.selection;
20 const words = doc.getText(selection).split(".");
21 const serviceName = words[0];
22 const methodName = words.length > 1 ? words[1] : "";
23 // 列出目錄中所有的文件
24 const files = fs.readdirSync(serviceDir);
25 for (const item of files) {
26 // 讀取文件名稱
27 const name = item.split(".")[0];
28 // 文件匹配
29 if (serviceName === name) {
30 const file = Uri.file(path.resolve(serviceDir, item));
31 // 根據換行符分隔字符串
32 const fileContentArr = fs
33 .readFileSync(path.resolve(serviceDir, item), "utf8")
34 .split(/\r?\n/);
35 // 聲明的方法會有 async 關鍵字,或者通過空格和括號匹配
36 const index = fileContentArr.findIndex(
37 (element) =>
38 element.indexOf(`async ${methodName}`) >= 0 ||
39 element.indexOf(` ${methodName}(`) >= 0
40 );
41 // 跳轉到指定行數的文件
42 window.showTextDocument(file).then((editor) => {
43 // 開始位置
44 const start = new Position(index, 0);
45 // 結束位置加了 20 行,為了便于查看
46 const end = new Position(index + 20, 0);
47 // 光標聚焦的位置
48 editor.selections = [new Selection(start, start)];
49 // 可見范圍
50 const range = new Range(start, end);
51 editor.revealRange(range);
52 });
53 break;
54 }
55 }
56 }
57 );
~~~
  上面這段代碼比較長,核心思路:
* 第13行,讀取當前項目 services 的絕對路徑。
* 第17行,獲取選中的文本,例如 common.aggregation,然后分隔得到文件名和方法名。
* 第23行,列出 services 的所有文件,并與選中的文件名匹配。
* 第28行,匹配成功時讀取文件內容并通過換行符分隔,查找方法所在的行。
* 第41行,通過[window.showTextDocument](https://code.visualstudio.com/api/references/vscode-api#window)打開[Uri.file()](https://code.visualstudio.com/api/references/vscode-api#Uri)處理過的文件,初始化[Position](https://code.visualstudio.com/api/references/vscode-api#Position)類,配置光標聚焦的位置([Selection](https://code.visualstudio.com/api/references/vscode-api#Selection))和可見范圍([Range](https://code.visualstudio.com/api/references/vscode-api#Range))。
  雖然只有40多行代碼,但花費了我一天的時間才完成,中間走了不少彎路,最麻煩的是跳轉文件,showTextDocument() 方法也是偶然間才發現的。
  還有個小技巧,可以通過看 window、Uri 這些類的聲明,就能了解到它們提供的功能。
## 三、對外發布
  為了能在 VSCode 的 Extensions 中被搜索到,還需要幾個步驟。
**1)注冊賬號**
  首先到[Azure DevOps](https://dev.azure.com/pwstrick/)?創建管理賬號,根據提示來就行了。
  然后選中 Personal access tokens,去創建 token。
:-: 
  接著在創建時,有些選項要注意,Organization 和 Scopes,網上說不能亂選,否則發布會不成功。創建后,記得自己將 token 保存一下,后面就無法查看了。
:-: 
  最后創建[發布賬號](https://marketplace.visualstudio.com/manage),填些信息,下一步登錄時使用。
**2)vsce**
  vsce 用于上傳插件,首先全局安裝。?
~~~
npm i vsce -g
~~~
  然后是登錄剛剛注冊的發布賬號,例如 vsce login pwstrick。
~~~
vsce login <publisher name>
~~~
  選好后會要求你輸入之前申請的 token,登錄成功后就會有下面的一段提示。
~~~
Personal Access Token for publisher 'pwstrick': ************************
The Personal Access Token verification succeeded for the publisher 'pwstrick'.
~~~
  此時,就可以輸入發布命令了,成功的話,就會出現 DONE 的提示。
~~~
vsce publish
INFO Publishing 'pwstrick.search-method v0.0.1'...
INFO Extension URL (might take a few minutes): https://marketplace.visualstudio.com/items?itemName=pwstrick.search-method
INFO Hub URL: https://marketplace.visualstudio.com/manage/publishers/pwstrick/extensions/search-method/hub
DONE Published pwstrick.search-method v0.0.1.
~~~
  上傳成功后,不會馬上就能搜索到。
  在[插件管理](https://marketplace.visualstudio.com/manage/publishers/)中,當出現綠色的勾時,才表示插件發布完成,現在可以在應用市場搜索到了。
:-: 
  可以看到并不是在第一行,需要往下翻一翻。
:-: 
  在給組員使用時,發現他們不能安裝,因為我設置的最低版本是 1.7.0,這個在開發的時候也需要注意。
~~~
"engines": {
"vscode": "^1.70.0"
},
~~~
參考:
[vscode插件開發指南(一)-理論篇](https://juejin.cn/post/6960626872791072798)
[vscode插件編寫體驗-右鍵菜單](https://segmentfault.com/a/1190000041672434)
[vscode window.showTextDocument示例](https://javascript.hotexamples.com/zh/examples/vscode/window/showTextDocument/javascript-window-showtextdocument-method-examples.html)
[編寫一個VSCode插件](https://juejin.cn/post/7119095066810908679)
*****
> 原文出處:
[博客園-前端利器躬行記](https://www.cnblogs.com/strick/category/1472499.html)
[知乎專欄-前端利器躬行記](https://zhuanlan.zhihu.com/pwtool)
已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。

推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、擴展運算符和剩余參數
- 3、解構
- 4、模板字面量
- 5、對象字面量的擴展
- 6、Symbol
- 7、代碼模塊化
- 8、數字
- 9、字符串
- 10、正則表達式
- 11、對象
- 12、數組
- 13、類型化數組
- 14、函數
- 15、箭頭函數和尾調用優化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、類
- 21、類的繼承
- 22、Promise
- 23、Promise的靜態方法和應用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基礎實踐
- 3、WebRTC視頻通話
- 4、Web音視頻基礎
- CSS進階
- 1、CSS基礎拾遺
- 2、偽類和偽元素
- 3、CSS屬性拾遺
- 4、浮動形狀
- 5、漸變
- 6、濾鏡
- 7、合成
- 8、裁剪和遮罩
- 9、網格布局
- 10、CSS方法論
- 11、管理后臺響應式改造
- React
- 1、函數式編程
- 2、JSX
- 3、組件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表單
- 8、樣式
- 9、組件通信
- 10、高階組件
- 11、Redux基礎
- 12、Redux中間件
- 13、React Router
- 14、測試框架
- 15、React Hooks
- 16、React源碼分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基礎
- 4、webpack進階
- 5、Git
- 6、Fiddler
- 7、自制腳手架
- 8、VSCode插件研發
- 9、WebView中的頁面調試方法
- Vue.js
- 1、數據綁定
- 2、指令
- 3、樣式和表單
- 4、組件
- 5、組件通信
- 6、內容分發
- 7、渲染函數和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、數據類型
- 2、接口
- 3、類
- 4、泛型
- 5、類型兼容性
- 6、高級類型
- 7、命名空間
- 8、裝飾器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系統和網絡
- 3、命令行工具
- 4、自建前端監控系統
- 5、定時任務的調試
- 6、自制短鏈系統
- 7、定時任務的進化史
- 8、通用接口
- 9、微前端實踐
- 10、接口日志查詢
- 11、E2E測試
- 12、BFF
- 13、MySQL歸檔
- 14、壓力測試
- 15、活動規則引擎
- 16、活動配置化
- 17、UmiJS版本升級
- 18、半吊子的可視化搭建系統
- 19、KOA源碼分析(上)
- 20、KOA源碼分析(下)
- 21、花10分鐘入門Node.js
- 22、Node環境升級日志
- 23、Worker threads
- 24、低代碼
- 25、Web自動化測試
- 26、接口攔截和頁面回放實驗
- 27、接口管理
- 28、Cypress自動化測試實踐
- 29、基于Electron的開播助手
- Node.js精進
- 1、模塊化
- 2、異步編程
- 3、流
- 4、事件觸發器
- 5、HTTP
- 6、文件
- 7、日志
- 8、錯誤處理
- 9、性能監控(上)
- 10、性能監控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 監控系統
- 1、SDK
- 2、存儲和分析
- 3、性能監控
- 4、內存泄漏
- 5、小程序
- 6、較長的白屏時間
- 7、頁面奔潰
- 8、shin-monitor源碼分析
- 前端性能精進
- 1、優化方法論之測量
- 2、優化方法論之分析
- 3、瀏覽器之圖像
- 4、瀏覽器之呈現
- 5、瀏覽器之JavaScript
- 6、網絡
- 7、構建
- 前端體驗優化
- 1、概述
- 2、基建
- 3、后端
- 4、數據
- 5、后臺
- Web優化
- 1、CSS優化
- 2、JavaScript優化
- 3、圖像和網絡
- 4、用戶體驗和工具
- 5、網站優化
- 6、優化閉環實踐
- 數據結構與算法
- 1、鏈表
- 2、棧、隊列、散列表和位運算
- 3、二叉樹
- 4、二分查找
- 5、回溯算法
- 6、貪心算法
- 7、分治算法
- 8、動態規劃
- 程序員之路
- 大學
- 2011年
- 2012年
- 2013年
- 2014年
- 項目反思
- 前端基礎學習分享
- 2015年
- 再一次項目反思
- 然并卵
- PC網站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端學習之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 2024年
- 日志
- 2020