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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM