本文为Varlet组件库源码主题阅读系列第七篇,读完本篇,可以了解到如何通过unplugin-vue-components插件来为你的组件库实现按需引入。
手动引入
前面的文章中我们介绍过Varlet
组件库的打包流程,最后会打包成几种格式,其中module
和commonjs
格式都不会把所有组件的代码打包到同一个文件,而是保留着各个组件的独立,每个组件都导出作为一个Vue
插件。
第一种按需使用的方法是我们手动导入某个组件并进行注册:
import {
createApp } from 'vue'
import {
Button } from '@varlet/ui'
import '@varlet/ui/es/button/style/index.js'
createApp().use(Button)
Button
组件并不是从它的自身目录中引入的,而是从一个统一的入口,@varlet/ui
包的package.json
中配置了两个导出入口:
按需引入,也可以理解成是tree shaking
,它依赖于ES6
模块,因为ESM
模块语法是静态的,和运行时无关,只能顶层出现,这就可以只分析导入和导出,不运行代码即可知道模块导出的哪些被使用了哪些没有,没有用到的就可以被删除。
所以想要支持按需引入那么必然使用的是module
入口,这个字段目前各种构建工具应该都是支持的,module
入口它是个统一的入口,这个文件中显然导出了所有组件,那么比如我们只导出Button
组件,其他没有用到的组件最终是不是不会被打包进去呢,实际上并没有这么简单,因为有的文件它会存在副作用,比如修改了原型链、设置了全局变量等,所以虽然没有显式的被使用,但是只要引入了该文件,副作用就生效了,所以不能被删除,要解决这个问题需要在package.json
中再配置一个sideEffects
字段,指明哪些文件是存在副作用的,没有指明的就是没有副作用的,那么构建工具就可以放心的删除了:
可以看到Varlet
告诉了构建工具,这些样式文件是有副作用的,不要给删除了,其他文件中没有用到的模块可以尽情删除。
自动引入
如果你觉得前面的手动引入比较麻烦,Varlet
也支持自动引入,这个实现依赖的是unplugin-vue-components插件,这个插件会扫描所有声明在模板中的组件,然后自动引入 组件逻辑
和 样式文件
并 注册组件
。
在Vite
中的配置方式:
import vue from '@vitejs/plugin-vue'
import components from 'unplugin-vue-components/vite'
import {
VarletUIResolver } from 'unplugin-vue-components/resolvers'
import {
defineConfig } from 'vite'
export default defineConfig({
plugins: [
vue(),
components({
resolvers: [VarletUIResolver()]
})
]
})
如果想要这个插件支持你的组件库,需要编写一个解析器,也就是类似上面的VarletUIResolver
,如果想要给更多人用就需要提个pr
,这个插件目前已经支持如下这些流行的组件库:
以VarletUIResolver
为例来看一下这个解析器都做了什么:
// unplugin-vue-components/src/core/resolvers/varlet-ui.ts
const varDirectives = ['Ripple', 'Lazy']
export function VarletUIResolver(options: VarletUIResolverOptions = {
}): ComponentResolver[] {
return [
{
type: 'component',
resolve: (name: string) => {
const {
autoImport = false } = options
if (autoImport && varFunctions.includes(name))
return getResolved(name, options)
if (name.startsWith('Var'))
return getResolved(name.slice(3), options)
},
},
{
type: 'directive',
resolve: (name: string) => {
const {
directives = true } = options
if (!directives)
return
if (!varDirectives.includes(name))
return
return getResolved(name, options)
},
},
]
}
执行VarletUIResolver
方法会返回一个数组,unplugin-vue-components
支持自动导入组件和指令,所以可以看到上面返回了两种解析方法,虽然目前我们没有看到unplugin-vue-components
的源码,但是我们可以猜想unplugin-vue-components
在模板中扫描到某个组件时会调用type
为component
的resolve
,扫描到指令时会调用type
为directive
的resolve
,如果解析成功,那么就会自动添加导入语句。
当扫描到的组件名以Var
开头或扫描到Varlet
的指令时,两个解析方法最后都会调用getResolved
方法:
// unplugin-vue-components/src/core/resolvers/varlet-ui.ts
export function getResolved(name: string, options: VarletUIResolverOptions): ComponentResolveResult {
const {
importStyle = 'css',
importCss = true,
importLess,
autoImport =