组件的使用
构建、测试、发布都完成之后,最后一个问题才真正落到使用者身上:
别人要怎样把你的组件库接进项目?
这个问题看起来只是“怎么 import”,但实际上它决定了组件库的使用门槛、包体积、类型体验和团队协作成本。
所以“组件的使用”本质上是在回答:
- 你的库支持哪些接入方式
- 不同接入方式会带来什么代价
- 你的组件库应该为使用者提供怎样的消费体验
先看常见现象
很多熟悉的组件库,安装命令看起来都差不多:
# Vue 2 历史项目(EOL)
npm i element-ui -S
# Vue 3 主线项目
npm i element-plus -S
npm i naive-ui -S但“安装方式相似”,并不等于“消费方式相同”。
绝大多数组件库至少会考虑三种消费模式:
- 完整引入
- 手动按需引入
- 自动导入
这三种方式没有绝对谁最好,核心是权衡:
- 使用成本
- 打包体积
- 工具链依赖
- 团队可控性
完整引入
以 Element Plus 为例,完整引入通常是这样:
import ElementPlus from 'element-plus'
import { createApp } from 'vue'
import App from './App.vue'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')从这个用法可以反推很多设计信息:
- 默认导出是一个 Vue Plugin
- 插件会在
app.use()时批量注册组件和相关能力 - 样式通常也需要整体引入
这类接入方式的优点很明显:
- 上手快
- 对新手友好
- 文档成本低
但代价也很明显:
- 不够按需
- 容易引入不需要的组件和样式
为什么完整引入通常要做成插件
因为这样可以把“批量注册”统一收敛到一个 install(app) 入口。
以 element-plus 的安装器思路为例,它的核心就是:
- 聚合所有组件和插件
- 在
install中统一app.use - 避免重复注册
这类设计很适合“全量接入”的场景,也方便配合全局配置能力。
全局引入的一个现实问题:类型提示
如果你用的是全局注册组件,IDE 并不会天然知道这些组件已经存在。
所以很多库还会要求在 tsconfig.json 中补充类型入口,例如:
{
"compilerOptions": {
"types": ["element-plus/global"]
}
}这说明组件库的“使用体验”不只是运行时可用,还包括编辑器层的智能提示能否跟上。
手动按需引入
另一种常见方式是:
<script>
import { ElButton } from 'element-plus'
export default {
components: { ElButton },
}
</script>
<template>
<ElButton>I am ElButton</ElButton>
</template>这类方式的目标很明确:
- 只引入需要的组件
- 配合 Tree Shaking 减少最终包体积
但这里又会出现一个现实问题:
组件引进来了,样式怎么办?
为什么按需引入经常要配合编译插件
像 Element Plus 这种库,通常 js 和 css 是分离的。
所以你只是写了:
import { ElButton } from 'element-plus'并不代表样式会自动跟进来。
这时像 unplugin-element-plus 这样的工具,本质上就是做一件事:
- 分析你的导入
- 在编译时自动补上对应样式导入
大致效果类似:
import { ElButton } from 'element-plus'
// 编译后补上
import 'element-plus/es/components/button/style/css'所以这类“按需样式注入”本质上不是运行时魔法,而是编译期源码改写。
自动导入
更进一步的方案,是连组件导入语句都不让你手写。
例如:
import AutoImport from 'unplugin-auto-import/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
})它之所以能做到“自动导入”,本质上还是编译阶段在做事:
- 扫描模板和脚本里未显式导入的组件/API
- 根据 resolver 推断导入来源
- 自动把导入语句注入到源代码或编译结果里
所以“自动导入”本质上并不是框架层功能,而是工具链帮你维护 import。
三种方式怎么选
完整引入
适合:
- 内部后台系统
- 组件使用面很广
- 更重视接入速度
手动按需引入
适合:
- 希望更明确控制依赖边界
- 比较在意最终打包体积
- 不想过度依赖自动导入工具
自动导入
适合:
- 团队已经接受编译器介入程度更高的开发方式
- 组件命名规范稳定
- 更看重开发效率和模板整洁度
自动导入为什么不是纯收益
自动导入的体验确实很好,但要有心理预期:
- 它更依赖构建工具和插件生态
- 项目迁移成本更高
- 对新成员来说,代码表面可读性和真实依赖关系之间会多一层间接性
也就是说,它是在“开发方便”和“依赖显式”之间做取舍。
从组件库作者视角,应该提供什么
如果你在设计自己的组件库,比较务实的做法通常是:
- 至少提供完整引入能力
- 尽量支持手动按需引入
- 如有余力,再提供自动导入 resolver
这样兼容面最广,也更利于不同团队按自己的工程习惯接入。
下一代组件库的一种思路
像 shadcn/ui 这类思路,和传统“发布完整组件包”不太一样。
它更偏向:
- 提供无样式或弱样式的 headless 能力
- 借助
tailwindcss等方案让样式留在业务项目内 - 通过 CLI 或配置把组件源码同步进项目
这条路线的好处是:
- 自定义空间极大
- 不容易被库本身的样式和结构强绑定
- 更适合需要深度定制设计系统的团队
但代价也很清楚:
- 使用者需要更强工程能力
- 不再是“装包即用”
一句话理解
组件的“使用方式”并不是附属问题,它本质上决定了你的组件库到底更像一个“快速上手的产品”,还是一个“高度可控的工程能力”。
总结
| 方式 | 优点 | 代价 |
|---|---|---|
| 完整引入 | 上手快、接入简单 | 体积和样式通常更重 |
| 手动按需引入 | 边界清晰、体积更可控 | 需要手动维护导入与样式 |
| 自动导入 | 开发体验好、代码更简洁 | 更依赖工具链和插件生态 |
如果你想做好自己的组件库,不能只关注“怎么写组件”,还要认真设计“别人怎么消费你的组件”。