一个关于 [unplugin-vue-components] 的错误提示的解决办法

·  阅读 417
一个关于 [unplugin-vue-components] 的错误提示的解决办法

记一次解决问题的步骤。

在插件 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.
复制代码

image.png

开门见山,首先说解决办法

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
}
复制代码

点开方法看看,果然实际上也是,但我注意到,如果 directoryAsNamespacetrue ,那么它会利用给 name 修饰成 文件夹-文件名 的方式。

那我肯定同名组件是放在不同名的文件夹里的,也就是说只要设置 directoryAsNamespace 设置为 true 就完事了。

终。

不过没仔细看源码,为啥它默认不为 true 啊?

分类:
前端
标签:
分类:
前端
标签: