Skip to content

组件的使用

构建、测试、发布都完成之后,最后一个问题才真正落到使用者身上:

别人要怎样把你的组件库接进项目?

这个问题看起来只是“怎么 import”,但实际上它决定了组件库的使用门槛、包体积、类型体验和团队协作成本。

所以“组件的使用”本质上是在回答:

  • 你的库支持哪些接入方式
  • 不同接入方式会带来什么代价
  • 你的组件库应该为使用者提供怎样的消费体验

先看常见现象

很多熟悉的组件库,安装命令看起来都差不多:

bash
# Vue 2 历史项目(EOL)
npm i element-ui -S

# Vue 3 主线项目
npm i element-plus -S
npm i naive-ui -S

但“安装方式相似”,并不等于“消费方式相同”。

绝大多数组件库至少会考虑三种消费模式:

  1. 完整引入
  2. 手动按需引入
  3. 自动导入

这三种方式没有绝对谁最好,核心是权衡:

  • 使用成本
  • 打包体积
  • 工具链依赖
  • 团队可控性

完整引入

Element Plus 为例,完整引入通常是这样:

js
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 中补充类型入口,例如:

json
{
  "compilerOptions": {
    "types": ["element-plus/global"]
  }
}

这说明组件库的“使用体验”不只是运行时可用,还包括编辑器层的智能提示能否跟上。

手动按需引入

另一种常见方式是:

vue
<script>
import { ElButton } from 'element-plus'

export default {
  components: { ElButton },
}
</script>

<template>
  <ElButton>I am ElButton</ElButton>
</template>

这类方式的目标很明确:

  • 只引入需要的组件
  • 配合 Tree Shaking 减少最终包体积

但这里又会出现一个现实问题:

组件引进来了,样式怎么办?

为什么按需引入经常要配合编译插件

Element Plus 这种库,通常 jscss 是分离的。

所以你只是写了:

js
import { ElButton } from 'element-plus'

并不代表样式会自动跟进来。

这时像 unplugin-element-plus 这样的工具,本质上就是做一件事:

  • 分析你的导入
  • 在编译时自动补上对应样式导入

大致效果类似:

js
import { ElButton } from 'element-plus'

// 编译后补上
import 'element-plus/es/components/button/style/css'

所以这类“按需样式注入”本质上不是运行时魔法,而是编译期源码改写。

自动导入

更进一步的方案,是连组件导入语句都不让你手写。

例如:

ts
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

三种方式怎么选

完整引入

适合:

  • 内部后台系统
  • 组件使用面很广
  • 更重视接入速度

手动按需引入

适合:

  • 希望更明确控制依赖边界
  • 比较在意最终打包体积
  • 不想过度依赖自动导入工具

自动导入

适合:

  • 团队已经接受编译器介入程度更高的开发方式
  • 组件命名规范稳定
  • 更看重开发效率和模板整洁度

自动导入为什么不是纯收益

自动导入的体验确实很好,但要有心理预期:

  • 它更依赖构建工具和插件生态
  • 项目迁移成本更高
  • 对新成员来说,代码表面可读性和真实依赖关系之间会多一层间接性

也就是说,它是在“开发方便”和“依赖显式”之间做取舍。

从组件库作者视角,应该提供什么

如果你在设计自己的组件库,比较务实的做法通常是:

  1. 至少提供完整引入能力
  2. 尽量支持手动按需引入
  3. 如有余力,再提供自动导入 resolver

这样兼容面最广,也更利于不同团队按自己的工程习惯接入。

下一代组件库的一种思路

shadcn/ui 这类思路,和传统“发布完整组件包”不太一样。

它更偏向:

  • 提供无样式或弱样式的 headless 能力
  • 借助 tailwindcss 等方案让样式留在业务项目内
  • 通过 CLI 或配置把组件源码同步进项目

这条路线的好处是:

  • 自定义空间极大
  • 不容易被库本身的样式和结构强绑定
  • 更适合需要深度定制设计系统的团队

但代价也很清楚:

  • 使用者需要更强工程能力
  • 不再是“装包即用”

一句话理解

组件的“使用方式”并不是附属问题,它本质上决定了你的组件库到底更像一个“快速上手的产品”,还是一个“高度可控的工程能力”。

总结

方式优点代价
完整引入上手快、接入简单体积和样式通常更重
手动按需引入边界清晰、体积更可控需要手动维护导入与样式
自动导入开发体验好、代码更简洁更依赖工具链和插件生态

如果你想做好自己的组件库,不能只关注“怎么写组件”,还要认真设计“别人怎么消费你的组件”。

Released under the CC BY-NC-SA 4.0 License.