:::info 🦊 这篇文档记录了 @Arno(surfacew) 研究 VSCodeExtension 的学习历程和一些技术思考。 :::
VSCode 的插件系统是我所见过的 IDE 里面生态最繁荣的了。VSCode 的作者是当年 Eclipse 的架构师,其功底绝对不浅,所以可以从 VSCode 的产品层设计到技术层设计进行学习和剖析,找到有趣的点记录在这里。
学习一个技术产品,最好的方式是先用起来,之前个人写过一个 VSCode 插件用来解决内部产品的研发体验,如今再来尝试实现一个好玩的功能包,便于给日常开发注入灵魂。便自己给自己提需求吧,Here we go ~
需求
内置支持各种花式插入「好(hua)玩(li)有(hu)趣(shao)」的代码注释,比如:
- D1:最大分割符号(参考 Angular)
- D2:中等分割符号
- D3:小型分割符号
- H1:佛祖保佑
- H2:草泥马
- H3:ASCII 划线图
- H4:ASCII 表格
- WARNING
- TODO
- FIXME
- ATTENTION
- …
实现
该项目存储在 Github 上:https://github.com/SurfaceW/arno-vscode-vcomments-ext
工程初始化
仅仅几个命令非常快
npm install -g yo generator-code
yo code
code ./helloworld
npm run start
随后就直接在 VSCode 里面运行起来了,很舒服。
增加 snippets
将这些 Comments 作为 Snippets 添加到 VSCode 中是第一步。根据 SnippetsGuide 文档的指引,我们编写一个 template.js
里面将常用的好玩有用的注释写入其中,然后设定分割规则,并写一个简单的解析函数,将之切割为 snippet.json
,具体请参考代码仓库里面的具体实现。最终实现下面的效果:
发布插件
- 完善 ExtensionManifest 所依赖的发布字段。
- 使用 Microsoft VSCE 命令行发布插件。
- 微软开发者社区,提供了 Marketplace 来管理插件相关的生命周期,整体和 Azure 开发者连接到了一起,说白了有点牵动 MS 开发者生态的味道。
https://marketplace.visualstudio.com/items?itemName=surfacew.arno-commenter,发布之后的效果 🎉
质量提升
- VSCode 插件给出了 AzurePipeline 以及 TravisCI 的配置,给出了 CI 的解决方案
- VSCode 官方文档也完备地给出了 VSCode 扩展的 Test 机制,可以直接在 VSCode 内调试测试代码 👍
VSCodeExt 的设计思考
VSCode Guideline 给出了 VSCode 做扩展的最佳实践。这里面 VSCode 就常见的扩展实现类型做了一个推荐,告知用户哪些设计是推荐的,哪些设计是不符合实践的。整体来说图文并茂,DO 以及 DO NOT 界线颇为清晰。
以 👆 这张图为例,就将 VSCode 「约定俗成」的命名一次性给到了开发者,「瞬间有了体感」。又比如 Notification 的流程图整体也比较干净:
:::info
ℹ️ 对于文档而言,我们必须非常用心地设计,要想发设法,图文并茂地向开发者呈递我们的设计思考。比如 DO 和 DO NOT 在设计 Guide 的时候的确广泛使用。
:::
开放结构的设计
文档:这里
ActivationEvents
: ActivationEvents 事件系统,激活事件的注册,用于声明当前插件需要依赖的系统事件,以便于系统做定向广播。ContributionPoints
: ContributionPoints 的设计整体类似于扩展点注册的 Manifest.json 文件。这块是 VSCode 对外抛出的核心「可扩展」、「可配置」的扩展接口,每一项配置都可以等价为一个扩展点的描述。VSCode 将可枚举的模块功能都抽离出「扩展点」并支持插件在package.json
中显式声明关联,是典型的扩展方式。VSCodeAPI
:开发者可以使用的 VSCode 暴露出来的功能 API,各个模块精要抽象了核心 API,供扩展层使用。其 vscode.d.ts 颇有灵魂。
整体设计还是比较干净的,自然,易理解,符合开发的思维模式。
VSCode 主要的可扩展点
思维导图简单绘制一番:
一些琐碎的 Tips
- Starter 的 Doc 可以学习 VSCode 的写法,「简单干净」。
- 大量 Provider 的模式,用于扩展 👇 VSCode 代码层 API 注册扩展实现的方式有
registerXXXProvider()
的命名规约,这种注册机制在 VSCode API 中大量使用,用于数据、服务、UI 等注入
VSCode 发明了一个简单的
WhenClause
DSL 用于处理简单的条件表达,覆盖常规的条件判断操作,比如:"when": "resourceFilename =~ /docker/"
大量的 SampleCode 提供给开发者参考,大量的开源项目亦如此:
- 比如:vscode-search-node-modules:支持搜索本地的
node_modules
- 比如:官方 SampleLib
- 比如:vscode-search-node-modules:支持搜索本地的
VSCode 源代码的实现
源代码实现浅析:
源代码关注点:
- VSCodeExtension Launcher 时序?看 VSCode 是如何完成扩展插件启动的?
- WhenClause 语法是如何解析 & 如何运行的?
- VSCode core 开放 API 是如何组织 & 管理的?
- VSCode 整体 Event 机制?其事件的注册、广播和管理机制如何实现?
- VSCode 有 ExtensionHost 的概念,支持 Server 和 Client 多平台模式,其代码是如何隔离实现的?
- VSCode Language Server 是如何实现的?LanguagePack 里面最有灵魂的部分?尝试写一个简单的编程语言和编程语言背后的 LanguageServer 来玩一玩也挺有意思的 😁(比如一个批处理的 DSL,或者把 VSCode 的条件 ConditionCaluse 写出来)
小结
VSCode 的插件系统是值得单体应用做大规模扩展的时候深度借鉴的。后续个人在设计软件系统的开放扩展的时候需要更进一步,学其精粹。