vscode自定义插件开发

1.vscode插件开发有什么用

每个公司、项目组、各人都有自己特殊的定制化、可公用的需求,vscode的已有插件显然不能满足我们各种各样的要求,所以开发一个适用于我们自己的定制化插件,无疑能大大提高我们的开发效率以及团队的语法规范

2.vscode插件开发、发布主要流程

  1. 插件开发前的准备:vscode、nodejs、vscode插件生产工具、git、微软账号
  2. 插件开发:插件构思、官方文档查阅
  3. 插件发布:打包、上传、插件市场操作
  4. 插件维护:更新迭代后打包、上传、插件市场操作

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.开发的插件功能

  1. 初始化react的组件模块
  2. 初始化项目里面能共用的模块

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/...

项目地址:https://github.com/huanglovesong...

posted @ 2020-01-10 16:07  福小松  阅读(3142)  评论(0编辑  收藏  举报