1.vscode插件開發有什么用
每個公司、項目組、各人都有自己特殊的定制化、可公用的需求,vscode的已有插件顯然不能滿足我們各種各樣的要求,所以開發一個適用於我們自己的定制化插件,無疑能大大提高我們的開發效率以及團隊的語法規范
2.vscode插件開發、發布主要流程
- 插件開發前的准備:vscode、nodejs、vscode插件生產工具、git、微軟賬號
- 插件開發:插件構思、官方文檔查閱
- 插件發布:打包、上傳、插件市場操作
- 插件維護:更新迭代后打包、上傳、插件市場操作
3.插件開發前的准備:
vscode、nodejs、git、微軟賬號
vscode插件生產工具:官方推薦使用Yeoman 和 VS Code Extension Generator。用如下命令安裝:
npm install -g yo generator-code
3.1使用生產工具初始化代碼
yo code
- 目錄如下
├── .vscode // 資源配置文件
├── CHANGELOG.md // 更改記錄文件,會展示到vscode插件市場
├── extension.js // 拓展源代碼文件
├── jsconfig.json
├── package.json // 資源配置文件
├── README.md // 插件介紹文件,會展示到vscode插件市場
├── test // 測試文件
└── vsc-extension-quickstart.md
在js拓展項目下,最重要的就是extension.js和package.json。
4.開發的插件功能
- 初始化react的組件模塊
- 初始化項目里面能共用的模塊
4.1項目結構以及代碼
extention.js 代碼
'use strict';
const vscode = require('vscode');
const paramCase = require('change-case').paramCase;
const utils = require('./utils');
const { logger, generators } = utils;
function activate(context) {
let createComponent = (uri, type) => {
console.log('Create-react-component activated...');
new Promise(resolve =>
vscode.window
.showInputBox({
prompt: 'Enter component name'
})
.then(inputValue => resolve(inputValue))
)
.then(val => {
if (val.length === 0) {
logger('error', 'Component name can not be empty!');
throw new Error('Component name can not be empty!');
}
let componentName = paramCase(val);
// if 是初始化頁面寫入的路徑 else 初始化頁面整體模板
let componentDir = type === 'initReactComponent' ? generators.createComponentDir(uri, componentName, true)
: generators.createComponentDir(uri, componentName);
// if 是初始化頁面寫入的路徑 else 初始化頁面整體模板
if (type === 'initReactComponent') {
return Promise.all([
generators.createComponent(componentDir, componentName, type),
generators.createTestFile(componentDir, componentName, type),
generators.createCSS(componentDir, componentName, type),
]);
}
return Promise.all([
generators.createComponent(componentDir, componentName, type),
generators.createTestFile(componentDir, componentName),
generators.createCSS(componentDir, componentName),
generators.createModelFile(componentDir, componentName),
generators.createServiceFile(componentDir, componentName)
]);
})
.then(
() => logger('success', 'React component successfully created!'),
err => logger('error', err.message)
);
};
// 注冊命令
const componentsList = [
{
type: 'class',
commandID: 'extension.createReactClassComponent'
},
{
type: 'initReactComponent',
commandID: 'extension.initReactComponent'
}
];
componentsList.forEach(comp => {
let type = comp.type;
let disposable = vscode.commands.registerCommand(comp.commandID, uri => {
createComponent(uri, type);
});
context.subscriptions.push(disposable);
});
}
/**
* 插件被激活時觸發,所有代碼總入口
* @param {*} context 插件上下文
*/
module.exports = {
activate
};
utils.js 代碼(做寫入文件的操作)
'use strict';
const vscode = require('vscode');
const fse = require('fs-extra');
const fs = require('fs');
const path = require('path');
const pascalCase = require('change-case').pascalCase;
const camelCase = require('change-case').camelCase;
function logger(type, msg = '') {
switch (type) {
case 'success':
return vscode.window.setStatusBarMessage(`Success: ${msg}`, 5000);
case 'warning':
return vscode.window.showWarningMessage(`Warning: ${msg}`);
case 'error':
return vscode.window.showErrorMessage(`Failed: ${msg}`);
}
}
module.exports = {
logger,
generators: {
templatesDir: path.join(__dirname, '/templates'),
createFile: (file, data) =>
new Promise(resolve => {
let output = fse.outputFile(file, data);
resolve(output);
}),
resolveWorkspaceRoot: path =>
path.replace('${workspaceFolder}', vscode.workspace.rootPath),
// 返回需要返回的路徑
createComponentDir: function (uri, componentName, isInit) {
let contextMenuSourcePath;
if (uri && fs.lstatSync(uri.fsPath).isDirectory()) {
contextMenuSourcePath = uri.fsPath;
} else if (uri) {
contextMenuSourcePath = path.dirname(uri.fsPath);
} else {
contextMenuSourcePath = vscode.workspace.rootPath;
}
// if 是初始化頁面寫入的路徑 else 初始化頁面整體模板
let componentDir = isInit ? `${contextMenuSourcePath}/${pascalCase(
componentName
)}` : `${contextMenuSourcePath}`;
fse.mkdirsSync(componentDir);
return componentDir;
},
// 創建組件
createComponent: function (componentDir, componentName, type) {
// 讀取我們自定義的模板
let templateFileName = this.templatesDir + `/${type}.template`;
// 處理駝峰大小寫的名稱
const compName = pascalCase(componentName);
const cName = camelCase(componentName);
console.log(componentDir, 23123);
let componentContent = fs
.readFileSync(templateFileName)
.toString()
.replace(/{componentName}/g, compName).replace(/{cName}/g, cName);
// if 是初始化頁面寫入的路徑 else 初始化頁面整體模板
let filename = type === 'class' ? `${componentDir}/components/${compName}/${compName}.js` : `${componentDir}/${compName}.js`;
return this.createFile(filename, componentContent);
},
// 創建index.js
createTestFile: function (componentDir, componentName, type) {
let templateFileName = this.templatesDir + `/test.template`;
const compName = pascalCase(componentName);
let componentContent = fs
.readFileSync(templateFileName)
.toString()
.replace(/{componentName}/g, compName);
let filename = type ? `${componentDir}/index.js` : `${componentDir}/components/${compName}/index.js`;
return this.createFile(filename, componentContent);
},
// 創建models文件
createModelFile: function (componentDir, componentName) {
let templateFileName = this.templatesDir + `/models.template`;
const compName = camelCase(componentName);
let componentContent = fs
.readFileSync(templateFileName)
.toString()
.replace(/{componentName}/g, compName);
let filename = `${componentDir}/models/${compName}.js`;
return this.createFile(filename, componentContent);
},
// 創建services文件
createServiceFile: function (componentDir, componentName) {
let templateFileName = this.templatesDir + `/services.template`;
const compName = camelCase(componentName);
let componentContent = fs
.readFileSync(templateFileName)
.toString()
.replace(/{componentName}/g, compName);
let filename = `${componentDir}/services/${compName}.js`;
return this.createFile(filename, componentContent);
},
// 創建less文件
createCSS: function (componentDir, componentName, type) {
let templateFileName = `${this.templatesDir}/sass.template`;
const compName = camelCase(componentName);
let cssContent = fs
.readFileSync(templateFileName)
.toString()
.replace(/{componentName}/g, compName);
let filename = type ? `${componentDir}/less/${compName}.less` : `${componentDir}/components/${compName}/less/${compName}.less`;
return this.createFile(filename, cssContent);
}
}
};
4.2運行調試
- 操作效果
- 實現效果
發布
官方插件發布流程:https://code.visualstudio.com...
網上詳細的發布流程 https://www.cnblogs.com/...