梅旭光的个人博客

装X是写博客的第一源动力🐶

0%

Vetur 插件是如何做到自动补全的

Vetur 插件 是一个 VS Code 上的 Vue 插件,提供了代码补全、高亮等功能。今天看了一下代码,记录一下 Vetur 插件是如何做到 Script 部分自动补全的。

不同 block 的处理

首先说一下 Vetur 是如何对 Vue 的每一部分进行高亮的。在 Vetur 的 Language Server 中,实现了一个 LanguageModes (server/src/embeddedSupport/languageModes.ts)类:

/images/2020/vetur-on-complete/01.png

这个 LanguageModes 类中实现了 getModeAtPosition 方法,也就是根据文档当前所处的位置,返回不同的 mode。

mode 是用于处理不同语言的一系列工具方法:

/images/2020/vetur-on-complete/02.png

他们是在 init 中进行初始化的。比如 vue-html 处理 template 部分,javascript、typescript 处理 script 部分。

这些 mode 的主要作用其实就是识别出语言,然后调用这些语言的方法来进行高亮、补全等操作。

可以看到 javascript、typescript、tsx 都使用的同一个 jsMode,他们的内部都是使用的 TypeScript 库来实现的。

jsMode定义在 server/src/modes/script/javascript.ts 中,它有这些方法:

/images/2020/vetur-on-complete/03.png

从名字就可以看出大部分方法的功能,其中 doComplete 方法就是用于代码补全的。

/images/2020/vetur-on-complete/04.png

这个方法的代码是这样的,其中 service.getCompletionsAtPosition 方法就是用于获取所有补全选项的,这个 service 其实就是 TypeScript 自身,getCompletionsAtPosition 是 TypeScript 的一个 API:https://github.com/Microsoft/TypeScript/wiki/Using-the-Language-Service-API

所以我们可以看到,Vetur 中对于 script 部分的代码补全,是依赖 TypeScript 来实现的,依赖两个工作:

  • 识别这部分是 js、ts
  • 有 Vue 的类型信息

extend Vue 时

我们知道 .vue 文件中的 script 其实不只有一种写法,可以这么写:

/images/2020/vetur-on-complete/05.png

也可以这么写:

/images/2020/vetur-on-complete/06.png

第一种写法使用了 Vue.extend 方法,那么只需要标记出 script 使用 jsMode 来处理,TypeScript 就可以根据 Vue.extend 方法来获取到类型信息,进而给出代码补全。

但是在第二种写法中,单单凭借 script 中的代码,是不能推断出类型信息的,Vetur 是如何实现的呢?

直接 export default 时的实现

在这种情况下,Vetur 会讲 script 部分的代码进行预处理,预处理代码在:server/src/services/typescriptService/preprocess.ts

/images/2020/vetur-on-complete/07.png

这里注释写的挺清楚的,经过处理后,代码实际变成了这样:

/images/2020/vetur-on-complete/08.png

vue-editor-bridge 是 Vetur 中实现的一个工具库,目的就是给 export default 出的对象增加类型信息。

这样通过 __vueEditorBridge 增加类型信息后,TypeScript 就可以正确返回代码补全内容了。