vscode自定义插件开发
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/...