Vite插件神器:5大构建增强+完整开发框架
一站式 Vite 插件工具库,5 个开箱即用的构建增强插件 + 完整的插件开发框架。无论你是想快速提升构建体验,还是开发自己的 Vite 插件,
@meng-xi/vite-plugin都能为你提供优雅的解决方案。
📑 目录
一、项目概览
@meng-xi/vite-plugin 是一个双用途的 Vite 生态工具库:
| 能力 | 说明 |
|---|---|
| 开箱即用的插件集 | 5 个精心设计的构建增强插件,覆盖进度可视化、文件复制、版本管理、路由生成、图标注入等常见需求 |
| 插件开发框架 | 基于 BasePlugin 抽象类的完整开发体系,提供配置管理、日志记录、错误处理、生命周期管理等基础设施 |
核心设计原则
- 零配置可用 — 每个插件都有合理的默认值,一行代码即可启用
- 灵活可定制 — 丰富的配置选项和钩子,满足不同场景需求
- 类型安全 — 完整的 TypeScript 类型定义,IDE 智能提示友好
- 错误容错 — 三级错误策略(throw / log / ignore),安全执行机制
- 框架一致性 — 所有插件遵循统一的 BasePlugin 规范,API 风格一致
包信息
{
"name": "@meng-xi/vite-plugin",
"version": "0.0.7",
"type": "module",
"peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" }
}
二、快速开始
安装
# pnpm(推荐)
pnpm add @meng-xi/vite-plugin -D
# npm
npm install @meng-xi/vite-plugin -D
# yarn
yarn add @meng-xi/vite-plugin -D
最小配置
import { defineConfig } from 'vite'
import { buildProgress, copyFile, generateVersion, injectIco } from '@meng-xi/vite-plugin'
export default defineConfig({
plugins: [
buildProgress(), // 构建进度条
copyFile({
// 文件复制
sourceDir: 'public',
targetDir: 'dist'
}),
generateVersion(), // 版本号生成
injectIco() // 图标注入
]
})
按需导入
通过子路径导出,只引入需要的模块:
// 仅导入插件
import { buildProgress } from '@meng-xi/vite-plugin/plugins'
// 仅导入工具函数
import { deepMerge, formatDate } from '@meng-xi/vite-plugin/common'
// 仅导入框架(开发自定义插件)
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin/factory'
// 仅导入日志
import { Logger } from '@meng-xi/vite-plugin/logger'
三、插件详解
3.1 buildProgress — 构建进度条
在终端实时显示 Vite 构建进度,告别"黑盒等待"。
三种显示格式
# bar(默认)— 完整进度条
⠋ 转换模块 ██████████████████████░░░░░░░░ 67% src/components/App.vue
# spinner — 旋转动画
⠹ 转换模块 67% src/components/App.vue
# minimal — 精简模式
转换模块 67%
使用示例
// 默认配置
buildProgress()
// 自定义外观
buildProgress({
format: 'bar',
width: 40,
completeChar: '■',
incompleteChar: '□',
clearOnComplete: false
})
// 自定义颜色主题(使用 picocolors)
import pc from 'picocolors'
buildProgress({
theme: {
completeColor: pc.green,
incompleteColor: pc.gray,
percentageColor: pc.bold,
phaseColor: pc.cyan,
moduleColor: pc.yellow
}
})
// CI 环境使用精简模式
buildProgress({
format: process.env.CI ? 'minimal' : 'bar',
enabled: process.env.CI !== 'true'
})
进度计算模型
| 阶段 | 进度 | 说明 |
|---|---|---|
| config | 5% | 读取配置 |
| resolve | 10% | 解析模块依赖 |
| transform | 15%-85% | 转换模块(按比例线性计算) |
| bundle | +10% | 打包(仅生产构建) |
| write | +5% | 写入文件 |
| done | 100% | 构建完成 |
关键设计:进度只进不退,通过 lastPercentage 缓存避免视觉闪烁。
配置参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
width | number | 30 | 进度条宽度(字符数) |
format | 'bar' | 'spinner' | 'minimal' | 'bar' | 显示格式 |
completeChar | string | '█' | 已完成填充字符 |
incompleteChar | string | '░' | 未完成填充字符 |
clearOnComplete | boolean | true | 完成后是否清除进度条 |
showModuleName | boolean | true | 是否显示当前模块名 |
theme | ProgressTheme | — | 自定义颜色主题 |
3.2 copyFile — 文件复制
构建完成后将指定目录的文件复制到目标位置,支持增量更新。
使用示例
// 基本使用
copyFile({
sourceDir: 'public',
targetDir: 'dist/build/h5'
})
// 高级配置
copyFile({
sourceDir: resolve('public'),
targetDir: resolve('dist/build/h5'),
overwrite: true,
recursive: true,
incremental: true, // 仅复制修改过的文件
enabled: isH5 && isProd
})
核心特性
- 增量复制 — 通过比较文件修改时间和大小,仅复制有变化的文件
- 并行 IO — 使用并发控制(默认 10 路)加速大批量文件复制
- 递归支持 — 可选递归复制子目录
- 覆盖控制 — 可配置是否覆盖同名文件
配置参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
sourceDir | string | — | 必填,源目录路径 |
targetDir | string | — | 必填,目标目录路径 |
overwrite | boolean | true | 是否覆盖同名文件 |
recursive | boolean | true | 是否递归复制子目录 |
incremental | boolean | true | 是否启用增量复制 |
3.3 generateVersion — 版本号生成
自动生成版本号,支持多种格式和输出方式。
使用示例
// 时间戳格式(默认)
generateVersion()
// 日期格式
generateVersion({ format: 'date' })
// 语义化版本 + 前缀
generateVersion({
format: 'semver',
semverBase: '2.0.0',
prefix: 'v'
})
// 自定义格式
generateVersion({
format: 'custom',
customFormat: '{YYYY}.{MM}.{DD}-{hash}',
hashLength: 6
})
// 同时输出文件和注入全局变量
generateVersion({
format: 'datetime',
outputType: 'both',
defineName: '__APP_VERSION__',
extra: {
environment: 'production',
author: 'MengXi Studio'
}
})
版本格式一览
| 格式 | 示例输出 | 说明 |
|---|---|---|
timestamp | 20260520153000 | 时间戳(默认) |
date | 2026.05.20 | 日期 |
datetime | 2026.05.20.153000 | 日期时间 |
semver | 1.0.0 | 语义化版本 |
hash | a1b2c3d4 | 随机哈希 |
custom | 自定义 | 配合 customFormat 使用 |
自定义格式占位符
customFormat 支持以下占位符:{YYYY}、{YY}、{MM}、{DD}、{HH}、{mm}、{ss}、{SSS}、{timestamp}、{hash}、{major}、{minor}、{patch}。
输出类型
file— 写入 JSON 文件到构建输出目录define— 通过 Vitedefine注入全局变量,可在代码中直接使用both— 两种方式同时启用
在代码中使用注入的版本号:
// 需要在 vite-env.d.ts 中声明类型
declare const __APP_VERSION__: string
declare const __APP_VERSION___INFO: { version: string; buildTime: string; timestamp: number }
console.log(__APP_VERSION__) // 'v2026.05.20-a1b2c3'
console.log(__APP_VERSION___INFO) // { version: '...', buildTime: '...', ... }
3.4 generateRouter — 路由配置生成
读取 uni-app 项目的 pages.json,自动生成路由配置文件。
使用示例
// 默认配置
generateRouter()
// 自定义路径
generateRouter({
pagesJsonPath: 'pages.json',
outputPath: 'src/router.config.ts'
})
// 输出 JavaScript
generateRouter({
outputFormat: 'js',
outputPath: 'src/router.config.js'
})
// 自定义路由名称策略
generateRouter({
nameStrategy: 'pascalCase' // 或 'camelCase' | 'path' | 'custom'
})
// 自定义名称生成函数
generateRouter({
nameStrategy: 'custom',
customNameGenerator: path => `route_${path.replace(/\//g, '_')}`
})
// 自定义元信息映射
generateRouter({
metaMapping: {
navigationBarTitleText: 'title',
requireAuth: 'requireAuth',
customField: 'custom'
}
})
核心特性
- 主包 + 子包 — 自动解析主包和
subPackages中的页面 - TabBar 识别 — 自动标记 tabBar 页面(
meta.isTab = true) - 名称策略 — 支持
path、camelCase、pascalCase、custom四种命名策略 - 元信息映射 — 可自定义
pages.jsonstyle 字段到路由 meta 的映射 - 变更保留 —
preserveRouteChanges开启后,用户对路由的手动修改不会被覆盖 - 文件监听 — 开发模式下自动监听
pages.json变化并重新生成 - 类型导出 — 自动生成
RouteConfig、RouteMeta等类型定义
生成的文件示例
// src/router.config.ts(自动生成)
export interface RouteMeta {
title?: string
isTab?: boolean
requireAuth?: boolean
[key: string]: unknown
}
export interface RouteConfig {
path: string
name?: string
meta?: RouteMeta
}
export const routes: RouteConfig[] = [
{ path: '/pages/index/index', name: 'pagesIndex', meta: { title: '首页', isTab: true } },
{ path: '/pages/user/profile', name: 'pagesUserProfile', meta: { title: '个人中心' } }
]
export default routes
3.5 injectIco — 图标注入
将网站图标链接注入到 HTML 的 <head> 中,并可选复制图标文件。
使用示例
// 最简配置
injectIco()
// 指定 base 路径(字符串简写)
injectIco('/assets')
// 完整配置
injectIco({
base: '/assets',
icons: [
{ rel: 'icon', href: '/favicon.svg', type: 'image/svg+xml' },
{ rel: 'icon', href: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
{ rel: 'apple-touch-icon', href: '/apple-touch-icon.png', sizes: '180x180' }
],
copyOptions: {
sourceDir: 'public',
targetDir: 'dist/build/h5',
overwrite: true,
recursive: true
}
})
// 使用外部 URL
injectIco({
url: 'https://cdn.example.com/favicon.ico'
})
// 自定义完整 link 标签
injectIco({
link: '<link rel="icon" href="/favicon.svg" type="image/svg+xml" />'
})
优先级
link > url > base + favicon.ico
当提供 link 时,其他选项被忽略;当提供 url 时,base 被忽略。
四、核心框架:BasePlugin 开发体系
4.1 架构设计
┌─────────────────────────────────────────────────────┐
│ BasePlugin<T> │
│ (抽象基类,提供插件开发的所有基础设施) │
├─────────────────────────────────────────────────────┤
│ 配置管理 mergeOptions + getDefaultOptions │
│ 参数验证 validateOptions + Validator │
│ 日志记录 Logger (单例) + PluginLogger (代理) │
│ 错误处理 safeExecute / safeExecuteSync │
│ 生命周期 onConfigResolved / destroy │
│ Vite 桥接 toPlugin() → Plugin 对象 │
├─────────────────────────────────────────────────────┤
│ 子类实现 │
│ getPluginName() — 插件名称(抽象) │
│ addPluginHooks() — 注册 Vite 钩子(抽象) │
│ getDefaultOptions()— 插件默认配置(可选重写) │
│ validateOptions() — 自定义验证(可选重写) │
│ destroy() — 清理逻辑(可选重写) │
└─────────────────────────────────────────────────────┘
│
▼ createPluginFactory()
┌─────────────────────────────────────────────────────┐
│ PluginFactory<T, R> │
│ (options?) => PluginWithInstance<T> │
│ · 支持选项标准化器(OptionsNormalizer) │
│ · 返回的 Plugin 对象附带 pluginInstance 属性 │
└─────────────────────────────────────────────────────┘
4.2 BasePlugin 抽象类
BasePlugin 是所有插件的基类,提供了完整的插件开发基础设施:
abstract class BasePlugin<T extends BasePluginOptions> {
// ===== 子类必须实现 =====
protected abstract getPluginName(): string
protected abstract addPluginHooks(plugin: Plugin): void
// ===== 子类可选重写 =====
protected getDefaultOptions(): Partial<T> // 插件默认配置
protected validateOptions(): void // 配置验证
protected destroy(): void // 清理逻辑
protected onConfigResolved(config: ResolvedConfig) // 配置解析回调
// ===== 框架提供的能力 =====
protected options: Required<T> // 合并后的配置
protected logger: PluginLogger // 日志代理
protected validator: Validator<T> // 参数验证器
protected safeExecute<T>(fn, context): Promise<T> // 安全异步执行
protected safeExecuteSync<T>(fn, context): T // 安全同步执行
protected handleError<T>(error, context): T // 错误处理
public toPlugin(): Plugin // 转换为 Vite 插件
}
通用配置(BasePluginOptions)
所有插件都继承以下基础配置:
interface BasePluginOptions {
enabled?: boolean // 是否启用,默认 true
verbose?: boolean // 是否输出日志,默认 true
errorStrategy?: 'throw' | 'log' | 'ignore' // 错误策略,默认 'throw'
}
错误处理策略
| 策略 | 行为 |
|---|---|
throw | 记录错误日志并抛出异常,中断构建 |
log | 记录错误日志但不中断,返回 undefined |
ignore | 同 log,静默处理 |
4.3 createPluginFactory 工厂函数
将插件类转换为符合 Vite 规范的工厂函数:
// 基本用法
const myPlugin = createPluginFactory(MyPluginClass)
// 带选项标准化器(支持字符串简写)
const injectIco = createPluginFactory<InjectIcoOptions, InjectIcoPlugin, string | InjectIcoOptions>(InjectIcoPlugin, options => (typeof options === 'string' ? { base: options } : options || {}))
返回的 PluginWithInstance 对象包含 pluginInstance 属性,可访问插件内部状态:
const progress = buildProgress() as PluginWithInstance<BuildProgressOptions>
console.log(progress.pluginInstance?.options)
4.4 自定义插件开发实战
以下是一个完整的自定义插件示例 — 构建耗时统计插件:
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin/factory'
import type { BasePluginOptions } from '@meng-xi/vite-plugin/factory'
import type { Plugin } from 'vite'
// 1. 定义配置类型
interface BuildTimerOptions extends BasePluginOptions {
/** 是否在构建完成后输出详细耗时分布 */
detailed?: boolean
/** 日志输出格式 */
format?: 'simple' | 'table'
}
// 2. 实现插件类
class BuildTimerPlugin extends BasePlugin<BuildTimerOptions> {
private startTime = 0
private phaseTimes: Record<string, number> = {}
protected getPluginName(): string {
return 'build-timer'
}
protected getDefaultOptions(): Partial<BuildTimerOptions> {
return {
detailed: false,
format: 'simple'
}
}
protected validateOptions(): void {
this.validator
.field('detailed')
.boolean()
.field('format')
.custom(val => !val || ['simple', 'table'].includes(val), 'format 必须是 simple 或 table')
.validate()
}
protected addPluginHooks(plugin: Plugin): void {
plugin.buildStart = () => {
this.startTime = Date.now()
this.phaseTimes = {}
}
plugin.writeBundle = () => {
this.phaseTimes['write'] = Date.now()
}
plugin.closeBundle = () => {
const totalTime = Date.now() - this.startTime
this.logger.success(`构建完成,总耗时: ${totalTime}ms`)
if (this.options.detailed) {
for (const [phase, time] of Object.entries(this.phaseTimes)) {
this.logger.info(` ${phase}: ${time}ms`)
}
}
}
}
}
// 3. 导出工厂函数
export const buildTimer = createPluginFactory(BuildTimerPlugin)
export type { BuildTimerOptions }
使用自定义插件:
import { buildTimer } from './plugins/build-timer'
export default defineConfig({
plugins: [buildTimer({ detailed: true, format: 'table' })]
})
五、通用工具模块
@meng-xi/vite-plugin/common 导出了一系列实用的工具函数,不仅框架内部使用,也可在业务代码中直接使用。
5.1 format — 格式化工具
import { padNumber, generateRandomHash, formatDate, parseTemplate, toCamelCase, toPascalCase, stripJsonComments } from '@meng-xi/vite-plugin/common'
| 函数 | 说明 | 示例 |
|---|---|---|
padNumber(num, length) | 数字补零 | padNumber(5, 2) → '05' |
generateRandomHash(length) | 生成随机哈希 | generateRandomHash(8) → 'a1b2c3d4' |
formatDate(date, format) | 日期格式化 | formatDate(new Date(), '{YYYY}-{MM}-{DD}') → '2026-05-20' |
parseTemplate(template, values) | 模板字符串替换 | parseTemplate('{name}-{ver}', { name: 'app', ver: '1.0' }) → 'app-1.0' |
toCamelCase(str) | 转 camelCase | toCamelCase('pages/user/profile') → 'pagesUserProfile' |
toPascalCase(str) | 转 PascalCase | toPascalCase('user-profile') → 'UserProfile' |
stripJsonComments(str) | 移除 JSON 注释 | stripJsonComments('{// comment\n"a":1}') → '{"a":1}' |
formatDate 占位符
{YYYY}、{YY}、{MM}、{DD}、{HH}、{mm}、{ss}、{SSS}、{timestamp}
5.2 fs — 文件系统工具
import { checkSourceExists, ensureTargetDir, readDirRecursive, shouldUpdateFile, fileExists, runWithConcurrency, copySourceToTarget, writeFileContent, readFileContent } from '@meng-xi/vite-plugin/common'
| 函数 | 说明 |
|---|---|
checkSourceExists(path) | 检查源路径是否存在,不存在则抛出详细错误 |
ensureTargetDir(path) | 确保目标目录存在,递归创建 |
readDirRecursive(path, recursive) | 递归读取目录,返回文件/目录条目列表 |
shouldUpdateFile(src, dest) | 比较修改时间和大小,判断是否需要更新 |
fileExists(path) | 异步检查文件是否存在 |
runWithConcurrency(items, handler, limit) | 带并发限制的批量执行 |
copySourceToTarget(src, dest, options) | 完整的文件复制实现,支持增量/并行 |
writeFileContent(path, content) | 写入文件,带权限错误提示 |
readFileContent(path) | 读取文件,带权限错误提示 |
CopyOptions 接口
interface CopyOptions {
recursive: boolean // 是否递归复制
overwrite: boolean // 是否覆盖
incremental?: boolean // 是否增量
parallelLimit?: number // 并发限制,默认 10
skipEmptyDirs?: boolean // 是否跳过空目录
}
CopyResult 接口
interface CopyResult {
copiedFiles: number // 复制的文件数
skippedFiles: number // 跳过的文件数
copiedDirs: number // 复制的目录数
executionTime: number // 耗时(毫秒)
}
5.3 object — 对象工具
import { deepMerge } from '@meng-xi/vite-plugin/common'
deepMerge
深度合并多个对象,是框架配置合并的核心:
// 基本合并
deepMerge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 }
// undefined 不覆盖已有值
deepMerge({ a: 1 }, { a: undefined }) // { a: 1 }
// null 会覆盖
deepMerge({ a: 1 }, { a: null }) // { a: null }
// 嵌套对象递归合并
deepMerge({ a: { b: 1 } }, { a: { c: 2 } }) // { a: { b: 1, c: 2 } }
// 数组直接覆盖(不合并)
deepMerge({ a: [1, 2] }, { a: [3, 4] }) // { a: [3, 4] }
5.4 validation — 参数验证器
import { Validator } from '@meng-xi/vite-plugin/common'
流畅的链式 API,用于验证插件配置:
const validator = new Validator(options)
validator
.field('sourceDir')
.required()
.string()
.custom(val => val.trim() !== '', '不能为空')
.field('targetDir')
.required()
.string()
.field('overwrite')
.boolean()
.default(true)
.field('width')
.number()
.custom(val => val > 0, '必须大于 0')
.field('items')
.array()
.field('config')
.object()
.validate() // 验证失败抛出 Error,成功返回 options
| 方法 | 说明 |
|---|---|
.field(name) | 指定要验证的字段 |
.required() | 标记为必填 |
.string() | 验证字符串类型 |
.number() | 验证数字类型 |
.boolean() | 验证布尔类型 |
.array() | 验证数组类型 |
.object() | 验证对象类型 |
.default(value) | 设置默认值(仅 undefined/null 时生效) |
.custom(fn, msg) | 自定义验证函数 |
.validate() | 执行验证,失败抛出错误 |
六、日志系统
@meng-xi/vite-plugin/logger 提供单例模式的日志管理器。
Logger 类
import { Logger } from '@meng-xi/vite-plugin/logger'
核心特性
- 单例模式 — 全局唯一实例,统一管理所有插件日志
- 插件级开关 — 每个插件可独立控制日志开关
- 彩色输出 — 使用 ANSI 颜色码区分日志级别
- 自动注销 — 插件销毁时自动清理日志配置
日志级别
| 级别 | 图标 | 颜色 | 方法 |
|---|---|---|---|
| success | ✅ | 绿色 | logger.success(msg, data?) |
| info | ℹ️ | 青色 | logger.info(msg, data?) |
| warn | ⚠️ | 黄色 | logger.warn(msg, data?) |
| error | ❌ | 红色 | logger.error(msg, data?) |
输出格式
✅ [@meng-xi/vite-plugin:build-progress] 构建完成
ℹ️ [@meng-xi/vite-plugin:copy-file] 复制文件成功:从 public 到 dist
⚠️ [@meng-xi/vite-plugin:generate-router] pages.json 中没有有效的页面配置
❌ [@meng-xi/vite-plugin:inject-ico] 未找到 </head> 标签
PluginLogger 接口
每个插件通过 PluginLogger 代理对象输出日志,由 BasePlugin 自动创建:
interface PluginLogger {
success(message: string, data?: any): void
info(message: string, data?: any): void
warn(message: string, data?: any): void
error(message: string, data?: any): void
}
七、子路径导出
@meng-xi/vite-plugin 支持精细化的子路径导出,便于按需引入:
| 路径 | 内容 | 典型场景 |
|---|---|---|
@meng-xi/vite-plugin | 全部导出 | 日常使用 |
@meng-xi/vite-plugin/plugins | 仅插件 | 只用插件不需要框架 |
@meng-xi/vite-plugin/common | 仅工具函数 | 只用工具不用插件 |
@meng-xi/vite-plugin/factory | 仅框架 | 开发自定义插件 |
@meng-xi/vite-plugin/logger | 仅日志 | 自定义日志管理 |
每个子路径均提供 CJS、ESM 和类型定义三种格式:
{
"./common": {
"require": "./dist/common/index.cjs",
"import": "./dist/common/index.mjs",
"types": "./dist/common/index.d.ts"
}
}
八、最佳实践
1. 插件顺序
buildProgress 不依赖顺序,可放在 plugins 数组任意位置。其他插件建议按以下顺序:
plugins: [
buildProgress(), // 进度条(最先注册,最早触发)
injectIco(), // 图标注入(transformIndexHtml 钩子)
generateVersion(), // 版本生成(config + writeBundle 钩子)
copyFile(), // 文件复制(writeBundle 钩子,enforce: 'post')
generateRouter() // 路由生成(configResolved 钩子)
]
2. 条件启用
根据平台和环境变量控制插件启用:
const isH5 = process.env.UNI_PLATFORM === 'h5'
const isProd = viteEnv.VITE_USER_NODE_ENV === 'production'
plugins: [buildProgress({ enabled: !process.env.CI }), injectIco({ enabled: isH5 && isProd }), copyFile({ enabled: isH5 && isProd }), generateVersion({ enabled: isProd })]
3. 错误策略选择
| 场景 | 推荐策略 |
|---|---|
| 开发环境 | throw(默认),快速暴露问题 |
| CI/CD | throw,确保构建失败可见 |
| 非关键插件 | log,记录但不中断 |
| 可选功能 | ignore,静默跳过 |
4. 版本号在代码中的使用
// vite.config.ts
generateVersion({
outputType: 'both',
defineName: '__APP_VERSION__'
})
// src/utils/version.ts
declare const __APP_VERSION__: string
export function getVersion(): string {
return __APP_VERSION__
}
// 用于错误上报
reportError({ version: __APP_VERSION__, ...errorInfo })
5. 路由配置的增量修改
开启 preserveRouteChanges 后,手动修改的路由 meta 不会被覆盖:
generateRouter({
preserveRouteChanges: true,
metaMapping: {
navigationBarTitleText: 'title',
requireAuth: 'requireAuth'
}
})
首次生成后,手动添加 requireAuth: true:
{ path: '/pages/admin/dashboard', name: 'pagesAdminDashboard', meta: { title: '管理后台', requireAuth: true } }
下次 pages.json 变化重新生成时,requireAuth: true 会被保留。
6. 自定义插件中复用工具函数
import { Validator, deepMerge, writeFileContent, readFileContent } from '@meng-xi/vite-plugin/common'
class MyPlugin extends BasePlugin<MyOptions> {
protected validateOptions(): void {
this.validator.field('inputDir').required().string().field('outputDir').required().string().validate()
}
protected async processData(): Promise<void> {
const content = await readFileContent(this.options.inputDir)
// ... 处理逻辑
await writeFileContent(this.options.outputDir, result)
}
}
九、常见问题解答
Q1:插件不生效?
排查步骤:
- 确认
enabled未设为false - 确认
verbose为true,查看日志输出 - 确认插件在
plugins数组中正确注册 - 检查
errorStrategy,如果是ignore可能静默跳过了错误
Q2:buildProgress 在 CI 中显示乱码?
CI 环境通常是非 TTY,插件会自动降级为日志输出。如果仍有问题:
buildProgress({
enabled: process.env.CI !== 'true' // CI 环境完全禁用
})
Q3:copyFile 增量复制不生效?
增量复制通过比较文件修改时间判断。如果源文件时间戳未变化但内容变了(如 git checkout),需要先触发文件修改时间更新。
Q4:generateVersion 的 define 注入如何在 TypeScript 中使用?
在 vite-env.d.ts 中声明类型:
declare const __APP_VERSION__: string
declare const __APP_VERSION___INFO: {
version: string
buildTime: string
timestamp: number
format: string
[key: string]: unknown
}
Q5:generateRouter 支持非 uni-app 项目吗?
当前版本专为 uni-app 的 pages.json 格式设计。非 uni-app 项目可通过自定义插件实现类似功能,使用 @meng-xi/vite-plugin/factory 中的 BasePlugin 作为基类。
Q6:如何访问插件的内部状态?
所有插件返回的对象包含 pluginInstance 属性:
import type { PluginWithInstance } from '@meng-xi/vite-plugin/factory'
import type { BuildProgressOptions } from '@meng-xi/vite-plugin/plugins'
const progress = buildProgress() as PluginWithInstance<BuildProgressOptions>
console.log(progress.pluginInstance?.options)
Q7:多个插件的日志可以分别控制吗?
可以。每个插件的 verbose 选项独立控制日志开关:
;(buildProgress({ verbose: true }),
copyFile({ verbose: false }), // 不输出日志
generateVersion({ verbose: true }))
Q8:injectIco 仅 H5 平台有效?
是的。小程序和 App 平台不支持 HTML <link> 标签,建议条件启用:
injectIco({ enabled: process.env.UNI_PLATFORM === 'h5' })
十、API 速查表
插件
| 导出 | 类型 | 说明 |
|---|---|---|
buildProgress | PluginFactory<BuildProgressOptions> | 构建进度条 |
copyFile | PluginFactory<CopyFileOptions> | 文件复制 |
generateVersion | PluginFactory<GenerateVersionOptions> | 版本号生成 |
generateRouter | PluginFactory<GenerateRouterOptions> | 路由配置生成 |
injectIco | PluginFactory<InjectIcoOptions, string | InjectIcoOptions> | 图标注入 |
框架
| 导出 | 类型 | 说明 |
|---|---|---|
BasePlugin | abstract class | 插件抽象基类 |
createPluginFactory | function | 插件工厂函数创建器 |
BasePluginOptions | interface | 基础插件配置 |
PluginWithInstance | interface | 带实例引用的 Plugin 类型 |
PluginFactory | type | 工厂函数类型 |
OptionsNormalizer | type | 选项标准化器类型 |
工具函数
| 导出 | 说明 |
|---|---|
padNumber | 数字补零 |
generateRandomHash | 随机哈希生成 |
formatDate | 日期格式化 |
getDateFormatParams | 获取日期参数对象 |
parseTemplate | 模板字符串替换 |
toCamelCase | 转 camelCase |
toPascalCase | 转 PascalCase |
stripJsonComments | 移除 JSON 注释 |
deepMerge | 深度合并对象 |
Validator | 参数验证器类 |
checkSourceExists | 检查源路径存在 |
ensureTargetDir | 确保目标目录 |
readDirRecursive | 递归读取目录 |
shouldUpdateFile | 判断文件是否需更新 |
fileExists | 异步文件存在检查 |
runWithConcurrency | 带并发限制批量执行 |
copySourceToTarget | 文件复制实现 |
writeFileContent | 写入文件 |
readFileContent | 读取文件 |
日志
| 导出 | 说明 |
|---|---|
Logger | 日志管理器类(单例) |
PluginLogger | 插件日志代理接口 |
本文基于 @meng-xi/vite-plugin@0.0.7 版本撰写,如有更新请以最新文档为准。
更多推荐

所有评论(0)