VS Code插件开发笔记(2) Get Started

这是VS Code官方文档的第二章节,主要内容是通过创建一个Hello World插件来作为插件编写入门

Hello World

建立框架

进行VS Code插件开发的前提是安装了Node.jsGit,并且需要安装YeomanVS Code Extension Generator来生成插件框架

npm install -g yo generator-code
复制代码

然后可以通过执行yo code创建一个插件框架

# ? What type of extension do you want to create? New Extension (TypeScript)
# ? What's the name of your extension? HelloWorld
### Press <Enter> to choose default for all options below ###

# ? What's the identifier of your extension? helloworld
# ? What's the description of your extension? LEAVE BLANK
# ? Initialize a git repository? Yes
# ? Bundle the source code with webpack? No
# ? Which package manager to use? npm
复制代码

该框架具备基本的功能,我们用VS Code刚刚创建的项目,按下F5键(此时不要打开任何文件),会自动开启一个新的VS Code界面,在这个界面中我们按下Ctrl+Shift+P组合键唤醒Command Palette,然后输入Hello Word命令:

image.png

之后我们会在页面的右下角见到Hello World from HelloWord!提示:

image.png

修改源码

我们可以试着尝试修改下上述的框架里的代码

定位到src/extension.ts

// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';

// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {

	// Use the console to output diagnostic information (console.log) and errors (console.error)
	// This line of code will only be executed once when your extension is activated
	  console.log('Congratulations, your extension "helloword" is now active!');

	// The command has been defined in the package.json file
	// Now provide the implementation of the command with registerCommand
	// The commandId parameter must match the command field in package.json
	let disposable = vscode.commands.registerCommand('helloword.helloWorld', () => {
	   // The code you place here will be executed every time your command is executed
         // Display a message box to the user
     vscode.window.showInformationMessage('Hello World from HelloWord!');
	});

	context.subscriptions.push(disposable);
}

// this method is called when your extension is deactivated
export function deactivate() {}
复制代码

我们可以将vscode.window.showInformationMessage('Hello World from HelloWord!');做修改,改为vscode.window.showInformationMessage('这是第一个插件!');,保存修改后,在调试窗口里执行Developer: Reload Window命令:

image.png

再次执行Hello World命令,可以看到提示信息发生了变化:

image.png

除此之外,我们还可以通过修改package.jsoncontributes字段信息,来修改命令的名称,如:

"contributes": {
   "commands": [{
      "command": "helloword.helloWorld",
+      "title": "Clock"
   }]
},
复制代码

将命令名称改为Clock,则执行命令时会看到Command Palette里的名称已经发生改变

image.png

可以尝试一个练习,修改提示的内容,比如显示当前时间。还可以通过查阅vscode-api试着用一些新的api,看看执行效果。例如我在这里就试着运行了一下vscode.window.showErrorMessage接口,这种尝试很有趣

调试

我们可以在源码上直接打断点,运行的时候会自动停止,而且我们可以将鼠标放在变量上,看到变量的具体取值。如果有过浏览器调试经验的话,应该不会感到困难

image.png

Hello World 进阶

我们在此继续对上面的hello world示例作进一步的分析

功能实现原理

细看起来上面的Hello World插件干了三件事:

  1. package.json中注册onCommand活动事件(Activation Event),以便当用户运行Hello World命令时唤醒(activated)插件

    "activationEvents": [
       "onCommand:helloword.helloWorld"
    ]
    复制代码
  2. package.json中注册contributes.commandsContribution Point),以便可以在Command Palette中使用

    "contributes": {
       "commands": [{
            "command": "helloword.helloWorld",
            "title": "Clock"
        }]
     }  
    复制代码
  3. extension.ts中用commands.registerCommandVS Code API)给Hello World命令绑定一个具体的函数

    let disposable = vscode.commands.registerCommand('helloword.helloWorld', () => {
     // The code you place here will be executed every time your command is executed
    
     // Display a message box to the user
     vscode.window.showErrorMessage(new Date().toLocaleString());
    });
    复制代码

