组件库别名导出自动化:VP 组件前缀、类型正则提取与 custom resolver 铺垫
概述
这一节是 custom resolver 最关键的前置工程落地:给组件建立统一前缀、给类型建立统一别名,让自动化脚本不只会导出组件,还能导出“更像公共 API”的命名体系。难点在于类型导出要读取文件内容、先用正则剥离注释再匹配真实导出项,把内部类型模块整理成对外可消费的类型接口层。统一 VP 前缀本质上不是命名偏好,而是在为下一节自动导入建立稳定可识别模式。
学习目标
- 理解统一前缀是 custom resolver 的前置工程,而非后置优化
- 给所有组件统一前缀并建立长期公共命名体系
- 处理历史
V前缀组件去重,重建统一前缀 - 组件前缀统一后,类型前缀也要同步,避免 API 语义割裂
- 用脚本读取类型文件内容、先剥离注释再正则匹配真实导出项
- 迭代正则覆盖泛型/别名等真实写法,公共类型先筛选再语义化
一、custom resolver 依赖稳定前缀模式
unplugin-vue-components 官方 README 明确支持 custom resolver,最典型写法就是“识别组件名前缀,再决定从哪个包导入”。如果库里 IconPicker、Header、VForm、CollapseDescription 混用,自定义 resolver 很难优雅实现。先统一前缀,实际上是在为下一节自动导入做地基。
custom resolver 更喜欢:
VPForm
VPTable
VPHeader
而不是:
组件名风格完全混杂的一组导出二、统一前缀建立长期公共命名体系
前面已处理 header、menu 这类保留字段冲突,这一节做更彻底的一步:给所有公共组件统一加前缀 VP。收益远大于“绕过规则报错”——宿主项目更容易区分组件来源、自定义 resolver 更容易写、类型命名和文档命名也更容易同步。前缀一旦定下,后续新增组件都应遵循。
const componentPrefix = 'VP'
let componentName = `${componentPrefix}${baseName}`补充一点:eslint-plugin-vue 对保留组件名的敏感校验只是推动统一前缀的因素之一,更深层原因是组件库公共命名体系必须统一。
前缀化的价值不止于绕开规则报错,更在于让组件、类型、文档共享同一套命名语言。组件库和宿主一旦共用这套命名,接入成本会显著下降。
三、历史 V 前缀组件先去重再重建新前缀
有些组件原本就叫 VForm、VTable,脚本无脑加前缀会变成 VPVForm、VPVTable,让公共 API 失去一致性。脚本要加一层去重逻辑:若命中已带前缀的组件,先把旧前缀去掉,再统一拼新库前缀。这一步本质是在“清洗历史命名债务”,由自动化脚本统一应用规则最合适。
let componentName = baseName
if (needChangeName.includes(baseName)) {
componentName = baseName.replace(/^V/, '')
}
componentName = `${componentPrefix}${componentName}`四、组件前缀统一后,类型前缀也要同步
不是只改组件导出名,还要继续整理类型导出名。对使用者来说,最终接触到一整套 API:组件名、props 类型、schema 类型、事件类型。如果组件已是 VPForm、VPTable,但类型仍叫 FormSchema、MenuSelectType,认知上就很割裂。公共类型应该跟公共组件名站在同一命名体系里。
组件名统一
-> VPForm
类型名也应该统一
-> VPFormSchema五、类型导出要先读文件内容、用正则匹配真实导出项
组件导出较简单(文件名通常对应组件名),类型导出复杂很多:一个 types.ts 可能导出多个 interface、type、enum,只看文件名没法知道该给哪些类型建别名。脚本要读取类型文件内容,用正则匹配导出项,再批量生成 VPXxx = module.Xxx 别名导出。这一步已从“简单路径扫描”进入“源码级别分析”,把脚本升级成一个小型 API 生成器。
读取文件内容
-> 正则匹配 export interface / type / enum
-> 提取导出名
-> 生成带前缀的别名导出六、正则匹配前先剥离注释,避免幽灵导出项
类型文件里有注释,注释里可能正好也包含 interface / type 关键字,结果会被正则误判成要导出的成员。所以真正匹配前,先把单行注释和多行注释从文本里剥离掉。只要还是用正则分析源码,这一步基本绕不开。
content = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '')不先清注释,正则很容易匹配出“幽灵导出项”,让脚本工程接近真正的代码分析边界。
七、正则要覆盖泛型/别名等真实写法,公共类型先筛选再语义化
最开始的匹配过于简单,只能抓到最普通的导出,遇到泛型、复杂写法就漏掉。正则必须足够贴近项目真实类型书写习惯,所以要不断迭代匹配规则。同时,不是所有类型都应加前缀并公开:像 emitSelectType、openCloseType 这类内部命名,对外 API 显得生硬,要改造成 MenuSelectEvent、MenuOpenCloseEvent 这类更像公共 API 的名字。前缀化解决归属感,语义化解决可理解性。
内部命名
emitSelectType
公共 API 命名
MenuSelectEvent常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 后续想写 custom resolver,但组件名太乱 | 组件名没有统一前缀模式 | 先统一组件命名,再去写 resolver |
| 给已有 VForm 再加前缀变成 VPVForm | 脚本没有处理历史前缀 | 对已带 V 的组件先去重旧前缀 |
| 类型导出乱七八糟,甚至包含注释内容 | 直接对原文件做正则匹配,没先清理注释 | 先移除单行和多行注释,再做匹配 |
| 有些导出的 type/interface 漏掉了 | 正则过于简单,没覆盖项目真实写法 | 根据真实导出形式迭代正则规则 |
| 类型都导出了但名字很怪 | 内部实现命名直接暴露成公共 API | 做语义化重命名,再建统一别名导出 |