背景
想必每個熟練的前端弄潮者
,在熟練業務之後,常常都會將元件進行抽離公共元件,可以大大的提高開發效率。然而抽離公共元件之後,日常的開發便是建立相同的資料夾,修改router
,修改表單的屬性 fields
和 prop
等,重複的建立相同的資料夾,重複修改檔案 name
, 重複的寫 router
等,但是作為組內不同的人員,風格又不一致,所以能不能即規範程式碼的風格,又能快速的建立模板呢。
比如我們常見的模板型別
├─componentsName
│ ├─api
│ │ index.js
│ ├─components
│ │ list-table.vue
│ │ list-search.vue
│ │ index.js
│ ├─config
│ │ index.js
│ index.vue
│ route.js
vscode外掛
通過 官方文件 的學習,我們可以發現 vscode
外掛擴充套件的方式,去實現這個功能。
- 環境安裝
npm i -g yo generator-code // 官方外掛開發腳手架
yo code // 執行腳手架命令
根據步驟我們選擇建立 New Extension
可以選擇自己喜歡的語言 Javascript
或者 TypeScript
, 這邊筆者選的是 JavaScript
同樣,我們從國際慣例的 Hello World
開始,選擇好相應的配置
專案結構
專案結構比較簡單,主要的檔案為 package.json
和 extension.js
這兩個檔案
{
"name": "hello-world", // 外掛名稱
"displayName": "Hello World",
"description": "hello world",
"version": "0.0.1", // 外掛版本
"engines": {
"vscode": "^1.63.0" // vscode的版本
},
"categories": [
"Other"
],
// 擴充套件的啟用事件
"activationEvents": [
"onCommand:hello-world.helloWorld"
],
// 入口檔案
"main": "./extension.js",
// vscode外掛大部分功能配置都在這裡配置
"contributes": {
"commands": [
{
"command": "hello-world.helloWorld",
"title": "Hello World"
}
]
},
"scripts": {
"lint": "eslint .",
"pretest": "npm run lint",
"test": "node ./test/runTest.js"
},
"devDependencies": {
"@types/vscode": "^1.63.0",
"@types/glob": "^7.1.4",
"@types/mocha": "^9.0.0",
"@types/node": "14.x",
"eslint": "^7.32.0",
"glob": "^7.1.7",
"mocha": "^9.1.1",
"typescript": "^4.4.3",
"@vscode/test-electron": "^1.6.2"
}
}
extension.js
檔案內容如下
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
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 "hello-world" 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
let disposable = vscode.commands.registerCommand('hello-world.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 from Hello World!');
});
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
function deactivate() {}
module.exports = {
activate,
deactivate
}
1. 理解
main
定義了整個外掛的主入口,所以看到這裡,按照我們的慣性,可以新建src
資料夾,將extension.js
已到src
資料夾下面。contributes.commands
註冊了名為hello-world.helloWorld
的命令,並在src/extension.js
實現。- 定義完命令之後,還需要在
activationEvents
上新增onCommand:hello-world.helloWorld
。
2. 執行除錯
新建完成之後,工程已經幫我們配置好除錯引數
我們只需要點選 Run Extension
即可,此時將開啟一個新的vscode
視窗,顯示Extension Development Host
此時我們按下快捷鍵 command + shift + P
,輸入 Hello
即可看到我們編寫的外掛了,選中我們的外掛,即可發現右下角的彈窗 Hello World from Hello World!
3. 新增快捷鍵和右鍵選單
在我們的 package.json
中,新增如下程式碼
"contributes": {
"commands": [
{
"command": "hello-world.helloWorld",
"title": "Hello World"
}
],
"keybindings": [
{
"command": "hello-world.helloWorld",
"key": "ctrl+f10",
"mac": "cmd+f10",
"when": "editorFocus"
}
],
"menus": {
"explorer/context": [
{
"command": "hello-world.helloWorld",
"group": "navigation", // 選單位於最上面
"when": "explorerResourceIsFolder" // 只有是資料夾時才能喚起選單
}
]
}
},
在資料夾區域右鍵,即可看到我們的選單命令了, 同時也可以看到快捷鍵。
至此,我們已經完成了一個簡單的 vscode
外掛。
4. 改造
修改檔案目錄如下
├─node_modules
├─src
│ main.js
├─test
│ .eslintrc.json
│ .gitignore
│ .vscodeignore
│ jsconfig.json
│ package-lock.json
│ package.json
│ READEME.md
│ vsc-extension-quickstart.md
修改 package.json
檔案
{
"name": "hello-template",
"displayName": "hello-template",
"description": "hello world",
"publisher": "retrychx",
"version": "0.0.1",
"engines": {
"vscode": "^1.63.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:hello-template"
],
"main": "./src/main.js",
"contributes": {
"commands": [
{
"command": "hello-template",
"title": "Hello Template"
}
],
"keybindings": [
{
"command": "hello-template",
"key": "ctrl+f10",
"mac": "cmd+f10",
"when": "editorFocus"
}
],
"menus": {
"explorer/context": [
{
"command": "hello-template",
"group": "navigation",
"when": "explorerResourceIsFolder"
}
]
}
},
"scripts": {
"lint": "eslint .",
"pretest": "npm run lint",
"test": "node ./test/runTest.js"
},
"devDependencies": {
"@types/vscode": "^1.63.0",
"@types/glob": "^7.1.4",
"@types/mocha": "^9.0.0",
"@types/node": "14.x",
"eslint": "^7.32.0",
"glob": "^7.1.7",
"mocha": "^9.1.1",
"typescript": "^4.4.3",
"@vscode/test-electron": "^1.6.2"
}
}
修改 src/main.js
檔案
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
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 "hello-world" 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
let disposable = vscode.commands.registerCommand('hello-template', 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('test');
});
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
function deactivate() {}
module.exports = {
activate,
deactivate
}
在 registerCommand
方法處,修改命令,和 package.json
中的 command
中保持一致,然後除錯執行我們的 vscode
,快捷鍵召喚出我們的外掛,可以看到我們的外掛名稱 Hello Template
,點選,即可看到跳出的彈窗
5. 新建模板字串
在 src/
下面,我們新建 template.js
檔案,在裡面宣告我們要新建的模板。
route.js
模板
由於需要路由名稱和標題兩個變數,所以宣告瞭兩個變數
const routeTemplate = params =>
`
import List from './index'
export default [
{
path: '${params.path}',
name: '${params.path}',
meta: {
title: '${params.title}'
},
component: List
}
]
`
index.js
入口檔案模板
const indexTemplate =
`
<template>
<div></div>
</template>
<script>
import { ListSearch, ListTable } from './components'
import * as API from './api/index'
import utils from '@/utils'
export default {
components: { ListSearch, ListTable },
data() {
return {
},
}
},
mounted() {
},
methods: {
},
}
</script>
<style>
</style>
`
根據封裝的元件,所以可以依次新建不同的模板:configTemplate
、apiTemplate
、comIndexTemplate
、searchTemplate
、tableTemplate
等,匯出我們需要的模板
const config = {
routeTemplate: routeTemplate,
indexTemplate: indexTemplate,
configTemplate: configTemplate,
apiTemplate: apiTemplate,
comIndexTemplate: comIndexTemplate,
searchTemplate: searchTemplate,
tableTemplate: tableTemplate
}
module.exports = config
6. 引入使用者變數
由於我們需要非同步處理,所以引入async
let disposable = vscode.commands.registerCommand('hello-template', async url => {
// 設定輸入框提示
const options = {
prompt: '請輸入模板名稱',
placeHolder: '模板名稱'
}
// 輸入模板名稱
const templateName = await vscode.window.showInputBox(options)
// 設定標題
const optionsTitle = {
prompt: '請輸入標題名稱',
placeHolder: '標題名稱'
}
// 輸入模板名稱
const templateTitle = await vscode.window.showInputBox(optionsTitle)
// 設定路徑
const optionsRoute = {
prompt: '請輸入路徑名稱',
placeHolder: '路徑名稱'
}
// 輸入路徑名稱
const templateRoute = await vscode.window.showInputBox(optionsRoute)
const params = {
path: templateRoute,
title: templateTitle
}
});
執行除錯,我們可以看到呼叫我們的外掛,可以看到出現了輸入框:
通過輸入名稱,我們可以拿到自己想要的變數。然後我們就可以呼叫 fs
和 path
兩個模組就可以寫我們自己的檔案了。
由於為了保證,我們的建立檔案和資料夾的順序。
首先我們用了 existsSync
和 mkdirSync
來建立資料夾;然後我們再用 existsSync
和 writeFileSync
來建立檔案,然後再最後,做個成功的提示即可:
vscode.window.showInformationMessage('模板建立成功')
至此,我們已經完成了所有的編碼。那麼我們就看一下最後的除錯結果。
在資料夾處右鍵,召喚出我們的外掛指令Hello Template
輸入對應的名稱之後,我們可以看到在右鍵的資料夾下,建立了我們想要的模板。
我們就可以節省很多重複的工作了。
7. 引入新功能
由於在開發過程中,後端給的開發文件,提供的介面都是來自mock
的連線,這個時候就在想能不能解析mock
的介面資料自動引入介面註釋。
const request = require('request')
const YAPIURL = 'https://mock.shizhuang-inc.com/api/interface/get'
const param = 'token' // 個人的token
function getYapi(id) {
const url = `${YAPIURL}?id=${id}&token=${param}`
return new Promise(async (resolve, reject) => {
request(url, function(error, response,body) {
debugger
if(error) {
reject(error)
}
const bodyToJson = JSON.parse(body)
// 介面id不存在
if(!bodyToJson.data) {
reject(null)
}
resolve({
title: bodyToJson.data.title,
path: bodyToJson.data.path
})
})
})
}
module.exports = {
getYapi
}
- 新增右鍵選單
在package.json
裡面
"menus": {
"editor/context": [
{
"when": "resourceLangId == javascript", // 當檔案為js檔案的時候
"command": "erp-addInterface",
"group": "navigation"
}
]
}
在main.js
中,註冊command
事件
let addDisposable = vscode.commands.registerCommand('erp-addInterface', async url => {
// 設定輸入框提示
const options = {
prompt: '請輸入介面Id',
placeHolder: '介面Id'
}
// 輸入路徑名稱
const apiTag = await vscode.window.showInputBox(options)
if(!+apiTag) {
vscode.window.showInformationMessage('輸入正確的介面Id')
return
}
try {
const res = await api.getYapi(+apiTag)
const apiName = res.path ? res.path.split('/').pop() : ''
res.name = apiName
const interfaceTemplate = config.interfaceTemplate(res)
await fs.appendFileSync(url.path, interfaceTemplate, 'utf8')
vscode.window.showInformationMessage('介面新增成功')
} catch (error) {
if(!error) {
vscode.window.showInformationMessage('介面Id不存在')
return
}
vscode.window.showInformationMessage(error)
}
- 檢視效果
可以生成註釋和介面,方便快捷。
打包
無論是本地打包還是釋出到應用市場,我們都要藉助vsce
這個工具。
1. 安裝
npm install vsce -g
2. 打包
打包成 vsix
檔案
vsce package
發現報錯如下:
錯誤指出我們要修改 README.md
檔案,我們修改以下檔案,再次執行打包。
按照指示命令,一步步的執行,打包成功,看一下我們的專案目錄,可以看到我們的打包檔案。
3. 釋出
開啟發布市場 官方網站 , 建立自己的釋出賬號,然後記錄下自己的個人 token
, 即可開始釋出。
vsce publish
輸入自己的賬號,和 token
之後就可以釋出了。等待幾分鐘後就可以在網頁看到自己的專案
例如筆者釋出的外掛 erp-template
,在外掛市場搜尋可以看到,我們自己的外掛了
好了,至此,vscode
外掛開發已經完成了。
總結
這裡僅僅是想到的一個開發場景,相對來說,只是提供一個開發思路,在開發過程中,可以多進行思考,做一些有趣的事情。
文/migor
關注得物技術,做最潮技術人!