记一次解决问题的步骤。
在插件 unplugin-vue-components
(github, npm) 的使用中,你可能会遇到类似这样的提示。
[unplugin-vue-components] component "Table"(/home/xmo/code/fasoso-management/src/components/Data/Table.vue) has naming conflicts with other components, ignored.
[unplugin-vue-components] component "Search"(/home/xmo/code/fasoso-management/src/components/Template/Search.vue) has naming conflicts with other components, ignored.
[unplugin-vue-components] component "Table"(/home/xmo/code/fasoso-management/src/components/Template/Table.vue) has naming conflicts with other components, ignored.
[unplugin-vue-components] component "Search"(/home/xmo/code/fasoso-management/src/components/User/Search.vue) has naming conflicts with other components, ignored.
[unplugin-vue-components] component "Table"(/home/xmo/code/fasoso-management/src/components/User/Table.vue) has naming conflicts with other components, ignored.
开门见山,首先说解决办法
import Components from "unplugin-vue-components/vite";
import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
export default defineConfig({
plugins: [
...
Components({
resolvers: [AntDesignVueResolver()],
// 加上下面这一行作为配置项即可
directoryAsNamespace: true,
}),
...
]
)}
我是直接看源码的,但其实直接看 github 的配置项也行。
在 unplugin-vue-components
的 github 的配置文档中是这么写的
Components({
// relative paths to the directory to search for components.
dirs: ['src/components'],
// valid file extensions for components.
extensions: ['vue'],
// search for subdirectories
deep: true,
// resolvers for custom components
resolvers: [],
// generate `components.d.ts` global declarations,
// also accepts a path for custom filename
dts: false,
// Allow subdirectories as namespace prefix for components.
// 允许子目录作为组件的命名空间前缀。
directoryAsNamespace: false,
// Subdirectory paths for ignoring namespace prefixes
// works when `directoryAsNamespace: true`
globalNamespaces: [],
// filters for transforming targets
include: [/\.vue$/, /\.vue\?vue/],
exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/],
})
其实警告说得蛮明白,命名冲突。然而为什么会命名冲突呢?
我一开始以为是因为 Vue3
组件的命名重复了,因为使用了 setup
语法糖,所以同名文件的组件 export
的组件名称是重复的。
所以我在 setup
之外又写了一个 script
单独用来给组件命名。
<script lang="ts">
/** 仅用于组件命名,不做额外行为 */
export default {
name: "UserSearch",
};
</script>
<template>
...
</template>
<script lang="ts" setup>
...
</script>
<style lang="scss" scoped>
...
</style>
结果发现鸟用没有,还是报警告,那我肯定怀疑是因为它看的是组件的文件名而不是组件 export
的名称了。为了证明我的想法,我看了一下源码,果然,
// /src/core/context.ts > Context > updateComponentNameMap > forEach() callback
const name = pascalCase(getNameFromFilePath(path, this.options))
if (this._componentNameMap[name] && !this.options.allowOverrides) {
// eslint-disable-next-line no-console
console.warn(`[unplugin-vue-components] component "${name}"(${path}) has naming conflicts with other components, ignored.`)
return
}
这里是 getNameFormFilePath
,从名字上来看就是通过文件名来获取名称。
// /src/core/utils.ts > getNameFromFilePath
export function getNameFromFilePath(filePath: string, options: ResolvedOptions): string {
const { resolvedDirs, directoryAsNamespace, globalNamespaces } = options
const parsedFilePath = parse(slash(filePath))
let strippedPath = ''
// remove include directories from filepath
for (const dir of resolvedDirs) {
if (parsedFilePath.dir.startsWith(dir)) {
strippedPath = parsedFilePath.dir.slice(dir.length)
break
}
}
let folders = strippedPath.slice(1).split('/').filter(Boolean)
let filename = parsedFilePath.name
// set parent directory as filename if it is index
if (filename === 'index' && !directoryAsNamespace) {
filename = `${folders.slice(-1)[0]}`
return filename
}
if (directoryAsNamespace) {
// remove namesspaces from folder names
if (globalNamespaces.some((name: string) => folders.includes(name)))
folders = folders.filter(f => !globalNamespaces.includes(f))
if (filename.toLowerCase() === 'index')
filename = ''
if (!isEmpty(folders)) {
// add folders to filename
filename = [...folders, filename].filter(Boolean).join('-')
}
return filename
}
return filename
}
点开方法看看,果然实际上也是,但我注意到,如果 directoryAsNamespace
为 true
,那么它会利用给 name
修饰成 文件夹-文件名
的方式。
那我肯定同名组件是放在不同名的文件夹里的,也就是说只要设置 directoryAsNamespace
设置为 true
就完事了。
终。
不过没仔细看源码,为啥它默认不为 true
啊?