第一次vscode插件开发记录

670 阅读6分钟

第一次vscode插件开发记录

1.开发文档地址

中文地址:liiked.github.io/VS-Code-Ext…

英文地址:code.visualstudio.com/api

2.vscode插件可以实现:

  • 自定义命令
  • 快捷键
  • 自定义菜单项
  • 自定义跳转
  • 自动补全
  • 悬浮提示
  • 新增语言支持
  • 语法检查
  • 语法高亮
  • 代码格式化 ····

3.如何创建插件

(1)首先安装脚手架 npm install -g yo generator-code 然后进入工作目录,使用脚手架 yo code

(2)脚手架生成目录结构

image-20220721144555019.png

(3)结合react开发,改造项目

image-20220718195918358.png

webpack相关修改,配置不同target

//@ts-check

'use strict';

const path = require('path');
const webpack = require('webpack');


//@ts-check
/** @typedef {import('webpack').Configuration} WebpackConfig **/

/** @type WebpackConfig */
const extensionConfig = {
  target: 'node', 
	mode: 'none',

  entry: './src/extension.ts', 
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'extension.js',
    libraryTarget: 'commonjs2'
  },
  externals: {
    vscode: 'commonjs vscode' 
  },
  resolve: {
    extensions: ['.ts', '.js']
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'ts-loader'
          }
        ]
      }
    ]
  },
  devtool: 'nosources-source-map',
  infrastructureLogging: {
    level: "log", // enables logging required for problem matchers
  },
};
const webConfig = {
  target: 'web',
	mode: 'none', 
  entry: {
    app: './app/index.tsx',
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist'),
  },
  externals: {
    vscode: 'commonjs vscode' 
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx', '.css']
    
  },
  module: {
    rules: [
      {
        test: /\.(tsx|ts)$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'ts-loader'
          }
        ]
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      }
    ]
  },
  devtool: 'nosources-source-map',
  infrastructureLogging: {
    level: "log", // enables logging required for problem matchers
  },
  plugins: [
    new webpack.DefinePlugin({
        // webpack自带该插件,无需单独安装
        'process.env': {
            NODE_ENV: process.env.NODE_ENV, // 将属性转化为全局变量,让代码中可以正常访问
        },
    }),
],
};
module.exports = [ extensionConfig,webConfig ];

tsconfig相关修改

{
	"compilerOptions": {
		"module": "commonjs",
		"target": "ES2020",
	
		"sourceMap": true,
		// "rootDir": "src",
		"jsx": "react",
		"experimentalDecorators": true,
		"lib": ["dom", "ES2015"], // react dom相关
		"allowSyntheticDefaultImports": true, // import引入
		"strict": true   /* enable all strict type-checking options */
		/* Additional Checks */
		// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
		// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
		// "noUnusedParameters": true,  /* Report errors on unused parameters. */
	},
	"exclude": ["node_modules"]
}

4.package.json详解

activationEvents

配置项配置插件的激活数组,即在什么情况下插件会被激活,目前支持以下8种配置:

onLanguage: 在打开对应语言文件时

onCommand: 在执行对应命令时

onDebug: 在 debug 会话开始前

onDebugInitialConfigurations: 在初始化 debug 设置前

onDebugResolve: 在 debug 设置处理完之前

workspaceContains: 在打开一个文件夹后,如果文件夹内包含设置的文件名模式时

onFileSystem: 打开的文件或文件夹,是来自于设置的类型或协议时

onView: 侧边栏中设置的 id 项目展开时

onUri: 在基于 vscode 或 vscode-insiders 协议的 url 打开时

onWebviewPanel: 在打开设置的 webview 时

*: 在打开 vscode 的时候,如果不是必须一般不建议这么设置

contributes

配置相关功能

commands:命令,通过cmd+shift+p进行输入来实现的。

menus:通过这个选项我们可以设置右键的菜单

keybindings:可以设置快捷键

languages:设置语言特点,包括语言的后缀等

grammars:可以在这个配置项里设置描述语言的语法文件的路径,vscode可以根据这个语法文件来自动实现语法高亮功能

snippets:设置语法片段相关的路径 . . . . .

5.调试(注意:本地vscode版本必须高于插件设定的版本)

(1)按 F5 产生一个新的 扩展开发宿主vscode 调试台,在帮助里打开开发者模式(或者输入Developer: Toggle Developer Tools)

(2)在新的 vscode 调试台,打开 命令面板

  • win: ctrl + shift + p
  • mac: command + shift + p

输入package注册的命令:例如 Hello World

(3) 每次修改都要点击刷新按钮才能有效果

6.vscode功能举例

(1)快捷键

"keybindings": [
    {
        "command": "plugin-demo.helloWorld",
        "key": "ctrl+e",
        "mac": "cmd+e",
        "when": "editorTextFocus" // 编辑器内的文本聚焦时(光标闪动)
    }
]
  • command: 快捷键关联的命令
  • key: Windows平台对应的快捷键
  • mac: mac平台对应的快捷键
  • when: 什么时候快捷键有效

当插件被激活后,并且满足快捷键有效的时间,按快捷键就可以找到extension.js中与快捷键关联的command所不绑定的事件并执行。

