unplugin-vue-components是怎样做到自动引入组件的

204 阅读4分钟

0.

自从使用了element-plus之后就开始使用element官网推荐的unplugin-vue-components插件做组件导入,一直疑惑他到底怎么做到的组件自动导入的,最近公司裁了一部分ui/ux,ui/ux人手告急,所以公司的产品、项目、前端和后端准备做自己的套ui,既然要做这个ui那我就想是不是要做一下类型element自动导入组件的功能,所以翻了翻unplugin-vue-components源码,哎呦我去,看不懂,然后就注意到这个文件夹,唉这块不是他兼容的所有ui插件的集合和名字吗,进去看一眼;

image.png

1.

个人习惯每次看别人的代码先找抛出函数搂一眼,因为参考的element-plus的做,自然而然的打开了element-plus,全局就只有一个抛出函数叫

image.png 额,这返回的是一个list,每一项里面有两个key,一个type,一个resolve,没有用别的,type两个值一个是component(代表的组件),做的是组件的自动导入,比如element-plus的el-table的自动导入,另一个是directive(代表的指令),做的指令的自动导入,其次是另一个key(resolve),他接受的是一个函数,那他的重点就是返回值了,那看看ComponentResolver类型是个啥,

50185f1fda313cdc6695e01fc042a7d.png 通过这个图看到type就是上面说的两个值,没有其他的了,那主要就看ComponentResolverFunction这个返回值了

3fe28e700b0276d2a8cc0d9d21b5608.png 一看这个返回的类型还挺多,看了一眼只有ComponentInfo类型挺有用,点过去看看

1698043143150.jpg 返回值有个可选的sideEffects值,翻了翻element-plus的文件看到了他

060a37ddf3a121993f5fb549c7ede87.png

81944c0610aecb7a46b83dd4da1ae67.png 他原来做的是css的引入,那看看还有没有其他的参数,毕竟ComponentInfo类型extends了ImportInfo类型

3482f9fd80af355825a2b1b22649e2b.png 现在能总结出他有四个key,三个可选一个必选,然后回来看这个

1698043462292.jpg 由此看见from是组件的引用路径,sideEffects是做css引用路径,name和as啥功能暂不确定那动手写一下

2.

0.创建项目

image.png

因为只是演示,就新建了个项目,删除现有所有组件和代码

1.

下载依赖

> npx pnpm i

2.

然后在components文件夹下创建一个公共组件

1698043462292.jpg 在App组件下使用这个Demonstration组件

image.png 注意这里没有引用,下面开始写unplugin-vue-components下的resolver插件

3.

因为是新项目,先下载一下unplugin-vue-components插件

> npx pnpm install -D unplugin-vue-components

修改vite.config.ts代码成这样

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import Components from "unplugin-vue-components/vite";
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),
    Components({
      resolvers:[
        autoComplete()
      ],
      dts: true,
    })
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

function autoComplete(){

}

下面开始写这个插件了

4.

写插件,看到上面代码可以看到这个插件的主要逻辑在autoComplete函数体内,他的返回值上面也说到了下面开始直接把返回值加上,因为只考虑组件的自动引入autoComplete函数写成这样

function autoComplete(){
  return {
      type: "component",
      resolver(name:string){
        return{
          from:`@/components/${name}`
        }
      }
    }

}

然后启动项目,好像出来了

image.png 然后兴冲冲的去邀功,然后被组长怼回来了,因为我们现有封装好的组件不是这样的场景,他是这样的

image.png 每个文件夹下不止一个组件,也没有像演示的项目中的那种有index入口,要在修改最少的代码下完成这个功能,然后我把演示代码的components文件夹下加了一个index文件,这个文件中的代码是这样的

import Demonstration from "./Demonstration/index.vue"
export {
  Demonstration
}

然后上面说的name属性就能用上了,因为是同一出口抛出,那autoComplete函数代码就得这么写了

function autoComplete(){
  return {
      type: "component",
      resolver(name:string){
        return{
          name:name,
          from:`@/components`
        }
      }
    }
}

看看项目什么样

image.png 不受影响,我又去找组长邀功了,还是被怼回来了,因为使用的时候要加统一前缀,那回来改代码

function autoComplete(){
  return {
      type: "component",
      resolve(name:string){
        return{
          name:name.replace(/^Ds/,''),
          from:`@/components`
        }
      }
    }
}

完美

3.

第一次写这个文档,写的不好不要见怪,谢谢