通过上述分析可知,通常一个插件就是Contribution PointsVS Code API的组合。官方的Extensions Capabilities Overview文档可以帮助你寻找到适合你自己插件的Contribution PointsVS Code API

项目结构

Hello World插件是以如下结构组织起来的:

.
├── .vscode
│   ├── launch.json     // Config for launching and debugging the extension
│   └── tasks.json      // Config for build task that compiles TypeScript
├── .gitignore          // Ignore build output and node_modules
├── README.md           // Readable description of your extension's functionality
├── src
│   └── extension.ts    // Extension source code
├── package.json        // Extension manifest
├── tsconfig.json       // TypeScript configuration
复制代码

这里我们要将目光集中在package.jsonextension.ts,这里是理解Hello World插件的关键

插件清单(Extension Manifest

每个VS Code插件都必须有一个package.json作为它的 Extension Manifest,这个package.json文件除了包含常见的Node.js用到的scriptsdevDependencies等字段外,还有VS Code插件所特有的contributespublisheractivationEvents等字段。你可以在官方的 Extension Manifest 文档中找到所有的VS Code插件字段。

对于Hello World插件来说,package.json文件内容是这样的:

{
  "name": "helloword",
  "displayName": "HelloWord",
  "description": "",
  "version": "0.0.1",
  "publisher": "vscode-lamengduo-samples",
  "engines": {
     "vscode": "^1.56.0"
  },
  "categories": [
     "Other"
  ],
  "activationEvents": [
     "onCommand:helloword.helloWorld"
  ],
  "main": "./dist/extension.js",
  "contributes": {
     "commands": [{
        "command": "helloword.helloWorld",
        "title": "Clock"
     }]
  },
  "scripts": {
     "vscode:prepublish": "yarn run package",
     "compile": "webpack",
     "watch": "webpack --watch",
     "package": "webpack --mode production --devtool hidden-source-map",
     "test-compile": "tsc -p ./",
     "test-watch": "tsc -watch -p ./",
     "pretest": "yarn run test-compile && yarn run lint",
     "lint": "eslint src --ext ts",
     "test": "node ./out/test/runTest.js"
  },
  "devDependencies": {
     "@types/vscode": "^1.56.0",
     "@types/glob": "^7.1.3",
     "@types/mocha": "^8.0.4",
     "@types/node": "14.x",
     "eslint": "^7.19.0",
     "@typescript-eslint/eslint-plugin": "^4.14.1",
     "@typescript-eslint/parser": "^4.14.1",
     "glob": "^7.1.6",
     "mocha": "^8.2.1",
     "typescript": "^4.1.3",
     "vscode-test": "^1.5.0",
     "ts-loader": "^8.0.14",
     "webpack": "^5.19.0",
     "webpack-cli": "^4.4.0"
  }
}
复制代码

这些字段中有几个比较重要,这里单独说一说:

  • namepublisherVS Code会把<publisher>.<name>作为插件的唯一ID,例如这个插件的ID就是vscode-lamengduo-samples.helloword
  • main:指明了插件的入口
  • activationEventscontributes:对应 Activation EventsContribution Points
  • engines.vscode:标记当前插件需要的VS Code最低版本

入口文件

每个VS Code插件都有一个入口文件(由package.json中的main字段指定),VS Code规范要求插件的入口文件需要导出两个函数activatedeactivate。当开发者注册的Activation Event被触发时,将会执行activate函数。deactivate函数则主要是给插件开发者一个在插件停止工作之前一个执行清理的机会。对很多应用来说,deactivate其实不是必须的,可以删掉。不过如果你希望当VS Code关闭、插件不可用、插件卸载时做点什么的话,这个方法就有用了。

VS Code的插件API在 @types/vscode 包中做了类型声明,这个文件将会根据package.json文件中的engines.vscode提供智能提示等服务(如果插件框架是通过yo命令生成的,则@types/vscode会默认安装好)

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享