(2)菜单

"menus": {
  "editor/context": [{ //editor/context 编辑器上下文  editor/title 编辑器标题栏
    "when": "editorFocus", // 编辑器聚焦时,不管是聚焦到文本还是小部件
    "command": "m.quickPage",
    "alt": "dadadada",
    "group": "navigation"
  }]
},

(3)代码片段

	"snippets": [
			{
				"language": "typescriptreact", // react ts中
				"path": "media/snippets.json" // 存放路径
			}
			
		]

7.使用webview

(1)webview API为开发者提供了完全自定义视图的能力,例如内置的Markdown插件使用了webview渲染Markdown预览文件。Webview也能用于构建比VS Code原生API支持构建的更加复杂的用户交互界面。

可以把webview看成是VS Code中的iframe,它可以渲染几乎全部的HTML内容,它通过消息机制和插件通信。这样的自由度令我们的webview非常强劲并将插件的潜力提升到了新的高度。

(2)创建WebView

context.subscriptions.push(vscode.commands.registerCommand('extension.demo.openWebview', function (uri) {
    // 创建webview
    const panel = vscode.window.createWebviewPanel(
        'testWebview', // viewType
        "WebView演示", // 视图标题
        vscode.ViewColumn.One, // 显示在编辑器的哪个部位
        {
            enableScripts: true, // 启用JS,默认禁用
            retainContextWhenHidden: true, // webview被隐藏时保持状态,避免被重置
           	localResourceRoots: [vscode.Uri.file(path.join(this.context.extensionPath, 'dist'))], // 加载本地资源路径
        }
    );
    panel.webview.html = `<html><body>你好,我是Webview</body></html>`
}

几点说明:

  • 默认情况下,在Web视图中禁用JavaScript,但可以通过传入enableScripts: true选项轻松启用;
  • 默认情况下当webview被隐藏时资源会被销毁,通过retainContextWhenHidden: true会一直保存,但会占用较大内存开销,仅在需要时开启;

(3)生命周期

export function activate(context: vscode.ExtensionContext) {
  context.subscriptions.push(
    vscode.commands.registerCommand('catCoding.start', () => {
      const panel = vscode.window.createWebviewPanel(
        'catCoding',
        'Cat Coding',
        vscode.ViewColumn.One,
        {}
      );

      let iteration = 0;
      const updateWebview = () => {
        const cat = iteration++ % 2 ? 'Compiling Cat' : 'Coding Cat';
        panel.title = cat;
        panel.webview.html = getWebviewContent(cat);
      };

      updateWebview();
      const interval = setInterval(updateWebview, 1000);
      // 手动销毁 panel.dispose()
      panel.onDidDispose(
        () => {
          // 当面板关闭时,取消webview内容之后的更新
          clearInterval(interval);
        },
        null,
        context.subscriptions
      );
    })
  );
}

(4)加载本地内容:这两种都可以

    const bundleScriptPath = this.panel.webview.asWebviewUri(
      vscode.Uri.file(path.join(this.context.extensionPath, 'dist', 'app.js'))
    );
     // 获取磁盘上的资源路径
     const onDiskPath = vscode.Uri.file(
      path.join(this.context.extensionPath, 'dist', 'app.js')
    );

    // 获取在webview中使用的特殊URI
    const catGifSrc = onDiskPath.with({ scheme: 'vscode-resource' });

(5)信息传递

插件可以用webview.postMessage()将数据发送到它的webview中。这个方法能发送任何序列化的JSON数据到webview中,在webview中则通过message事件接受信息。


// 插件发送消息
panel.webview.postMessage({ command: 'refactor' });

// webview接收消息
window.addEventListener('message',handleMessage, false);

webview也可以把信息传递回对应的插件中,用VS Code API 为webview提供的postMessage函数我们就可以完成这个目标。调用webview中的acquireVsCodeApi获取VS Code API对象。这个函数在一个会话中只能调用一次,你必须保持住这个方法返回的VS Code API实例,然后再转交到需要调用这个实例的地方。

// webview发送消息
const vscode = acquireVsCodeApi();
 vscode.postMessage({
   type: 'submit',
   data: values
 });

// 插件接受webview信息
panel.webview.onDidReceiveMessage(message => {
  switch (message.command) {
    case 'alert':
      vscode.window.showErrorMessage(message.text);
      return;
  }
}, undefined, context.subscriptions);

8.发布流程

(1)打包:

先安装 npm install -g vsce

​ 执行 vsce package 命令,得到一个 vsix 结尾的文件

(2)发版:

  • 创建组织:先在这个网站里 Azure DevOps 登录自己的账号,然后创建组织
  • 创建token:选择 个人访问令牌 后,点击 New Token ,填写相关信息后,将会得到 Token,复制token
  • 创建发布者:vsce create-publisher (publisher name) 或者 创建发布者 ,填写自己的 Name 即可
  • 注意:需要在我们的 package.json 中添加 publisher 字段
  • 执行 vsce login ,输入复制的token,登录成功
  • 执行发布 vsce publish

image-20220719193047910.png