使用 unplugin-vue-components 按需引入组件(内附实现原理)

简介: 使用 unplugin-vue-components 按需引入组件(内附实现原理)

我们开发 Vue 项目时,一般会使用组件库进行开发,组件库有两种加载方式:全局引入按需引入

全局引入组件库,使用起来就非常方便,但是坏处就是产物体积大,对性能要求较高的项目不友好。

按需引入,可以减少体积大小,但需要通过以下方式加载组件:


import Button from 'ant-design-vue/lib/button';
import 'ant-design-vue/lib/button/style';
// 或者 ant-design-vue/lib/button/style/css 加载 css 文件

引入组件还需要引入样式,非常麻烦,因此有了 babel-plugin-import 来进行按需加载,加入这个插件后,可以省去 style 的引入。


import { Button } from 'ant-design-vue';

但这种仍然需要手动引入组件,而且还必须使用 babel

而  unplugin-vue-components 可以不需要手动引入组件,能够让开发者就像全局组件那样进行开发,但实际上又是按需引入,且不限制打包工具,不需要使用 babel


使用效果


Antd Vuevite 为例:


import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
export default {
  plugins: [
    Components({
      resolvers: [
          AntDesignVueResolver()
      ],
    }),
  ],
};

这样就能自动引入 Antd Vue 的组件,不需要手动 import 组件以及组件样式,使用起来就像全局组件一样,但这是按需自动引入,可以减少产物大小。


<template>
  <a-button>按钮</a-button>
</template>

这样直接使用即可

解析器


unplugin-vue-components 为主流的 UI 组件库提供了内置的支持,通过使用对应 UI 组件库的解析器(resolvers),就能自动引入对应的组件库组件及样式

解析器可以是一个函数或者是对象

以对象为例:


{
    type: 'component',
    resolve: (name: string) => {
        const map = {
            'Abutton': 'Button'
        }
        const path = `ant-design-vue/es`
        const name = map[name]
        return {
          // Button
          name,   
          // ant-design-vue/es
          from: path, 
          // ant-design-vue/es/button/style/css
          sideEffects: `ant-design-vue/es/${name.toLowerCase()}/style/css`, 
        }
      }
    },
  }
}

resolve 是一个函数,当遇到 a-button 时,就会调用该函数,入参是 AButton

函数需要返回一个对象,例如:


{
  name: 'Button',   
  from: 'ant-design-vue/es',  
  sideEffects: 'ant-design-vue/es/button/style/css',  
}

这样 unplugin-vue-components  就会加入以下代码:


import { Button } from 'ant-design-vue/es'
import 'ant-design-vue/es/button/style/css'

ant-design-vue/es/button/style/css 中,引入了 Button 组件相关的样式:


import '../../style/default.css';
import './index.css';

一般情况按需引入组件,需要把组件的样式也引入进来,这就是 sideEffects 的作用。


实现原理


可能大家会想到,将 Vue 处理成以下内容即可:


<template>
  <a-button>按钮</a-button>
</template>
<script setup>
import { Button as AButton } from 'ant-design-vue/es'
import 'ant-design-vue/es/button/style/css'
</script>

看起来可行,但其实不行,因为你 script 有普通的写法和 setup 写法,如果要做,得兼容两种情况,比较复杂。

其实 unplugin-vue-components 的实现非常简单。我们直接来看看 Vue 编译后的代码

1686404724870.png

可以看到,全局组件编译后会用 resolveComponent 包裹,该函数在 Vue 官网有说明,就是按名称找到已注册的全局组件。

unplugin-vue-components 只需要正则匹配 _resolveComponent,拿到入参 a-button,然后根据将名称标准化为 AButton,然后交给解析器,解析器会返回如下对象:


{
  name: 'Button',   
  from: 'ant-design-vue/es',  
  sideEffects: 'ant-design-vue/es/button/style/css',  
}

