unplugin-vue-components 实现组件的按需自动导入,消除手动 import 的重复工作。本文讲解其配置方式、命名空间策略,以及与 Element Plus、Naive UI 等 UI 库的 Resolver 集成。
<!-- 传统:手动导入 -->
<script setup>
import UserCard from '@/components/UserCard.vue'
import AppHeader from '@/components/AppHeader.vue'
</script>
<!-- 自动导入:直接使用 -->
<template>
<AppHeader />
<UserCard />
</template>pnpm add -D unplugin-vue-components// vite.config.ts
import Components from 'unplugin-vue-components/vite'
export default defineConfig({
plugins: [
vue(),
Components({
dirs: ['src/components'],
extensions: ['vue'],
dts: 'components.d.ts',
directoryAsNamespace: false,
collapseSamePrefixes: false,
}),
],
})| 配置项 | 说明 | 默认值 |
|---|---|---|
dirs | 扫描目录 | ['src/components'] |
extensions | 文件扩展名 | ['vue'] |
dts | 类型声明输出路径 | 'components.d.ts' |
directoryAsNamespace | 目录名作为组件前缀 | false |
collapseSamePrefixes | 折叠重复前缀 | false |
resolvers | UI 库解析器 | [] |
src/components/
├── UserCard.vue → <UserCard />
├── AppHeader.vue → <AppHeader />
└── base/
└── Button.vue → <Button />Components({
directoryAsNamespace: true,
})src/components/
├── UserCard.vue → <UserCard />
└── base/
└── Button.vue → <BaseButton />避免不同目录下同名组件冲突。
pnpm add element-plusimport { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
Components({
resolvers: [ElementPlusResolver()],
})import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
Components({
resolvers: [NaiveUiResolver()],
})Components({
resolvers: [
(componentName) => {
if (componentName.startsWith('My')) {
return {
name: componentName,
from: `@/my-lib/${componentName}`,
}
}
},
],
})插件自动生成,为所有可自动导入的组件提供类型:
// components.d.ts(自动生成)
declare module 'vue' {
export interface GlobalComponents {
UserCard: typeof import('./src/components/UserCard.vue')['default']
AppHeader: typeof import('./src/components/AppHeader.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
}
}{
"include": ["components.d.ts"]
}Q: 自动导入的组件在单元测试中如何识别?
在测试配置(如 vitest.config.ts)中也引入 Components 插件,或在测试文件中手动 import 被测组件。
Q: 如何排除某些组件不自动注册?
使用 exclude 配置项,或将组件放在扫描目录之外。通常 layouts/、composables/ 目录不应被扫描。
Q: 组件名冲突如何处理?
启用 directoryAsNamespace: true,用目录名作为前缀区分。或调整 dirs 扫描顺序,先扫描的目录优先级更高。