工作中需要为vscode编写几个extension,查了不少资料,包括官网的API和示例,但是感觉不是特别适合入门者,所以打算写一个关于vscode extensions系列的文章。
在您读这篇文章的时候,我默认您已经安装了vscode和nodejs的开发环境。如果还没有安装nodejs,我想这篇文章Node.js安装配置-菜鸟网可能对您有所帮助。
vscode有入门的例子可供参看,理解vscode官方给的示例对于我们编写extensions很有帮助。
注:本文只介绍基本概念,下一篇文章介绍代码及API。
了解vscode extensions的基本概念,能够帮助我们更好的写vscode的扩展。
扩展有三种基本的类别:
- Extensions - 最基础的类别
- Language Servers - 通过 Language Server Protocol
增强编辑体验
- Debuggers - 和调试有关
所有的扩展被激活后都运行在扩展进程(extension host process)中的,这个单独的进程可以保证VS代码始终保持响应,避免扩展出错导致IDE崩溃。
扩展支持(Extensions include support for):
- Activation - 检测到特定的文件类型、存在特定文件、通过命令选项版选择一个命令(a command is selected via the Command Palette)或者组合键(a key combination)时,加载一个扩展
- Editor - 和编辑器内容有关
- Workspace - 访问开放式编辑器、状态栏、信息消息等
- Eventing - 和编辑器生命周期有关,比如: open, close, change, and more
- Evolved editing - 创建丰富的语言支持提供程序,包括 IntelliSense, Peek, Hover, Diagnostics 等等
语言服务器是一种特殊的扩展,它为VS Code中的多种语言提供更好的编辑体验。 使用语言服务器,您可以实现跳转到定义,自动完成,错误检查以及VS Code中支持的许多其他语言功能。
Language Server is a special kind of extension that powers the editing experience for many languages in VS Code. With language servers, you can implement jump-to-definitions, autocomplete, error-checking and many other language features supported in VS Code.
vscode实现了一个通用的调试器UI,调试器有自己专用的进程。
VS Code implements a generic debugger UI and relies on debugger extensions and so called “debug adapters” to connect the debug UI to a real debugger or runtime. A debug adapter is a dedicated process that communicates with VS Code through the VS Code Debug Protocol and can be implemented in any language.
本节参考:Overview
vs code 提供扩展功能的时候,会考虑很多因素,以下是vscode核心决策的背景:
- 稳定性 - 扩展隔离(Stability - Extension Isolation)
- 扩展是运行在独立的进程(extension host process)中的,目的是为了避免扩展影响vs code的性能和稳定性,特别是启动时间。
- 这种架构可以保证vs code随时响应用户的操作,无论扩展在做什么。
- 性能 - 扩展激活(Performance - Extension Activation)
- 扩展会尽肯能晚的被加载,未使用的扩展不会被加载,因此不会消耗内存。为了支持延迟触发扩展,vscode定义了激活事件。
- 扩展清单(Extension Manifest)
- 为了延迟加载扩展,vscode需要一个扩展清单文件(package.json)为其提供特定字段,这其中包括激活事件和扩展点,vscode在启动时会读取清单并准备相对应的UI。
- 可扩展性API(Extensibility API)
- vscode不向扩展程序提供修改DOM的能力。
- 基于协议的扩展(Protocol based extensions)
- VS Code中一个常见的扩展方式是在一个独立的进程中执行扩展代码,并通过协议和VS Code通信。
VS Code中的扩展API遵循一些在所有API中应用的指导模式:
- Promises
- VS Code使用Promises处理异步。
- 取消令牌(Cancellation Tokens)
- 通常操作是在不稳定的状态下启动的,在操作完成之前会发生变化。有这种行为的API会传递一个CancellationToken,你可以检查是否取消或者在取消是获取通知,取消令牌通常是函数调用的最后一个参数,是可选的。
- Disposables
- The VS Code API uses the dispose pattern for resources that are obtained from VS Code. This applies to event listening, commands, interacting with the UI, and various language contributions.
- Events
- VS Code API中的函数,可以使用侦听器函数来订阅这些函数,返回一个一次性的事件侦听器,可以在处理事件后删除该事件侦听器。
- 事件命名遵循on[Will|Did]VerbNoun?
模式,
- Strict null
- Using Node.js Modules with Extensions
- 你可以在扩展中使用NodeJS模块,与Node项目类似,你可以将这些依赖添加到包中,在 package.json 使用 dependencies 字段。
- VS Code不会安装扩展总需要的依赖,因此你需要在发布之前安装到扩展中。
本节参考: patterns-and-principles
vscode提供一下激活方式:
onLanguage:${language}
onCommand:${command}
onDebug
workspaceContains:${toplevelfilename}
onFileSystem:${scheme}
onView:${viewId}
*
activationEvents
数组中声明多种语言。"activationEvents": [
"onLanguage:json",
"onLanguage:markdown",
"onLanguage:typescript"
]
"activationEvents": [
"onCommand:extension.sayHello"
]
"activationEvents": [
"onDebug"
]
还有两个更细粒度的激活事件:
- onDebugInitialConfigurations
:在调用DebugConfigurationProvider
的provideDebugConfigurations
方法之前会被调用
- onDebugResolve:type
:在调用DebugConfigurationProvider
的resolveDebugConfiguration
方法之前会被调用
Rule of thumb: If activation of a debug extensions is lightweight, use onDebug. If it is heavyweight, use onDebugInitialConfigurations and/or onDebugResolve depending on whether the DebugConfigurationProvider implements the corresponding methods provideDebugConfigurations and/or resolveDebugConfiguration.
"activationEvents": [
"workspaceContains:**/.editorconfig"
]
ftp
、 ssh
。"activationEvents": [
"onFileSystem:sftp"
]
"activationEvents": [
"onView:nodeDependencies"
]
*
要好。注:
- 这些扩展中,除了*
都是特定事件激活,只有在满足特定条件时才触发。
- 扩展必须在主模块导出activate()
函数,该函数仅会在被触发后执行一次。
- 扩展必须在主模块导出deactivate()
函数,以便VS代码关闭时执行清理任务。
本节参考:Activation Events -package.json
所有的vscode 扩展,在其根目录下都会有一个清单文件package.json
,字段(Fields)如下:
名称 | 必须 | 类型 | 描述 |
---|---|---|---|
name | Y | string | 扩展的名称,全小写,没有空格 |
version | Y | string | ]SemVer兼容版本 |
publisher | Y | string | 发布名称 |
engines | Y | object | 扩展能够兼容的最小的VS Code代码版本,不能为* 。例如^0.10.5表示扩展能够运行的最小的VS Code版本为0.10.5 |
license | N | string | 许可 |
displayName | N | string | 市场中显示的扩展的名称 |
description | N | string | 简短描述您的扩展是什么和做了什么 |
categories | N | string[] | 扩展所属的类别: [Programming Languages, Snippets, Linters, Themes, Debuggers, Formatters, Keymaps, SCM Providers, Other, Extension Packs, Language Packs] |
keywords | N | array | 关键词,使扩展更容易被发现 |
galleryBanner | N | object | |
preview | N | boolean | |
main | N | string | 扩展入口 |
contributes | N | object | 扩展描述对象 |
activationEvents | N | array | 激活事件数组 |
badges | N | array | 显示在市场侧栏的徽标,分别表示url、href、description |
markdown | N | string | 控制扩展市场上使用的markdown渲染引擎,要么是github (default)要么是standard |
qna | N | marketplace (default), string, false | 控制市场上Q & A 链接 |
dependencies | N | object | 运行时需要的NodeJS依赖。 |
devDependencies | N | object | 开发时需要的NodeJS依赖。 |
extensionDependencies | N | array | 此扩展所依赖的扩展的id集合。当该扩展被安装时,所依赖的扩展会一并被安装。扩展的id总是${publisher}.${name} |
scripts | N | object | 与npm的脚本完全相同,但是带有额外的VS代码特定字段。 |
icon | N | string | 至少128x128像素的图标路径(视网膜屏幕256 x256) |
本节参考: extension-manifest
vscode提供以下扩展点:
configuration
commands
menus
keybindings
languages
debuggers
breakpoints
grammars
themes
snippets
jsonValidation
views
problemMatchers
problemPatterns
文档写的很详细,我就不详细写了,需要哪一部分自己看吧,以后有时间会继续完善这一部分。
本节参考:Contribution Points - package.json