然后修改 Vue 编译后的代码(unplugin-vue-components 会在 Vue 插件之后执行

1686404700366.png

引入以下代码:


import { Button as __unplugin_components_0 } from 'ant-design-vue/es';
import 'ant-design-vue/es/button/style/css';
const _sfc_main = {}

并且_resolveComponent 替换成 __unplugin_components_0

这就将 a-button 组件的全局使用,转换成了按需引入的方式


局限性


unplugin-auto-import 看起来非常厉害,但它也有些局限性:

  • 不能作用于 JSX,因为插件只处理 template 模板的代码。不过JSX 则需要配合 unplugin-auto-import(用于自动引入变量)
  • 在 Vite 中 CSS 无法 tree shaking,不过这个是 Vite 的问题。但 JS 仍然是可以 tree shaking,相对于全局注册组件,对构建产物体积的优化还是非常可观的

总结


使用 unplugin-vue-components 可以非常方便地实现按需引入组件的功能,从而减小项目体积、加快项目加载速度,提升用户体验。

它通过正则匹配 Vue 的全局组件(编译后使用 _resolveComponent 包裹),然后引入组件并替换 _resolveComponent,因此这种方式,只适用于 template 模板编译后的代码,JSX 的自动引入,则需要配合 unplugin-auto-import(用于自动引入变量)

实际上, unplugin-vue-components 还能自动引入项目 components 目录下的组件,同时也支持自定义指定的自动按需引入,更多内容请查看  unplugin-vue-components文档

如果这篇文章对您有所帮助,可以点赞加收藏👍,您的鼓励是我创作路上的最大的动力。也可以关注我的公众号订阅后续的文章:Candy 的修仙秘籍(点击可跳转)

另外,想要米哈游/腾讯内推的,也可以关注公众号找我内推

目录
相关文章
|
5天前
|
JavaScript API
vue 批量自动引入并注册组件或路由等等
【10月更文挑战第12天】 vue 批量自动引入并注册组件或路由等等
|
5天前
|
JavaScript 前端开发 API
vue3中常用插件的使用方法:按需引入自定义组件,自动导入依赖包,自动生成路由,自动生成模拟数据
vue3中常用插件的使用方法:按需引入自定义组件,自动导入依赖包,自动生成路由,自动生成模拟数据
93 0
|
6天前
|
JavaScript
vue 组件中的 data 为什么是一个函数 ?
【10月更文挑战第8天】 在 Vue 组件中,`data` 被定义为一个函数而非普通对象,以确保每个组件实例拥有独立的数据空间,避免数据混乱。这种方式还支持数据的响应式更新、组件的继承与扩展,并有助于避免潜在问题,提升应用的可靠性和性能。
13 2
|
6天前
|
JavaScript 前端开发 UED
Vue 组件设计:构建生动多彩的树形结构组件
本文介绍了如何使用 Vue 构建一个功能强大的树形结构组件。该组件支持递归渲染节点及其子节点,提供了自定义节点颜色、文本和布局的功能。通过独特的样式处理不同层级的节点,展示出丰富的视觉效果。组件还支持动态布局和缩放,确保灵活的界面展示和用户体验。文章提供了详细的代码实现,包括 HTML、JavaScript 和 SCSS,帮助开发者快速集成和定制自己的树形结构组件。
27 0
Vue 组件设计:构建生动多彩的树形结构组件
|
7天前
|
JavaScript 搜索推荐
Vue 插槽全攻略:重塑组件灵活性
【10月更文挑战第7天】 Vue 的插槽(Slots)是一个强大的特性,用于增强组件的灵活性和可扩展性。插槽允许父组件向子组件传递内容,实现组件的复用和个性化展示。主要包括默认插槽、具名插槽和作用域插槽三种类型,分别适用于不同场景。通过插槽,可以提高组件的复用性、实现灵活的布局,并促进团队协作。
16 1
|
8天前
|
JavaScript
vue 函数化组件
【10月更文挑战第1天】 Vue.js 的函数化组件通过设置 `functional: true`,使其无状态和无实例,从而减少渲染开销。通过 `render` 函数的 `context` 参数传递数据。示例中,`smart-item` 组件根据 `data.type` 动态选择并渲染 `ImgItem`、`VideoItem` 或 `TextItem` 组件。根实例 `app` 通过按钮切换不同类型的组件数据。函数化组件适用于程序化选择组件和操作传递数据的场景。
|
12天前
|
前端开发 JavaScript API
Vue3商品SKU多规格编辑组件
Vue3商品SKU多规格编辑组件
34 5
|
9天前
|
JavaScript 前端开发
VUE学习三:双向绑定指令(v-mode)、组件化开发(全局组件/局部组卷/组件通信)、组件化高级(slot插槽使用)
这篇文章是关于Vue.js框架中的v-model指令和组件化开发的详细教程,涵盖了从基础使用到高级功能的多个方面。
19 1
|
9天前
|
JavaScript 程序员 开发者
你真的完全了解vue组件的概念吗?
【10月更文挑战第7天】你真的完全了解vue组件的概念吗?
|
11天前
|
缓存 JavaScript UED
vue的动态组件 keep-alive
【10月更文挑战第6天】
27 3