版本:0.2.6 | 协议:MIT | 依赖:Vite >=5.0.0 <8.0.0
写在前面
v0.2.6 的主题是:消除重复代码,让架构更干净,让版本号管理更自动化。
本次更新是一次内部架构优化版本,将散落在各插件内部的重复工具函数统一提取到 common 目录,新增 6 个通用子模块(code、compress、env、hash、object、string),并重构了版本号注入机制------从手动同步脚本升级为构建时自动注入。同时统一了插件内部目录命名(common → helpers),提升了整体可维护性。
本版重点:
| 能力 | 一句话说明 | 你需要做什么 |
|---|---|---|
| 6 个新增 Common 子模块 | code/compress/env/hash/object/string 统一管理工具函数 |
按需从新子路径导入 |
parsePluginTemplate |
插件专用模板解析函数,统一注释头模板处理 | 无需操作,内部已自动使用 |
__PLUGIN_VERSION__ 注入 |
构建时自动从 package.json 注入版本号,无需手动同步 | 无需操作 |
helpers 目录统一 |
插件内部 common 目录重命名为 helpers |
无需操作(内部结构变更) |
| versionUpdateChecker 优化 | 自定义模板解析改用通用 parseTemplateWithDelimiter |
无需操作 |
升级方式 :修改 devDependencies 中版本号为 ^0.2.6。无 Breaking Change,可直接平滑升级。
一、5 分钟快速上手
1.1 安装与升级
json
{
"devDependencies": {
"@meng-xi/vite-plugin": "^0.2.6"
}
}
1.2 使用新增的 Common 子模块
v0.2.6 将原本散落在各插件内部的工具函数提取为 6 个通用子模块,现在你可以直接按需导入:
typescript
// 深度合并对象
import { deepMerge } from '@meng-xi/vite-plugin/common/object'
const merged = deepMerge(
{ a: 1, b: { c: 2 } },
{ b: { d: 3 }, e: 4 }
)
// { a: 1, b: { c: 2, d: 3 }, e: 4 }
// 生成随机哈希
import { generateRandomHash } from '@meng-xi/vite-plugin/common/hash'
const hash = generateRandomHash(16) // 'a3f2b9c1d4e5f6a7'
// 路径转驼峰命名
import { toCamelCase } from '@meng-xi/vite-plugin/common/string'
const name = toCamelCase('/pages/user/profile') // 'pagesUserProfile'
1.3 一览新增子模块
| 子路径 | 核心导出 | 典型场景 |
|---|---|---|
@meng-xi/vite-plugin/common/code |
JS_KEYWORDS、stripCommentsAndStrings |
静态分析时移除注释与字符串 |
@meng-xi/vite-plugin/common/compress |
calculateGzipSize |
计算产物 gzip 压缩大小 |
@meng-xi/vite-plugin/common/env |
parseEnvContent |
解析 .env 文件内容 |
@meng-xi/vite-plugin/common/hash |
generateRandomHash |
生成缓存破坏哈希、版本标识 |
@meng-xi/vite-plugin/common/object |
deepMerge |
深度合并配置对象 |
@meng-xi/vite-plugin/common/string |
toCamelCase、toPascalCase、stripJsonComments、escapeRegex |
命名转换、JSON 解析、正则转义 |
二、Common 工具模块扩展
2.1 common/code ------ 代码处理
从 autoImport 插件提取,用于静态分析时预处理代码:
typescript
import { JS_KEYWORDS, stripCommentsAndStrings } from '@meng-xi/vite-plugin/common/code'
// JS 关键字集合:自动导入时跳过这些标识符
JS_KEYWORDS.has('class') // true
JS_KEYWORDS.has('myVar') // false
// 移除注释和字符串内容(保留换行符以维持行号)
const cleaned = stripCommentsAndStrings(`
const a = 1 // 注释
const b = "字符串"
`)
// 注释和字符串内容被替换为空白,结构保留
2.2 common/compress ------ 压缩计算
从 bundleAnalyzer 插件提取,用于产物体积分析:
typescript
import { calculateGzipSize } from '@meng-xi/vite-plugin/common/compress'
const originalSize = 1024
const gzipSize = await calculateGzipSize('console.log("hello world")')
// 35(字节数)
// 计算压缩率
const ratio = ((1 - gzipSize / originalSize) * 100).toFixed(1) + '%'
2.3 common/env ------ 环境变量解析
从 envGuard 插件提取,支持前缀过滤和引号去除:
typescript
import { parseEnvContent } from '@meng-xi/vite-plugin/common/env'
const content = `
# Database config
DB_HOST=localhost
DB_PORT="5432"
VITE_API_URL='https://api.example.com'
VITE_APP_TITLE="My App"
`
// 解析全部变量
const allVars = parseEnvContent(content)
// { DB_HOST: 'localhost', DB_PORT: '5432', VITE_API_URL: 'https://api.example.com', VITE_APP_TITLE: 'My App' }
// 仅解析 VITE_ 前缀变量
const viteVars = parseEnvContent(content, { prefix: 'VITE_' })
// { VITE_API_URL: 'https://api.example.com', VITE_APP_TITLE: 'My App' }
2.4 common/hash ------ 哈希生成
从 generateVersion 插件提取,使用加密级随机数:
typescript
import { generateRandomHash } from '@meng-xi/vite-plugin/common/hash'
generateRandomHash() // 'a3f2b9c1'(默认 8 位)
generateRandomHash(16) // 'a3f2b9c1d4e5f6a7'
generateRandomHash(32) // 'a3f2b9c1d4e5f6a7b8c9d0e1f2a3b4c5'
// 长度自动限制在 1-64 范围
generateRandomHash(100) // 截断为 64 位
generateRandomHash(0) // 修正为 1 位
2.5 common/object ------ 对象合并
从 factory 模块提取,递归合并普通对象:
typescript
import { deepMerge } from '@meng-xi/vite-plugin/common/object'
// 递归合并嵌套对象
deepMerge(
{ a: 1, b: { c: 2, e: 5 } },
{ b: { d: 3 }, f: 6 }
)
// { a: 1, b: { c: 2, d: 3, e: 5 }, f: 6 }
// undefined 值不会覆盖已有属性
deepMerge(
{ a: 1, b: 2 },
{ a: undefined, c: 3 }
)
// { a: 1, b: 2, c: 3 }
// 非对象值直接覆盖
deepMerge(
{ a: { x: 1 } },
{ a: null }
)
// { a: null }
2.6 common/string ------ 字符串处理
从 autoImport 插件提取,提供命名转换和 JSON 处理:
typescript
import { toCamelCase, toPascalCase, stripJsonComments, escapeRegex } from '@meng-xi/vite-plugin/common/string'
// 驼峰命名(路由名称生成)
toCamelCase('/pages/index/index') // 'pagesIndexIndex'
toCamelCase('user-name') // 'userName'
// 帕斯卡命名(组件名称生成)
toPascalCase('/pages/index/index') // 'PagesIndexIndex'
toPascalCase('user-name') // 'UserName'
// 移除 JSON 注释(解析带注释的配置文件)
const json = `{
// 页面配置
"pages": ["index"] /* 主页面 */
}`
const clean = stripJsonComments(json)
// { "pages": ["index"] }
// 转义正则特殊字符(安全构建正则表达式)
const userPattern = new RegExp(escapeRegex('user.name') + '\\d+')
// 匹配字面量 'user.name' 后跟数字,而非 'user' + 任意字符 + 'name'
2.7 common/format ------ 新增 parsePluginTemplate
common/format 模块新增 parsePluginTemplate 函数,统一插件注释头模板解析逻辑。该函数支持 {name}、{date}、{date:FORMAT}、{version}、{custom:KEY} 占位符:
typescript
import { parsePluginTemplate } from '@meng-xi/vite-plugin/common/format'
// 基础用法
parsePluginTemplate('{name} {date} {version}', {
name: 'generate-router',
version: '0.2.6'
})
// 'generate-router 2026-06-25 14:30:00 0.2.6'
// 自定义日期格式
parsePluginTemplate('{name} {date:YYYY-MM-DD} {version}', {
name: 'generate-router',
version: '0.2.6'
})
// 'generate-router 2026-06-25 0.2.6'
// 自定义字段
parsePluginTemplate('{name} {custom:author} {date:YYYY-MM-DD} {version}', {
name: 'generate-router',
version: '0.2.6',
customFields: { author: 'MengXi Studio' }
})
// 'generate-router MengXi Studio 2026-06-25 0.2.6'
该函数主要供
generateRouter插件内部使用,用于解析headerTemplate配置。你也可以在自定义插件中直接调用。
三、版本号注入机制重构
3.1 问题背景
在 v0.2.5 及之前,插件版本号通过 generate-exports.ts 脚本手动同步到各插件源码中。每次发版需要:
- 修改
package.json的version字段 - 运行
generate-exports.ts脚本扫描并替换源码中的版本号 - 手动确认所有插件版本号已更新
这种方式容易遗漏,且脚本逻辑复杂。
3.2 新机制:构建时自动注入
v0.2.6 引入 __PLUGIN_VERSION__ 全局变量,通过 unbuild 的 replace 配置在构建时自动注入:
typescript
// build.config.ts(自动生成)
export default defineBuildConfig({
// ...其他配置
replace: {
__PLUGIN_VERSION__: "\"0.2.6\"" // 从 package.json 自动读取
}
})
插件源码中直接使用全局变量:
typescript
// generateRouter/helpers/generator.ts
/** 插件版本号,由 unbuild 在构建时通过 replace 配置注入 */
const PLUGIN_VERSION = __PLUGIN_VERSION__
// 在注释头模板中使用
parsePluginTemplate(headerTemplate, {
name: 'generate-router',
version: PLUGIN_VERSION, // 自动获取,无需手动维护
customFields
})
3.3 类型声明支持
新增 src/types/global.d.ts 提供 TypeScript 类型声明:
typescript
// src/types/global.d.ts
declare const __PLUGIN_VERSION__: string
这意味着在插件源码中直接使用 __PLUGIN_VERSION__ 即可获得完整类型提示,无需重复声明。
3.4 对比
| 维度 | v0.2.5 | v0.2.6 |
|---|---|---|
| 版本号来源 | generate-exports.ts 手动同步 |
unbuild replace 自动注入 |
| 维护方式 | 每次发版运行脚本扫描替换源码 | 构建时自动从 package.json 读取 |
| 类型支持 | 无 | global.d.ts 全局类型声明 |
| 出错风险 | 可能遗漏某些插件 | 全局统一,不可能遗漏 |
四、versionUpdateChecker 优化
4.1 自定义模板解析统一
v0.2.6 将 versionUpdateChecker 插件的自定义提示模板解析逻辑从多次链式 .replace() 改用通用的 parseTemplateWithDelimiter 函数:
typescript
// v0.2.5:多次链式 replace
return options.customPromptTemplate
.replace(/\{\{message\}\}/g, message)
.replace(/\{\{currentVersion\}\}/g, '<span id="__vuc-current__"></span>')
.replace(/\{\{newVersion\}\}/g, '<span id="__vuc-new__"></span>')
.replace(/\{\{refreshButton\}\}/g, `<button>...</button>`)
.replace(/\{\{dismissButton\}\}/g, `<button>...</button>`)
// v0.2.6:使用通用工具函数一次解析
const values = {
message,
currentVersion: '<span id="__vuc-current__"></span>',
newVersion: '<span id="__vuc-new__"></span>',
refreshButton: `<button>...</button>`,
dismissButton: `<button>...</button>`
}
return parseTemplateWithDelimiter(options.customPromptTemplate, values, '{{', '}}')
4.2 收益
| 维度 | v0.2.5 | v0.2.6 |
|---|---|---|
| 代码量 | 5 次链式 replace | 1 次函数调用 |
| 可维护性 | 新增占位符需追加 replace | 只需在 values 对象中添加键值对 |
| 安全性 | 手动拼接正则 | 键名自动转义正则特殊字符 |
对用户无影响,
customPromptTemplate的{{message}}、{{currentVersion}}等占位符用法保持不变。
五、插件目录结构统一
5.1 common → helpers 重命名
v0.2.6 将所有插件内部的 common 目录统一重命名为 helpers,避免与顶层 common 工具模块混淆:
erlang
packages/core/src/plugins/generateRouter/
├── common/ ← v0.2.5(已移除)
│ ├── generator.ts
│ ├── merger.ts
│ └── ...
└── helpers/ ← v0.2.6(新增)
├── generator.ts
├── merger.ts
└── ...
涉及的 15 个插件全部完成迁移:
| 插件 | 目录变更 |
|---|---|
assetManifest |
common/ → helpers/ |
autoImport |
common/ → helpers/ |
buildProgress |
common/ → helpers/ |
bundleAnalyzer |
common/ → helpers/ |
compressAssets |
common/ → helpers/ |
envGuard |
common/ → helpers/ |
faviconManager |
common/ → helpers/,类型文件统一 |
generateRouter |
common/ → helpers/ |
generateVersion |
common/ → helpers/ |
htmlInject |
common/ → helpers/ |
imageOptimizer |
common/ → helpers/ |
loadingManager |
common/ → helpers/ |
proxyManager |
common/ → helpers/ |
versionUpdateChecker |
common/ → helpers/ |
5.2 faviconManager 类型文件统一
faviconManager 的类型文件从 common/type.ts 移动到插件根目录 types.ts,与其他插件保持一致:
bash
packages/core/src/plugins/faviconManager/
├── common/type.ts ← v0.2.5(已移除)
└── types.ts ← v0.2.6(统一位置)
重要 :此变更仅影响插件内部结构,对用户导入路径无任何影响。所有
@meng-xi/vite-plugin/plugins/*子路径导出保持不变。
六、实战场景
6.1 使用 deepMerge 合并多份配置
typescript
import { deepMerge } from '@meng-xi/vite-plugin/common/object'
// 合并默认配置、环境配置和用户自定义配置
const defaultConfig = {
timeout: 5000,
headers: { 'Content-Type': 'application/json' },
retry: { count: 3, delay: 1000 }
}
const envConfig = {
timeout: 10000,
retry: { delay: 2000 }
}
const userConfig = {
headers: { Authorization: 'Bearer token' },
customField: 'value'
}
const finalConfig = deepMerge(defaultConfig, envConfig, userConfig)
// {
// timeout: 10000,
// headers: { 'Content-Type': 'application/json', Authorization: 'Bearer token' },
// retry: { count: 3, delay: 2000 },
// customField: 'value'
// }
6.2 使用 parseEnvContent 读取自定义 .env 文件
typescript
import { readFileSync } from 'node:fs'
import { parseEnvContent } from '@meng-xi/vite-plugin/common/env'
// 读取自定义配置文件
const content = readFileSync('.env.deploy', 'utf-8')
const deployConfig = parseEnvContent(content, { prefix: 'DEPLOY_' })
// .env.deploy 内容:
// DEPLOY_HOST=192.168.1.100
// DEPLOY_PORT="22"
// DB_PASSWORD=secret
// deployConfig: { DEPLOY_HOST: '192.168.1.100', DEPLOY_PORT: '22' }
6.3 使用 generateRandomHash 生成缓存破坏标识
typescript
import { generateRandomHash } from '@meng-xi/vite-plugin/common/hash'
// 为静态资源生成缓存破坏参数
const assetHash = generateRandomHash(8)
const imageUrl = `/banner.png?v=${assetHash}`
// '/banner.png?v=a3f2b9c1'
// 生成唯一的构建标识
const buildId = generateRandomHash(16)
console.log(`Build ID: ${buildId}`)
// Build ID: a3f2b9c1d4e5f6a7
6.4 使用 toCamelCase 生成路由名称
typescript
import { toCamelCase } from '@meng-xi/vite-plugin/common/string'
// 根据文件路径自动生成路由名称
const pages = [
'/pages/index/index',
'/pages/user/profile',
'/pages-sub/settings/index'
]
const routeNames = pages.map(path => ({
path,
name: toCamelCase(path)
}))
// [
// { path: '/pages/index/index', name: 'pagesIndexIndex' },
// { path: '/pages/user/profile', name: 'pagesUserProfile' },
// { path: '/pages-sub/settings/index', name: 'pagesSubSettingsIndex' }
// ]
七、内置插件全景
v0.2.6 共包含 15 个实用插件,覆盖构建优化的各个方面:
| 插件 | enforce | 描述 |
|---|---|---|
assetManifest |
post | 构建后生成资源映射清单,支持 Vite/Webpack/自定义格式、按入口分组和运行时注入 |
autoImport |
pre | 自动导入,支持预设映射、通配符('*')、目录扫描、Vue 模板自动导入和类型声明生成 |
buildProgress |
- | 终端实时构建进度条,支持 bar / spinner / minimal |
bundleAnalyzer |
post | 构建产物体积分析,支持 JSON/HTML 报告、gzip 计算和阈值告警 |
compressAssets |
post | 构建产物压缩,支持 gzip / brotli / both,并发压缩和统计报告 |
copyFile |
post | 构建完成后复制文件或目录,支持增量复制 |
envGuard |
post | 环境变量校验,支持类型检查、范围验证、自定义规则和运行时守卫 |
faviconManager |
post | 管理网站图标链接注入和文件复制 |
generateRouter |
post | 根据 pages.json 自动生成路由配置与类型声明(uni-app) |
generateVersion |
post | 自动生成版本号,支持文件输出和全局变量注入 |
htmlInject |
post | HTML 内容注入,支持多种位置、选择器定位、条件注入和安全过滤 |
imageOptimizer |
post | 图片优化压缩与格式转换,支持 WebP/AVIF 转换、SVG 优化、并发处理 |
loadingManager |
post | 全局 Loading 状态管理,支持请求拦截、防抖、过渡动画 |
proxyManager |
- | 开发代理管理,支持环境切换、规则文件、请求日志、延迟模拟和响应修改 |
versionUpdateChecker |
post | 运行时版本更新检查,支持多种提示样式和自定义回调 |
八、Common 工具模块全景
v0.2.6 共包含 14 个 Common 工具子模块:
| 子路径 | 核心能力 |
|---|---|
common/code |
JS 关键字集合、代码注释与字符串移除(静态分析预处理) |
common/compress |
gzip 压缩大小计算 |
common/concurrency |
带并发限制的批量异步执行 |
common/env |
.env 文件内容解析(支持引号去除和前缀过滤) |
common/format |
日期参数提取、模板变量替换、日期格式化、文件大小格式化、压缩率计算、插件模板解析 |
common/fs |
源文件检查、文件/目录复制、目录扫描、批量删除、文件写入、JSON 报告、文件变更检测 |
common/hash |
随机哈希生成(加密级随机数,用于版本标识、缓存破坏) |
common/html |
HTML 标签注入、双区域注入、内容安全消毒、HTML 属性值转义 |
common/object |
深度合并对象(递归合并普通对象,跳过 undefined) |
common/path |
路径规范化、扩展名过滤、路径排除匹配、预压缩格式检测 |
common/script |
回调函数体包装为安全的函数表达式(含 try-catch) |
common/string |
大小写转换(camelCase/PascalCase)、JSON 注释移除、正则特殊字符转义 |
common/ui |
终端 ANSI 颜色码常量 |
common/validation |
链式配置验证器、全局名称校验、脚本检测、回调字段校验 |
九、子路径导出变更
新增
- 新增
@meng-xi/vite-plugin/common/code子路径导出 - 新增
@meng-xi/vite-plugin/common/compress子路径导出 - 新增
@meng-xi/vite-plugin/common/env子路径导出 - 新增
@meng-xi/vite-plugin/common/hash子路径导出 - 新增
@meng-xi/vite-plugin/common/object子路径导出 - 新增
@meng-xi/vite-plugin/common/string子路径导出
新增导出函数
@meng-xi/vite-plugin/common/code新增导出:JS_KEYWORDS、stripCommentsAndStrings@meng-xi/vite-plugin/common/compress新增导出:calculateGzipSize@meng-xi/vite-plugin/common/env新增导出:parseEnvContent@meng-xi/vite-plugin/common/format新增导出:parsePluginTemplate@meng-xi/vite-plugin/common/hash新增导出:generateRandomHash@meng-xi/vite-plugin/common/object新增导出:deepMerge@meng-xi/vite-plugin/common/string新增导出:toCamelCase、toPascalCase、stripJsonComments、escapeRegex
移除
无移除项,本次版本完全向后兼容。
十、升级指南
10.1 平滑升级
v0.2.6 无 Breaking Change,直接升级即可:
bash
pnpm update @meng-xi/vite-plugin@^0.2.6
10.2 可选:使用新增的 Common 子模块
如果你有自定义插件或脚本需要用到深度合并、哈希生成等工具,现在可以直接从 common 子路径导入,无需自行实现:
typescript
// 之前:自行实现或从插件内部导入(不推荐)
// 现在:直接从 common 子路径导入
import { deepMerge } from '@meng-xi/vite-plugin/common/object'
import { generateRandomHash } from '@meng-xi/vite-plugin/common/hash'
import { toCamelCase } from '@meng-xi/vite-plugin/common/string'
写在最后
v0.2.6 是一次"内部健康度"优化版本。虽然对用户可见的 API 变化不多,但这次重构为后续版本的功能扩展打下了更干净的基础:
- Common 模块扩展让通用工具可以独立复用,减少未来新插件的开发成本
- 版本号注入自动化消除了发版时的人工操作风险
- 目录结构统一让代码库更易维护和贡献
下一个版本我们将继续聚焦于功能增强和开发者体验优化。如果你有任何建议或问题,欢迎在 GitHub Issues 反馈。