Skip to content

关于组件引入问题

关于组件的引入问题,有那么几种选择:

  • 全局引入

  • 自动引入

  • 手动按需引入

全局(自动)引入组件

我们需要理解一个概念是,这里的全局引入是指代码层面的,而不是编译器层面的行为。也就是说,在 vite 打包的时候,在 vue 文件夹中全局注册的组件将会被处理,之后在处理 vue 文件的时候,他们不使用 import 也能正确的被编译。

这种情况很类似于自动导入。他们的共同点,也是共同的缺点,就是他们抛弃了类型声明,也就是语法提示。需要不够优雅的在 tsconfig 里配置类型声明,或者生产出一个 auto-imports.d.ts 之类的文件。

语法提示这个东西,是建立在编译器之上的。这在 vsc 中表现为相关语言的插件,如 ts-plugins, vue-official。过去,我们只有手动引入,引入的过程中,很"顺便"的就出现了类型声明,因为在这里,类型引入和实际代码的引入是强耦合的。对于一门带有类型的编程语言来讲,这是一个天然的优势。

在最初的时候,js 没有自己的类型系统,被诟病为天生的缺陷,我们使用 ts 对它进行类型支持,并且 ts 不负使命,为 js 提供了具有严谨数学逻辑的类型系统——虽然看起来不是那么好用,但它却承担起了大型工程的救命稻草。模块与类型在编译器层面进行了强耦合。现在,我们又想要拿到模块的自动引入——这种语法糖行为,会导致类型层面的丢失。模块被自动引入,但是类型却没有被自动引入。这个问题的本质就在于这种强耦合的丢失。

全局引入的插件为了补救,提供了 全局的.d.ts 声明来解决这种问题。这本质上只是一种补救方法,而不是重新做到让模块与类型的强耦合。

思考一下,对于一个在代码中引入的插件,他们提供的模块引入发生在编译时,也就是 vite 打包的时候。在我们编写代码的过程中,类型引入的语法支持本质上是编译器做的事,是高于代码本身的层面的。除非插件本身不在局限于代码,而是变为编译器的插件,告诉编译器“嘿,我的代码凡是 vue 模块,都可以引入一些组件,而且不需要 import ,你提供语法提示即可,不需要检查合理性!”……我们在编写过程中自动的引入类型声明,否则它对于类型的引入无计可施,只能通过生产.d.ts 代码来告诉编译器自己用到了这个模块。相比于直接告诉 ts 编译器在哪里直接导入并提供语法提示,这样做,显然是不够优雅的。

我对他们三者的态度

  • 全局引入,是整个组件库的代码引入,加一个 .d.ts 的全局类型文件声明。前面指出,这个生产出来的类型文件,本身只是一种补救方案,不够优雅。但是对于全局性质的引入,将它作为全局类型文件,似乎也没有什么不妥。虽然丢失了模块的强耦合,但他们本身就是 src 下的工程的全局性质的模块,加一个全局类型文件,倒没什么影响。对于全局引入,主要的缺点还是在于,它的全部引入不如按需引入打包后的体积小。
  • 按需引入,这种不借助任何奇技淫巧,老老实实用到的时候引,按需引。这是我个人极力推荐的做法。也许你会认为用到的时候一个个import会很麻烦,但是这完全是可以通过 vsc 插件改善的,并且不会产生什么副作用,即导致模块和类型强耦合性断裂。
  • 自动引入。这种情况会产生 .d.ts,作用于全局。它是按需引的,而且有类型提示。虽然它其实不会产生污染和任何 bug,但是它本质上还是一种补救方案式的做法。是否使用,就仁者见仁了。不得不承认,它能够提供最好的开发体验、最优的代码产物,但是需要使用者明白自己在干什么,团队开发则需要考虑每个人对项目的熟悉成本(新成员会看不懂这是怎么做到的、为什么会产生这些冗余的类型声明文件)。