Vite插件v0.2.6:架构优化与自动化升级

版本:0.2.6 | 协议:MIT | 依赖:Vite >=5.0.0 <8.0.0


写在前面

v0.2.6 的主题是:消除重复代码,让架构更干净,让版本号管理更自动化

本次更新是一次内部架构优化版本,将散落在各插件内部的重复工具函数统一提取到 common 目录,新增 6 个通用子模块(codecompressenvhashobjectstring),并重构了版本号注入机制------从手动同步脚本升级为构建时自动注入。同时统一了插件内部目录命名(commonhelpers),提升了整体可维护性。

本版重点

能力 一句话说明 你需要做什么
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_KEYWORDSstripCommentsAndStrings 静态分析时移除注释与字符串
@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 toCamelCasetoPascalCasestripJsonCommentsescapeRegex 命名转换、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 脚本手动同步到各插件源码中。每次发版需要:

  1. 修改 package.jsonversion 字段
  2. 运行 generate-exports.ts 脚本扫描并替换源码中的版本号
  3. 手动确认所有插件版本号已更新

这种方式容易遗漏,且脚本逻辑复杂。

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_KEYWORDSstripCommentsAndStrings
  • @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 新增导出:toCamelCasetoPascalCasestripJsonCommentsescapeRegex

移除

无移除项,本次版本完全向后兼容。


十、升级指南

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 反馈。

相关推荐
threerocks3 小时前
什么?我连 A2A、MCP 都没学会,现在又来了 AG-UI、A2UI.
前端·aigc·ai编程
牛奶3 小时前
如何自己写一个浏览器插件?
前端·chrome·浏览器
亿元程序员4 小时前
为什么Cocos都4.0了还有人用2.x?
前端
MomentYY4 小时前
AI 到底是“懂”,还是在“猜”?
前端·人工智能·ai编程
鹏毓网络科技4 小时前
Cursor Rules 文件配置实战:3 个隐藏参数让我每月少写 40% 样板代码
前端·github
没烦恼3014 小时前
无痕模式下 HTTP\-First 拦截引发的“页面刷新”误判
前端
文心快码BaiduComate4 小时前
从个人提效到组织提效:Comate辅助构建自我进化的AI研发系统
前端·程序员
hunterandroid5 小时前
Compose 状态管理:remember、rememberSaveable 与状态提升
前端
星栈5 小时前
Dioxus 接数据库最容易写歪的 3 个地方:sqlx + SQLite 怎么接才顺
前端·rust·前端框架