{T}

组件库统一前缀与类型别名:custom resolver 前置准备、VP 组件命名与 type 导出收敛

概述

想让组件库支持自动导入,前提不是先写 resolver,而是先让组件命名具备稳定的可识别模式。这一节重点不是立刻把 unplugin-vue-components 自定义 resolver 写出来,而是先做两类“命名收敛”:给组件统一前缀(如 VP),给类型建立统一别名和语义化重命名。命名规范是自动导入的前置工程,没有它,resolver 很难稳定区分“这是组件库组件”还是普通标签。

学习目标

  • 理解自定义 resolver 依赖稳定命名模式,而不是“组件很多”
  • 给所有组件建立统一前缀 VP,建立长期公共命名体系
  • 处理已带 V 历史前缀组件的去重,再拼新前缀
  • 组件名前缀化后,类型名也必须同步统一,避免 API 语义割裂
  • 用脚本读取类型文件、正则匹配真实导出项并生成带前缀别名
  • 筛选真正值得公开的类型,并做语义化重命名

一、自动导入的前提是先有稳定可识别的命名模式

unplugin-vue-components 官方自定义 resolver 的典型写法,就是判断组件名前缀再决定从哪个包导入。这意味着 resolver 的工作前提是组件名必须有模式,而不是杂乱无章。如果库里 VFormIconPickerHeaderMenuCollapseDescription 并存,resolver 很难写得优雅稳定。先统一命名,再写 resolver,这是给下一节自动导入铺路。

text
resolver 最适合识别:
  VPButton
  VPForm
  VPTable

不适合识别:
  名字风格完全不统一的组件集合

二、给所有组件建立统一前缀

前面课程已处理过 headermenu 这类保留字段冲突,这一节更进一步:不再只处理冲突项,而是直接建立全局前缀 VP。好处至少有三:组件名风格统一、resolver 更容易写、和宿主项目或其他 UI 库组件更容易区分。

js
const componentPrefix = 'VP'
let componentName = `${componentPrefix}${baseName}`

统一前缀是组件库级规范,最好早做。这里的 VP 可理解为 “View Plus”,也可换成更稳定的品牌前缀。

统一前缀还有一层实际收益:它能规避 eslint-plugin-vue 对保留标签名的敏感校验。

即便不是为了自动导入,前缀化也能减少组件名与 HTML 原生标签、其他 UI 库冲突的概率。组件库公共命名一旦统一,宿主接入和类型提示都会稳定很多。

三、对已带 V 历史前缀的组件先做去重

有些组件本身已带 V(如 VFormVTable),脚本若机械再拼 VP,会变成 VPVFormVPVTable,既不美观也不利理解。需要折中:对这类已带前缀的组件先 replace(/^V/, ''),再统一拼组件库前缀。这类“前缀去重”只该存在于自动化脚本里,不要让人反复手改文件名。

js
const componentPrefix = 'VP'
let componentName = baseName

if (needChangeName.includes(baseName)) {
  componentName = baseName.replace(/^V/, '')
}

componentName = `${componentPrefix}${componentName}`

四、组件名统一后,类型名也必须同步统一

不只改组件名,类型也要改。对使用者来说最终看到的是一整套 API:组件名、props 类型、事件类型、schema 类型。如果组件已经前缀化,但类型仍停留在 FormSchema / MenuSelectType,用户会很难判断哪些类型是这个库真正公开的、哪些只是内部实现。公共 API 的一致性不只体现在组件标签名,类型命名越语义化,自动导入、文档生成、IDE 提示越清晰。

text
组件名统一
  -> 类型名也应统一或至少做别名映射

五、类型导出要读取文件内容并用正则匹配真实导出项

组件导出只需收集文件名,类型导出不能只看文件名——真正要公开的是文件里具体哪些 interfacetypeenum。脚本要读取类型文件内容,用正则匹配出导出类型名,再生成 export { Xxx as VPXxx } 别名导出。这一步本质是把“类型文件”从内部模块提升为外部公共 API 映射层。一旦进入“读源码内容 + 正则匹配导出项”,脚本就不再是简单的路径处理脚本。

text
读取类型文件
  -> 匹配 export interface / type / enum
  -> 收集导出名
  -> 生成带前缀别名

六、不是所有类型都值得公开导出

不要无脑导出每个 types.ts 里的东西,而要逐个判断:这个类型是不是外部会用到?是不是只在内部实现中短暂存在?它的命名是否足够语义化?组件库一旦把类型导出出去,就要长期维护兼容性。公共类型应当是“用户会直接使用、并且你愿意长期维护”的那部分。

text
可以导出
  !=
值得成为公共类型 API

七、类型语义化重命名比机械加前缀更重要

emitSelectType 改成 menuSelectEvent,比单纯前缀化更有价值:前缀解决归属问题,语义化命名解决可读性和可理解性。对组件库使用者来说,最重要的不是“这是谁家的类型”,而是“这个类型到底表示什么”。这一步说明组件库开始从“搬运现有代码”转向“重新设计公共 API”。

text
机械命名
  emitSelectType

语义化命名
  menuSelectEvent

常见问题

问题原因解决方案
想写 custom resolver,但组件名没有统一规律组件库命名风格不统一,resolver 很难稳定识别先统一组件前缀,再写 resolver
给已有 VForm 再加 VP 后变成 VPVForm脚本没有处理已有前缀组件先去重旧前缀,再统一拼新前缀
组件名改了,但类型名还是旧名字只改了组件导出,没同步改类型导出体系给类型也建立统一别名映射
自动化脚本把所有类型都导出,公共 API 很乱没有筛选哪些类型值得公开逐个判断类型用途,保留真正公共的类型 API
类型名导出了但很难理解类型名过于贴近内部实现历史命名做语义化重命名,例如 menuSelectEvent

延伸阅读