@meng-xi/vite-plugin 0.0.9 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-en.md +467 -269
- package/README.md +451 -254
- package/dist/common/format/index.cjs +1 -0
- package/dist/common/format/index.d.cts +156 -0
- package/dist/common/format/index.d.mts +156 -0
- package/dist/common/format/index.d.ts +156 -0
- package/dist/common/format/index.mjs +1 -0
- package/dist/common/fs/index.cjs +1 -0
- package/dist/common/fs/index.d.cts +150 -0
- package/dist/common/fs/index.d.mts +150 -0
- package/dist/common/fs/index.d.ts +150 -0
- package/dist/common/fs/index.mjs +1 -0
- package/dist/common/html/index.cjs +2 -0
- package/dist/common/html/index.d.cts +109 -0
- package/dist/common/html/index.d.mts +109 -0
- package/dist/common/html/index.d.ts +109 -0
- package/dist/common/html/index.mjs +2 -0
- package/dist/common/index.cjs +1 -1
- package/dist/common/index.d.cts +7 -318
- package/dist/common/index.d.mts +7 -318
- package/dist/common/index.d.ts +7 -318
- package/dist/common/index.mjs +1 -1
- package/dist/common/object/index.cjs +1 -0
- package/dist/common/object/index.d.cts +30 -0
- package/dist/common/object/index.d.mts +30 -0
- package/dist/common/object/index.d.ts +30 -0
- package/dist/common/object/index.mjs +1 -0
- package/dist/common/script/index.cjs +1 -0
- package/dist/common/script/index.d.cts +54 -0
- package/dist/common/script/index.d.mts +54 -0
- package/dist/common/script/index.d.ts +54 -0
- package/dist/common/script/index.mjs +1 -0
- package/dist/common/validation/index.cjs +1 -0
- package/dist/common/validation/index.d.cts +93 -0
- package/dist/common/validation/index.d.mts +93 -0
- package/dist/common/validation/index.d.ts +93 -0
- package/dist/common/validation/index.mjs +1 -0
- package/dist/factory/index.cjs +1 -1
- package/dist/factory/index.d.cts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.d.ts +1 -1
- package/dist/factory/index.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +15 -3
- package/dist/index.d.mts +15 -3
- package/dist/index.d.ts +15 -3
- package/dist/index.mjs +1 -1
- package/dist/plugins/buildProgress/index.cjs +2 -0
- package/dist/plugins/buildProgress/index.d.cts +187 -0
- package/dist/plugins/buildProgress/index.d.mts +187 -0
- package/dist/plugins/buildProgress/index.d.ts +187 -0
- package/dist/plugins/buildProgress/index.mjs +2 -0
- package/dist/plugins/copyFile/index.cjs +1 -0
- package/dist/plugins/copyFile/index.d.cts +78 -0
- package/dist/plugins/copyFile/index.d.mts +78 -0
- package/dist/plugins/copyFile/index.d.ts +78 -0
- package/dist/plugins/copyFile/index.mjs +1 -0
- package/dist/plugins/faviconManager/index.cjs +1 -0
- package/dist/plugins/faviconManager/index.d.cts +143 -0
- package/dist/plugins/faviconManager/index.d.mts +143 -0
- package/dist/plugins/faviconManager/index.d.ts +143 -0
- package/dist/plugins/faviconManager/index.mjs +1 -0
- package/dist/plugins/generateRouter/index.cjs +35 -0
- package/dist/plugins/generateRouter/index.d.cts +215 -0
- package/dist/plugins/generateRouter/index.d.mts +215 -0
- package/dist/plugins/generateRouter/index.d.ts +215 -0
- package/dist/plugins/generateRouter/index.mjs +35 -0
- package/dist/plugins/generateVersion/index.cjs +1 -0
- package/dist/plugins/generateVersion/index.d.cts +184 -0
- package/dist/plugins/generateVersion/index.d.mts +184 -0
- package/dist/plugins/generateVersion/index.d.ts +184 -0
- package/dist/plugins/generateVersion/index.mjs +1 -0
- package/dist/plugins/htmlInject/index.cjs +7 -0
- package/dist/plugins/htmlInject/index.d.cts +278 -0
- package/dist/plugins/htmlInject/index.d.mts +278 -0
- package/dist/plugins/htmlInject/index.d.ts +278 -0
- package/dist/plugins/htmlInject/index.mjs +7 -0
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.d.cts +10 -1520
- package/dist/plugins/index.d.mts +10 -1520
- package/dist/plugins/index.d.ts +10 -1520
- package/dist/plugins/index.mjs +1 -1
- package/dist/plugins/loadingManager/index.cjs +487 -0
- package/dist/plugins/loadingManager/index.d.cts +769 -0
- package/dist/plugins/loadingManager/index.d.mts +769 -0
- package/dist/plugins/loadingManager/index.d.ts +769 -0
- package/dist/plugins/loadingManager/index.mjs +487 -0
- package/dist/plugins/versionUpdateChecker/index.cjs +185 -0
- package/dist/plugins/versionUpdateChecker/index.d.cts +200 -0
- package/dist/plugins/versionUpdateChecker/index.d.mts +200 -0
- package/dist/plugins/versionUpdateChecker/index.d.ts +200 -0
- package/dist/plugins/versionUpdateChecker/index.mjs +185 -0
- package/dist/shared/vite-plugin.Bcg6RW2N.cjs +3 -0
- package/dist/shared/{vite-plugin.CiHfwMiN.d.cts → vite-plugin.DRRlWY8P.d.cts} +50 -0
- package/dist/shared/{vite-plugin.CiHfwMiN.d.mts → vite-plugin.DRRlWY8P.d.mts} +50 -0
- package/dist/shared/{vite-plugin.CiHfwMiN.d.ts → vite-plugin.DRRlWY8P.d.ts} +50 -0
- package/dist/shared/{vite-plugin.B88RyRN8.mjs → vite-plugin.DcExl6jd.mjs} +2 -2
- package/package.json +72 -2
- package/dist/shared/vite-plugin.BI4kA-bR.mjs +0 -526
- package/dist/shared/vite-plugin.Ba9646wL.cjs +0 -1
- package/dist/shared/vite-plugin.C3ejdBNf.mjs +0 -1
- package/dist/shared/vite-plugin.CawoITTT.cjs +0 -1
- package/dist/shared/vite-plugin.CsdNNQ-4.cjs +0 -526
- package/dist/shared/vite-plugin.DSb6XzBn.mjs +0 -1
- package/dist/shared/vite-plugin.IGZeStMa.cjs +0 -3
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
## 特性
|
|
17
17
|
|
|
18
|
-
- **开箱即用** - 提供
|
|
18
|
+
- **开箱即用** - 提供 8 个实用插件,覆盖构建进度展示、文件复制、路由生成、版本管理、版本更新检查、HTML 注入、图标注入、全局 Loading 状态管理等常见场景
|
|
19
19
|
- **插件开发框架** - 导出 BasePlugin、Logger、Validator 等核心组件,快速构建符合规范的自定义 Vite 插件
|
|
20
20
|
- **完整生命周期** - 支持初始化、配置解析、销毁等生命周期管理,自动组合钩子逻辑
|
|
21
21
|
- **类型安全** - 完整的 TypeScript 类型定义,配置验证器确保参数正确性
|
|
@@ -46,7 +46,7 @@ pnpm add @meng-xi/vite-plugin -D
|
|
|
46
46
|
|
|
47
47
|
```typescript
|
|
48
48
|
import { defineConfig } from 'vite'
|
|
49
|
-
import { buildProgress, copyFile, generateRouter, generateVersion,
|
|
49
|
+
import { buildProgress, copyFile, generateRouter, generateVersion, versionUpdateChecker, htmlInject, faviconManager, loadingManager } from '@meng-xi/vite-plugin'
|
|
50
50
|
|
|
51
51
|
export default defineConfig({
|
|
52
52
|
plugins: [
|
|
@@ -71,11 +71,25 @@ export default defineConfig({
|
|
|
71
71
|
outputType: 'both'
|
|
72
72
|
}),
|
|
73
73
|
|
|
74
|
+
// 版本更新检查(配合 generateVersion 使用)
|
|
75
|
+
versionUpdateChecker(),
|
|
76
|
+
|
|
77
|
+
// HTML 内容注入
|
|
78
|
+
htmlInject({
|
|
79
|
+
rules: [
|
|
80
|
+
{
|
|
81
|
+
id: 'meta-description',
|
|
82
|
+
content: '<meta name="description" content="My App">',
|
|
83
|
+
position: 'head-end'
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}),
|
|
87
|
+
|
|
74
88
|
// 注入网站图标(支持字符串简写)
|
|
75
|
-
|
|
89
|
+
faviconManager('/assets'),
|
|
76
90
|
|
|
77
|
-
//
|
|
78
|
-
|
|
91
|
+
// 全局 Loading 状态管理
|
|
92
|
+
loadingManager({
|
|
79
93
|
defaultVisible: true,
|
|
80
94
|
autoHideOn: 'DOMContentLoaded'
|
|
81
95
|
})
|
|
@@ -97,238 +111,18 @@ const routerPlugin = generateRouter({ watch: true }) as PluginWithInstance<Gener
|
|
|
97
111
|
console.log(routerPlugin.pluginInstance?.options)
|
|
98
112
|
```
|
|
99
113
|
|
|
100
|
-
### 开发自定义插件
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin'
|
|
104
|
-
import type { BasePluginOptions, PluginWithInstance } from '@meng-xi/vite-plugin/factory'
|
|
105
|
-
import type { Plugin } from 'vite'
|
|
106
|
-
|
|
107
|
-
interface MyPluginOptions extends BasePluginOptions {
|
|
108
|
-
path: string
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
class MyPlugin extends BasePlugin<MyPluginOptions> {
|
|
112
|
-
protected getDefaultOptions() {
|
|
113
|
-
return { path: './default' }
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
protected validateOptions(): void {
|
|
117
|
-
this.validator.field('path').required().string().validate()
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
protected getPluginName(): string {
|
|
121
|
-
return 'my-plugin'
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
protected addPluginHooks(plugin: Plugin): void {
|
|
125
|
-
plugin.buildStart = () => {
|
|
126
|
-
this.logger.info(`Plugin started with path: ${this.options.path}`)
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
protected destroy(): void {
|
|
131
|
-
super.destroy()
|
|
132
|
-
// 自定义清理逻辑,如关闭连接、停止监听等
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// 基本使用
|
|
137
|
-
export const myPlugin = createPluginFactory(MyPlugin)
|
|
138
|
-
|
|
139
|
-
// 带标准化器(支持字符串简写配置)
|
|
140
|
-
export const myPluginWithNormalizer = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
141
|
-
// 使用时支持简写:myPluginWithNormalizer('./custom-path')
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## 插件开发框架
|
|
145
|
-
|
|
146
|
-
### BasePlugin 核心概念
|
|
147
|
-
|
|
148
|
-
`BasePlugin` 是所有插件的基类,提供了完整的生命周期管理和开发规范:
|
|
149
|
-
|
|
150
|
-
#### 生命周期
|
|
151
|
-
|
|
152
|
-
| 阶段 | 方法 | 说明 |
|
|
153
|
-
| -------- | ------------------ | -------------------------------------- |
|
|
154
|
-
| 初始化 | `constructor` | 合并配置、初始化日志和验证器 |
|
|
155
|
-
| 配置解析 | `onConfigResolved` | Vite 配置解析完成时调用 |
|
|
156
|
-
| 钩子注册 | `addPluginHooks` | 注册 Vite 插件钩子 |
|
|
157
|
-
| 销毁 | `destroy` | `closeBundle` 时自动调用,用于清理资源 |
|
|
158
|
-
|
|
159
|
-
#### 钩子自动组合
|
|
160
|
-
|
|
161
|
-
`toPlugin()` 方法会自动组合以下钩子:
|
|
162
|
-
|
|
163
|
-
- **configResolved** - 先执行基类的 `onConfigResolved`,再执行子类注册的钩子
|
|
164
|
-
- **closeBundle** - 先执行子类注册的钩子,再执行基类的 `destroy`
|
|
165
|
-
|
|
166
|
-
> 子类无需手动注册 `closeBundle` 钩子来清理资源,只需重写 `destroy()` 方法即可。
|
|
167
|
-
|
|
168
|
-
#### 必须实现的方法
|
|
169
|
-
|
|
170
|
-
| 方法 | 说明 |
|
|
171
|
-
| ------------------------ | ------------------ |
|
|
172
|
-
| `getPluginName()` | 返回插件名称 |
|
|
173
|
-
| `addPluginHooks(plugin)` | 添加 Vite 插件钩子 |
|
|
174
|
-
|
|
175
|
-
#### 可选重写的方法
|
|
176
|
-
|
|
177
|
-
| 方法 | 默认行为 | 说明 |
|
|
178
|
-
| -------------------------- | ----------- | ---------------------------------- |
|
|
179
|
-
| `getDefaultOptions()` | 返回 `{}` | 提供插件默认配置 |
|
|
180
|
-
| `validateOptions()` | 无验证 | 验证配置参数 |
|
|
181
|
-
| `getEnforce()` | `undefined` | 插件执行时机(`'pre'` / `'post'`) |
|
|
182
|
-
| `onConfigResolved(config)` | 存储配置 | 配置解析完成回调 |
|
|
183
|
-
| `destroy()` | 注销日志 | 插件销毁时的清理逻辑 |
|
|
184
|
-
|
|
185
|
-
#### 内置属性
|
|
186
|
-
|
|
187
|
-
| 属性 | 类型 | 说明 |
|
|
188
|
-
| ------------ | ------------------------ | ----------------- |
|
|
189
|
-
| `options` | `Required<T>` | 合并后的完整配置 |
|
|
190
|
-
| `logger` | `PluginLogger` | 插件日志记录器 |
|
|
191
|
-
| `validator` | `Validator<T>` | 配置验证器 |
|
|
192
|
-
| `viteConfig` | `ResolvedConfig \| null` | Vite 解析后的配置 |
|
|
193
|
-
|
|
194
|
-
#### 错误处理策略
|
|
195
|
-
|
|
196
|
-
通过 `errorStrategy` 配置项控制错误行为:
|
|
197
|
-
|
|
198
|
-
- `'throw'`(默认)- 记录错误并抛出异常,中断构建
|
|
199
|
-
- `'log'` - 记录错误但不抛出,继续执行
|
|
200
|
-
- `'ignore'` - 记录错误但不抛出,继续执行
|
|
201
|
-
|
|
202
|
-
使用 `safeExecute` / `safeExecuteSync` 包裹可能出错的操作:
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
// 异步安全执行
|
|
206
|
-
const result = await this.safeExecute(async () => {
|
|
207
|
-
return await someAsyncOperation()
|
|
208
|
-
}, '执行异步操作')
|
|
209
|
-
|
|
210
|
-
// 同步安全执行
|
|
211
|
-
const value = this.safeExecuteSync(() => {
|
|
212
|
-
return someSyncOperation()
|
|
213
|
-
}, '执行同步操作')
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### createPluginFactory
|
|
217
|
-
|
|
218
|
-
创建插件工厂函数,支持选项标准化器:
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
// 基本使用
|
|
222
|
-
const myPlugin = createPluginFactory(MyPlugin)
|
|
223
|
-
|
|
224
|
-
// 带标准化器(支持字符串简写配置)
|
|
225
|
-
const myPlugin = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
226
|
-
|
|
227
|
-
// 使用时支持简写
|
|
228
|
-
myPlugin('./custom-path')
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### Validator
|
|
232
|
-
|
|
233
|
-
流畅的配置验证器,支持链式调用:
|
|
234
|
-
|
|
235
|
-
```typescript
|
|
236
|
-
import { Validator } from '@meng-xi/vite-plugin/common'
|
|
237
|
-
|
|
238
|
-
const validator = new Validator(options)
|
|
239
|
-
validator
|
|
240
|
-
.field('sourceDir')
|
|
241
|
-
.required()
|
|
242
|
-
.string()
|
|
243
|
-
.field('targetDir')
|
|
244
|
-
.required()
|
|
245
|
-
.string()
|
|
246
|
-
.field('overwrite')
|
|
247
|
-
.boolean()
|
|
248
|
-
.default(true)
|
|
249
|
-
.field('port')
|
|
250
|
-
.number()
|
|
251
|
-
.field('list')
|
|
252
|
-
.array()
|
|
253
|
-
.field('config')
|
|
254
|
-
.object()
|
|
255
|
-
.field('name')
|
|
256
|
-
.custom(val => val.length > 0, 'name 不能为空')
|
|
257
|
-
.validate()
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
| 方法 | 说明 |
|
|
261
|
-
| ------------ | -------------------------------------------------- |
|
|
262
|
-
| `field()` | 指定要验证的字段 |
|
|
263
|
-
| `required()` | 标记字段为必填 |
|
|
264
|
-
| `string()` | 验证字段值是否为字符串类型 |
|
|
265
|
-
| `boolean()` | 验证字段值是否为布尔类型 |
|
|
266
|
-
| `number()` | 验证字段值是否为数字类型 |
|
|
267
|
-
| `array()` | 验证字段值是否为数组类型 |
|
|
268
|
-
| `object()` | 验证字段值是否为对象类型 |
|
|
269
|
-
| `default()` | 为字段设置默认值(仅当值为 undefined/null 时生效) |
|
|
270
|
-
| `custom()` | 使用自定义函数验证字段值 |
|
|
271
|
-
| `validate()` | 执行验证,失败时抛出错误 |
|
|
272
|
-
|
|
273
|
-
### Logger
|
|
274
|
-
|
|
275
|
-
全局单例日志管理器,为每个插件提供独立的日志控制:
|
|
276
|
-
|
|
277
|
-
```typescript
|
|
278
|
-
import { Logger } from '@meng-xi/vite-plugin/logger'
|
|
279
|
-
|
|
280
|
-
// 创建日志记录器(通常由 BasePlugin 自动调用)
|
|
281
|
-
Logger.create({ name: 'my-plugin', enabled: true })
|
|
282
|
-
|
|
283
|
-
// 注销插件日志配置(插件销毁时自动调用)
|
|
284
|
-
Logger.unregister('my-plugin')
|
|
285
|
-
|
|
286
|
-
// 销毁单例(测试场景使用)
|
|
287
|
-
Logger.destroy()
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
日志输出格式:
|
|
291
|
-
|
|
292
|
-
```
|
|
293
|
-
ℹ️ [@meng-xi/vite-plugin:my-plugin] Info message
|
|
294
|
-
✅ [@meng-xi/vite-plugin:my-plugin] Success message
|
|
295
|
-
⚠️ [@meng-xi/vite-plugin:my-plugin] Warning message
|
|
296
|
-
❌ [@meng-xi/vite-plugin:my-plugin] Error message
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### 通用工具函数
|
|
300
|
-
|
|
301
|
-
通过 `@meng-xi/vite-plugin/common` 导出,可在自定义插件中复用:
|
|
302
|
-
|
|
303
|
-
```typescript
|
|
304
|
-
import { deepMerge, formatDate, parseTemplate, toCamelCase, toPascalCase, stripJsonComments, generateRandomHash, Validator } from '@meng-xi/vite-plugin/common'
|
|
305
|
-
import { readFileContent, writeFileContent, fileExists, copySourceToTarget } from '@meng-xi/vite-plugin/common'
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
| 函数 | 说明 |
|
|
309
|
-
| ---------------------- | -------------------------------------------------- |
|
|
310
|
-
| `deepMerge()` | 深度合并对象(undefined 不覆盖,数组直接覆盖) |
|
|
311
|
-
| `formatDate()` | 格式化日期,支持 `{YYYY}`, `{MM}`, `{DD}` 等占位符 |
|
|
312
|
-
| `parseTemplate()` | 解析模板字符串,替换占位符 |
|
|
313
|
-
| `toCamelCase()` | 转换为驼峰命名(camelCase) |
|
|
314
|
-
| `toPascalCase()` | 转换为帕斯卡命名(PascalCase) |
|
|
315
|
-
| `stripJsonComments()` | 移除 JSON 字符串中的注释 |
|
|
316
|
-
| `generateRandomHash()` | 生成随机哈希字符串(1-64 位) |
|
|
317
|
-
| `readFileContent()` | 异步读取文件内容 |
|
|
318
|
-
| `writeFileContent()` | 异步写入文件内容 |
|
|
319
|
-
| `fileExists()` | 异步检查文件是否存在 |
|
|
320
|
-
| `copySourceToTarget()` | 复制文件或目录,支持增量复制和并发控制 |
|
|
321
|
-
|
|
322
114
|
## 内置插件
|
|
323
115
|
|
|
324
|
-
| 插件
|
|
325
|
-
|
|
|
326
|
-
| buildProgress
|
|
327
|
-
| copyFile
|
|
328
|
-
| generateRouter
|
|
329
|
-
| generateVersion
|
|
330
|
-
|
|
|
331
|
-
|
|
|
116
|
+
| 插件 | 说明 |
|
|
117
|
+
| -------------------- | --------------------------------------------------------------- |
|
|
118
|
+
| buildProgress | 终端实时构建进度条,支持 bar / spinner / minimal |
|
|
119
|
+
| copyFile | 构建完成后复制文件或目录,支持增量复制 |
|
|
120
|
+
| generateRouter | 根据 pages.json 自动生成路由配置(uni-app) |
|
|
121
|
+
| generateVersion | 自动生成版本号,支持文件输出和全局变量注入 |
|
|
122
|
+
| versionUpdateChecker | 运行时版本更新检查,支持多种提示样式和自定义回调 |
|
|
123
|
+
| htmlInject | HTML 内容注入,支持多种位置、条件注入、模板变量替换和安全过滤 |
|
|
124
|
+
| faviconManager | 管理网站图标(favicon)链接注入到 HTML 文件,支持字符串简写配置 |
|
|
125
|
+
| loadingManager | 全局 Loading 状态管理,支持请求拦截和白屏 Loading |
|
|
332
126
|
|
|
333
127
|
### buildProgress
|
|
334
128
|
|
|
@@ -531,7 +325,166 @@ generateVersion({
|
|
|
531
325
|
})
|
|
532
326
|
```
|
|
533
327
|
|
|
534
|
-
###
|
|
328
|
+
### versionUpdateChecker
|
|
329
|
+
|
|
330
|
+
在运行时定期检查版本号变更,发现新版本时提示用户刷新页面。通常与 `generateVersion` 插件配合使用。
|
|
331
|
+
|
|
332
|
+
**工作原理:**
|
|
333
|
+
|
|
334
|
+
1. `generateVersion` 在构建时生成版本号文件(`version.json`)或注入全局变量
|
|
335
|
+
2. `versionUpdateChecker` 在运行时定期请求版本文件,与当前版本对比
|
|
336
|
+
3. 发现版本不一致时,弹出提示引导用户刷新
|
|
337
|
+
|
|
338
|
+
| 选项 | 类型 | 默认值 | 描述 |
|
|
339
|
+
| ----------------------- | ------------------------------------ | ------------------------------------------ | ------------------------------------ |
|
|
340
|
+
| versionSource | `'define'` \| `'file'` \| `'auto'` | `'auto'` | 当前版本号来源 |
|
|
341
|
+
| defineName | `string` | `'__APP_VERSION__'` | define 模式下的全局变量名 |
|
|
342
|
+
| checkUrl | `string` | `'/version.json'` | 版本检查文件的 URL 路径 |
|
|
343
|
+
| checkInterval | `number` | `300000` | 检查间隔时间(毫秒,默认 5 分钟) |
|
|
344
|
+
| checkOnVisibilityChange | `boolean` | `true` | 页面可见性变化时是否立即检查 |
|
|
345
|
+
| enableInDev | `boolean` | `false` | 是否在开发模式下启用 |
|
|
346
|
+
| promptStyle | `'modal'` \| `'banner'` \| `'toast'` | `'modal'` | 更新提示 UI 样式 |
|
|
347
|
+
| promptMessage | `string` | `'发现新版本,是否立即刷新获取最新内容?'` | 提示消息文本 |
|
|
348
|
+
| refreshButtonText | `string` | `'立即刷新'` | 刷新按钮文本 |
|
|
349
|
+
| dismissButtonText | `string` | `'稍后再说'` | 忽略按钮文本 |
|
|
350
|
+
| customPromptTemplate | `string` | - | 自定义提示 UI 的 HTML 模板 |
|
|
351
|
+
| customStyle | `string` | - | 自定义 CSS 样式字符串 |
|
|
352
|
+
| onUpdateAvailable | `string` | - | 发现新版本时的回调(函数体字符串) |
|
|
353
|
+
| onRefresh | `string` | - | 用户选择刷新时的回调(函数体字符串) |
|
|
354
|
+
| onDismiss | `string` | - | 用户选择忽略时的回调(函数体字符串) |
|
|
355
|
+
|
|
356
|
+
> `versionSource` 说明:`'define'` 从全局变量读取,`'file'` 从版本文件读取,`'auto'` 优先使用 define,回退到 file。自定义模板中可使用
|
|
357
|
+
> `{{message}}`、`{{currentVersion}}`、`{{newVersion}}`、`{{refreshButton}}`、`{{dismissButton}}` 占位符。回调以函数体字符串形式提供,可用变量:`currentVersion`、`newVersion`。
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
// 基本使用(配合 generateVersion)
|
|
361
|
+
generateVersion({ outputType: 'both' })
|
|
362
|
+
versionUpdateChecker()
|
|
363
|
+
|
|
364
|
+
// 仅从版本文件读取
|
|
365
|
+
versionUpdateChecker({ versionSource: 'file' })
|
|
366
|
+
|
|
367
|
+
// 自定义检查间隔和提示样式
|
|
368
|
+
versionUpdateChecker({
|
|
369
|
+
checkInterval: 60000,
|
|
370
|
+
promptStyle: 'banner'
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
// 底部轻提示
|
|
374
|
+
versionUpdateChecker({ promptStyle: 'toast' })
|
|
375
|
+
|
|
376
|
+
// 自定义提示文本
|
|
377
|
+
versionUpdateChecker({
|
|
378
|
+
promptMessage: '系统已更新,建议刷新体验新功能',
|
|
379
|
+
refreshButtonText: '更新',
|
|
380
|
+
dismissButtonText: '取消'
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
// 自定义回调
|
|
384
|
+
versionUpdateChecker({
|
|
385
|
+
onUpdateAvailable: 'console.log("新版本:", newVersion); return true;',
|
|
386
|
+
onRefresh: 'console.log("用户选择刷新");',
|
|
387
|
+
onDismiss: 'console.log("用户选择忽略");'
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
// 开发环境也启用(调试用)
|
|
391
|
+
versionUpdateChecker({ enableInDev: true })
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### htmlInject
|
|
395
|
+
|
|
396
|
+
在 Vite 构建过程中根据配置规则将 HTML 内容注入到目标文件中,支持多种注入位置、条件注入、模板变量替换和安全过滤。
|
|
397
|
+
|
|
398
|
+
**注入位置:**
|
|
399
|
+
|
|
400
|
+
| 位置 | 说明 |
|
|
401
|
+
| ------------------ | -------------------------- |
|
|
402
|
+
| `head-start` | 注入到 `<head>` 标签开始后 |
|
|
403
|
+
| `head-end` | 注入到 `</head>` 标签前 |
|
|
404
|
+
| `body-start` | 注入到 `<body>` 标签开始后 |
|
|
405
|
+
| `body-end` | 注入到 `</body>` 标签前 |
|
|
406
|
+
| `before-selector` | 注入到选择器匹配内容前 |
|
|
407
|
+
| `after-selector` | 注入到选择器匹配内容后 |
|
|
408
|
+
| `replace-selector` | 替换选择器匹配的内容 |
|
|
409
|
+
|
|
410
|
+
| 选项 | 类型 | 默认值 | 描述 |
|
|
411
|
+
| ------------ | ------------------------ | -------------- | -------------------------- |
|
|
412
|
+
| targetFile | `string` | `'index.html'` | 目标 HTML 文件路径或文件名 |
|
|
413
|
+
| rules | `InjectRule[]` | - | 注入规则数组(必填) |
|
|
414
|
+
| security | `SecurityConfig` | - | 安全过滤配置 |
|
|
415
|
+
| templateVars | `Record<string, string>` | - | 全局模板变量 |
|
|
416
|
+
| logInjection | `boolean` | `true` | 是否输出注入日志 |
|
|
417
|
+
|
|
418
|
+
**InjectRule**
|
|
419
|
+
|
|
420
|
+
| 属性 | 类型 | 默认值 | 描述 |
|
|
421
|
+
| -------------------- | ------------------------ | ---------- | ----------------------------------- |
|
|
422
|
+
| id | `string` | - | 规则唯一标识,用于日志和调试 |
|
|
423
|
+
| content | `string` | - | 要注入的 HTML 内容(必填) |
|
|
424
|
+
| position | `InjectPosition` | - | 注入位置(必填) |
|
|
425
|
+
| selector | `string` | - | 选择器字符串(selector 位置时必填) |
|
|
426
|
+
| selectorMatch | `'string'` \| `'regex'` | `'string'` | 选择器匹配模式 |
|
|
427
|
+
| priority | `number` | `100` | 优先级,数值越小越先执行 |
|
|
428
|
+
| condition | `InjectCondition` | - | 注入条件 |
|
|
429
|
+
| templateVars | `Record<string, string>` | - | 规则级模板变量(覆盖全局) |
|
|
430
|
+
| allowScriptInjection | `boolean` | `false` | 是否允许注入脚本等危险内容 |
|
|
431
|
+
|
|
432
|
+
**InjectCondition**
|
|
433
|
+
|
|
434
|
+
| 属性 | 类型 | 默认值 | 描述 |
|
|
435
|
+
| ------ | ------------------------------------------- | ------- | ------------------ |
|
|
436
|
+
| type | `'env'` \| `'file-contains'` \| `'custom'` | - | 条件类型(必填) |
|
|
437
|
+
| value | `string` \| `((...args: any[]) => boolean)` | - | 条件值(必填) |
|
|
438
|
+
| negate | `boolean` | `false` | 是否对条件结果取反 |
|
|
439
|
+
|
|
440
|
+
**SecurityConfig**
|
|
441
|
+
|
|
442
|
+
| 属性 | 类型 | 默认值 | 描述 |
|
|
443
|
+
| ------------------------ | ---------- | ------ | -------------------- |
|
|
444
|
+
| blockDangerousTags | `boolean` | `true` | 是否阻止危险标签 |
|
|
445
|
+
| blockDangerousAttributes | `boolean` | `true` | 是否阻止危险属性 |
|
|
446
|
+
| allowedTags | `string[]` | - | 允许通过的标签白名单 |
|
|
447
|
+
| blockedTags | `string[]` | - | 自定义阻止标签列表 |
|
|
448
|
+
| blockedAttributes | `string[]` | - | 自定义阻止属性列表 |
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
// 基本使用
|
|
452
|
+
htmlInject({
|
|
453
|
+
rules: [{ id: 'meta-desc', content: '<meta name="description" content="My App">', position: 'head-end' }]
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
// 条件注入(仅生产环境)
|
|
457
|
+
htmlInject({
|
|
458
|
+
rules: [
|
|
459
|
+
{
|
|
460
|
+
id: 'analytics',
|
|
461
|
+
content: '<script src="/analytics.js"></script>',
|
|
462
|
+
position: 'body-end',
|
|
463
|
+
condition: { type: 'env', value: 'PRODUCTION' },
|
|
464
|
+
allowScriptInjection: true
|
|
465
|
+
}
|
|
466
|
+
]
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
// 模板变量替换
|
|
470
|
+
htmlInject({
|
|
471
|
+
templateVars: { appName: 'My App', version: '1.0.0' },
|
|
472
|
+
rules: [{ id: 'meta', content: '<meta name="description" content="{{appName}}">', position: 'head-end' }]
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
// 选择器注入
|
|
476
|
+
htmlInject({
|
|
477
|
+
rules: [{ id: 'replace-title', content: '<title>New Title</title>', position: 'replace-selector', selector: '<title>.*</title>', selectorMatch: 'regex' }]
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
// 安全配置
|
|
481
|
+
htmlInject({
|
|
482
|
+
security: { blockDangerousTags: true, allowedTags: ['iframe'] },
|
|
483
|
+
rules: [{ id: 'embed', content: '<iframe src="https://example.com"></iframe>', position: 'body-end' }]
|
|
484
|
+
})
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### faviconManager
|
|
535
488
|
|
|
536
489
|
在 Vite 构建过程中将网站图标链接注入到 HTML 文件的 head 中。支持字符串简写配置。
|
|
537
490
|
|
|
@@ -565,13 +518,13 @@ generateVersion({
|
|
|
565
518
|
|
|
566
519
|
```typescript
|
|
567
520
|
// 使用默认配置
|
|
568
|
-
|
|
521
|
+
faviconManager()
|
|
569
522
|
|
|
570
523
|
// 字符串简写(设置 base 路径)
|
|
571
|
-
|
|
524
|
+
faviconManager('/assets')
|
|
572
525
|
|
|
573
526
|
// 自定义图标数组
|
|
574
|
-
|
|
527
|
+
faviconManager({
|
|
575
528
|
base: '/assets',
|
|
576
529
|
icons: [
|
|
577
530
|
{ rel: 'icon', href: '/favicon.svg', type: 'image/svg+xml' },
|
|
@@ -581,12 +534,12 @@ injectIco({
|
|
|
581
534
|
})
|
|
582
535
|
|
|
583
536
|
// 自定义完整 link 标签
|
|
584
|
-
|
|
537
|
+
faviconManager({
|
|
585
538
|
link: '<link rel="icon" href="/favicon.svg" type="image/svg+xml" />'
|
|
586
539
|
})
|
|
587
540
|
|
|
588
541
|
// 带文件复制
|
|
589
|
-
|
|
542
|
+
faviconManager({
|
|
590
543
|
base: '/assets',
|
|
591
544
|
copyOptions: {
|
|
592
545
|
sourceDir: 'src/assets/icons',
|
|
@@ -595,7 +548,7 @@ injectIco({
|
|
|
595
548
|
})
|
|
596
549
|
```
|
|
597
550
|
|
|
598
|
-
###
|
|
551
|
+
### loadingManager
|
|
599
552
|
|
|
600
553
|
注入全局 Loading 状态管理,支持 XHR/Fetch 请求拦截、白屏 Loading、自定义样式和生命周期回调。
|
|
601
554
|
|
|
@@ -709,30 +662,30 @@ injectIco({
|
|
|
709
662
|
|
|
710
663
|
```typescript
|
|
711
664
|
// 白屏 Loading:页面加载即显示,DOM 就绪后自动隐藏
|
|
712
|
-
|
|
665
|
+
loadingManager({ defaultVisible: true, autoHideOn: 'DOMContentLoaded' })
|
|
713
666
|
|
|
714
667
|
// 白屏 Loading:所有资源加载完成后隐藏
|
|
715
|
-
|
|
668
|
+
loadingManager({ defaultVisible: true, autoHideOn: 'load' })
|
|
716
669
|
|
|
717
670
|
// Vue/React SPA:白屏即显示,框架渲染完成后手动隐藏
|
|
718
|
-
|
|
671
|
+
loadingManager({ defaultVisible: true, autoHideOn: 'manual' })
|
|
719
672
|
// 在应用入口处:window.__LOADING_MANAGER__.hide()
|
|
720
673
|
|
|
721
674
|
// 自动拦截所有请求
|
|
722
|
-
|
|
675
|
+
loadingManager({ autoBind: 'all' })
|
|
723
676
|
|
|
724
677
|
// 自定义样式 + 请求过滤
|
|
725
|
-
|
|
678
|
+
loadingManager({
|
|
726
679
|
style: { overlayColor: 'rgba(0,0,0,0.5)', spinnerColor: '#fff', backdropBlur: true },
|
|
727
680
|
autoBind: 'fetch',
|
|
728
681
|
requestFilter: { excludeUrls: [/\/api\/health/], excludeUrlPrefixes: ['http://localhost'] }
|
|
729
682
|
})
|
|
730
683
|
|
|
731
684
|
// 防抖隐藏(避免快速闪烁)
|
|
732
|
-
|
|
685
|
+
loadingManager({ debounceHide: { enabled: true, duration: 100 } })
|
|
733
686
|
|
|
734
687
|
// 生命周期回调
|
|
735
|
-
|
|
688
|
+
loadingManager({
|
|
736
689
|
callbacks: {
|
|
737
690
|
onBeforeShow: 'if (shouldSkip) return false;',
|
|
738
691
|
onShow: 'console.log("loading shown")',
|
|
@@ -742,31 +695,275 @@ injectLoading({
|
|
|
742
695
|
})
|
|
743
696
|
|
|
744
697
|
// 手动控制
|
|
745
|
-
|
|
698
|
+
loadingManager()
|
|
746
699
|
window.__LOADING_MANAGER__.show('正在保存...')
|
|
747
700
|
window.__LOADING_MANAGER__.hide()
|
|
748
701
|
window.__LOADING_MANAGER__.toggle()
|
|
749
702
|
window.__LOADING_MANAGER__.disablePointerEvents()
|
|
750
703
|
```
|
|
751
704
|
|
|
705
|
+
## 通用工具函数
|
|
706
|
+
|
|
707
|
+
通过 `@meng-xi/vite-plugin/common` 导出,可在自定义插件中复用:
|
|
708
|
+
|
|
709
|
+
```typescript
|
|
710
|
+
import { deepMerge, formatDate, parseTemplate, toCamelCase, toPascalCase, stripJsonComments, generateRandomHash, escapeHtmlAttr, Validator } from '@meng-xi/vite-plugin/common'
|
|
711
|
+
import { readFileContent, writeFileContent, fileExists, copySourceToTarget } from '@meng-xi/vite-plugin/common/fs'
|
|
712
|
+
import { injectBeforeTag, injectHtmlByPriority, injectBeforeTagWithFallback, injectHeadAndBody } from '@meng-xi/vite-plugin/common/html'
|
|
713
|
+
import { makeCallback, containsScriptTag, validateIdentifierName } from '@meng-xi/vite-plugin/common/script'
|
|
714
|
+
import { validateGlobalName, validateNoScriptInTemplate, validateCallbackFields, validateNonNegativeNumber, validateNestedDuration, validateEnumValue } from '@meng-xi/vite-plugin/common/validation'
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
| 函数 | 说明 | 子路径 |
|
|
718
|
+
| ------------------------------- | --------------------------------------------------------------- | ------------------- |
|
|
719
|
+
| `deepMerge()` | 深度合并对象(undefined 不覆盖,数组直接覆盖) | `common/object` |
|
|
720
|
+
| `formatDate()` | 格式化日期,支持 `{YYYY}`, `{MM}`, `{DD}` 等占位符 | `common/format` |
|
|
721
|
+
| `parseTemplate()` | 解析模板字符串,替换占位符 | `common/format` |
|
|
722
|
+
| `toCamelCase()` | 转换为驼峰命名(camelCase) | `common/format` |
|
|
723
|
+
| `toPascalCase()` | 转换为帕斯卡命名(PascalCase) | `common/format` |
|
|
724
|
+
| `stripJsonComments()` | 移除 JSON 字符串中的注释 | `common/format` |
|
|
725
|
+
| `generateRandomHash()` | 生成随机哈希字符串(1-64 位) | `common/format` |
|
|
726
|
+
| `escapeHtmlAttr()` | 转义 HTML 属性值中的特殊字符,防止 XSS 注入 | `common/format` |
|
|
727
|
+
| `readFileContent()` | 异步读取文件内容 | `common/fs` |
|
|
728
|
+
| `writeFileContent()` | 异步写入文件内容 | `common/fs` |
|
|
729
|
+
| `fileExists()` | 异步检查文件是否存在 | `common/fs` |
|
|
730
|
+
| `copySourceToTarget()` | 复制文件或目录,支持增量复制和并发控制 | `common/fs` |
|
|
731
|
+
| `injectBeforeTag()` | 在 HTML 指定闭合标签前注入代码 | `common/html` |
|
|
732
|
+
| `injectHtmlByPriority()` | 按优先级向 HTML 中注入代码(`</head>` → `</body>` → `</html>`) | `common/html` |
|
|
733
|
+
| `injectBeforeTagWithFallback()` | 带回退策略的 HTML 注入(`</body>` → `</html>` → 末尾) | `common/html` |
|
|
734
|
+
| `injectHeadAndBody()` | 双区域 HTML 注入(head + body) | `common/html` |
|
|
735
|
+
| `makeCallback()` | 将回调函数体包装为安全的函数表达式(含 try-catch) | `common/script` |
|
|
736
|
+
| `containsScriptTag()` | 检测字符串是否包含 `<script>` 标签 | `common/script` |
|
|
737
|
+
| `validateIdentifierName()` | 验证字符串是否为合法的 JavaScript 标识符,防止原型污染 | `common/script` |
|
|
738
|
+
| `validateGlobalName()` | 验证全局变量名的合法性 | `common/validation` |
|
|
739
|
+
| `validateNoScriptInTemplate()` | 验证模板字符串不包含 script 标签(XSS 防护) | `common/validation` |
|
|
740
|
+
| `validateCallbackFields()` | 验证回调字段不包含 script 标签 | `common/validation` |
|
|
741
|
+
| `validateNonNegativeNumber()` | 验证数值为非负数 | `common/validation` |
|
|
742
|
+
| `validateNestedDuration()` | 验证嵌套配置项的 duration 合法性 | `common/validation` |
|
|
743
|
+
| `validateEnumValue()` | 验证字符串值是否在允许的枚举列表中 | `common/validation` |
|
|
744
|
+
|
|
745
|
+
## 插件开发框架
|
|
746
|
+
|
|
747
|
+
### BasePlugin 核心概念
|
|
748
|
+
|
|
749
|
+
`BasePlugin` 是所有插件的基类,提供了完整的生命周期管理和开发规范:
|
|
750
|
+
|
|
751
|
+
#### 生命周期
|
|
752
|
+
|
|
753
|
+
| 阶段 | 方法 | 说明 |
|
|
754
|
+
| -------- | ------------------ | -------------------------------------- |
|
|
755
|
+
| 初始化 | `constructor` | 合并配置、初始化日志和验证器 |
|
|
756
|
+
| 配置解析 | `onConfigResolved` | Vite 配置解析完成时调用 |
|
|
757
|
+
| 钩子注册 | `addPluginHooks` | 注册 Vite 插件钩子 |
|
|
758
|
+
| 销毁 | `destroy` | `closeBundle` 时自动调用,用于清理资源 |
|
|
759
|
+
|
|
760
|
+
#### 钩子自动组合
|
|
761
|
+
|
|
762
|
+
`toPlugin()` 方法会自动组合以下钩子:
|
|
763
|
+
|
|
764
|
+
- **configResolved** - 先执行基类的 `onConfigResolved`,再执行子类注册的钩子
|
|
765
|
+
- **closeBundle** - 先执行子类注册的钩子,再执行基类的 `destroy`
|
|
766
|
+
|
|
767
|
+
> 子类无需手动注册 `closeBundle` 钩子来清理资源,只需重写 `destroy()` 方法即可。
|
|
768
|
+
|
|
769
|
+
#### 必须实现的方法
|
|
770
|
+
|
|
771
|
+
| 方法 | 说明 |
|
|
772
|
+
| ------------------------ | ------------------ |
|
|
773
|
+
| `getPluginName()` | 返回插件名称 |
|
|
774
|
+
| `addPluginHooks(plugin)` | 添加 Vite 插件钩子 |
|
|
775
|
+
|
|
776
|
+
#### 可选重写的方法
|
|
777
|
+
|
|
778
|
+
| 方法 | 默认行为 | 说明 |
|
|
779
|
+
| -------------------------- | ----------- | ---------------------------------- |
|
|
780
|
+
| `getDefaultOptions()` | 返回 `{}` | 提供插件默认配置 |
|
|
781
|
+
| `validateOptions()` | 无验证 | 验证配置参数 |
|
|
782
|
+
| `getEnforce()` | `undefined` | 插件执行时机(`'pre'` / `'post'`) |
|
|
783
|
+
| `onConfigResolved(config)` | 存储配置 | 配置解析完成回调 |
|
|
784
|
+
| `destroy()` | 注销日志 | 插件销毁时的清理逻辑 |
|
|
785
|
+
|
|
786
|
+
#### 内置属性
|
|
787
|
+
|
|
788
|
+
| 属性 | 类型 | 说明 |
|
|
789
|
+
| ------------ | ------------------------ | ----------------- |
|
|
790
|
+
| `options` | `Required<T>` | 合并后的完整配置 |
|
|
791
|
+
| `logger` | `PluginLogger` | 插件日志记录器 |
|
|
792
|
+
| `validator` | `Validator<T>` | 配置验证器 |
|
|
793
|
+
| `viteConfig` | `ResolvedConfig \| null` | Vite 解析后的配置 |
|
|
794
|
+
|
|
795
|
+
#### 错误处理策略
|
|
796
|
+
|
|
797
|
+
通过 `errorStrategy` 配置项控制错误行为:
|
|
798
|
+
|
|
799
|
+
- `'throw'`(默认)- 记录错误并抛出异常,中断构建
|
|
800
|
+
- `'log'` - 记录错误但不抛出,继续执行
|
|
801
|
+
- `'ignore'` - 记录错误但不抛出,继续执行
|
|
802
|
+
|
|
803
|
+
使用 `safeExecute` / `safeExecuteSync` 包裹可能出错的操作:
|
|
804
|
+
|
|
805
|
+
```typescript
|
|
806
|
+
// 异步安全执行
|
|
807
|
+
const result = await this.safeExecute(async () => {
|
|
808
|
+
return await someAsyncOperation()
|
|
809
|
+
}, '执行异步操作')
|
|
810
|
+
|
|
811
|
+
// 同步安全执行
|
|
812
|
+
const value = this.safeExecuteSync(() => {
|
|
813
|
+
return someSyncOperation()
|
|
814
|
+
}, '执行同步操作')
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
### createPluginFactory
|
|
818
|
+
|
|
819
|
+
创建插件工厂函数,支持选项标准化器:
|
|
820
|
+
|
|
821
|
+
```typescript
|
|
822
|
+
// 基本使用
|
|
823
|
+
const myPlugin = createPluginFactory(MyPlugin)
|
|
824
|
+
|
|
825
|
+
// 带标准化器(支持字符串简写配置)
|
|
826
|
+
const myPlugin = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
827
|
+
|
|
828
|
+
// 使用时支持简写
|
|
829
|
+
myPlugin('./custom-path')
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
### Validator
|
|
833
|
+
|
|
834
|
+
流畅的配置验证器,支持链式调用:
|
|
835
|
+
|
|
836
|
+
```typescript
|
|
837
|
+
import { Validator } from '@meng-xi/vite-plugin/common'
|
|
838
|
+
|
|
839
|
+
const validator = new Validator(options)
|
|
840
|
+
validator
|
|
841
|
+
.field('sourceDir')
|
|
842
|
+
.required()
|
|
843
|
+
.string()
|
|
844
|
+
.field('targetDir')
|
|
845
|
+
.required()
|
|
846
|
+
.string()
|
|
847
|
+
.field('overwrite')
|
|
848
|
+
.boolean()
|
|
849
|
+
.default(true)
|
|
850
|
+
.field('port')
|
|
851
|
+
.number()
|
|
852
|
+
.field('list')
|
|
853
|
+
.array()
|
|
854
|
+
.field('config')
|
|
855
|
+
.object()
|
|
856
|
+
.field('name')
|
|
857
|
+
.custom(val => val.length > 0, 'name 不能为空')
|
|
858
|
+
.validate()
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
| 方法 | 说明 |
|
|
862
|
+
| ------------ | -------------------------------------------------- |
|
|
863
|
+
| `field()` | 指定要验证的字段 |
|
|
864
|
+
| `required()` | 标记字段为必填 |
|
|
865
|
+
| `string()` | 验证字段值是否为字符串类型 |
|
|
866
|
+
| `boolean()` | 验证字段值是否为布尔类型 |
|
|
867
|
+
| `number()` | 验证字段值是否为数字类型 |
|
|
868
|
+
| `array()` | 验证字段值是否为数组类型 |
|
|
869
|
+
| `object()` | 验证字段值是否为对象类型 |
|
|
870
|
+
| `enum()` | 验证字段值是否在允许的枚举列表中 |
|
|
871
|
+
| `minValue()` | 验证数字字段值是否不小于指定最小值 |
|
|
872
|
+
| `maxValue()` | 验证数字字段值是否不大于指定最大值 |
|
|
873
|
+
| `default()` | 为字段设置默认值(仅当值为 undefined/null 时生效) |
|
|
874
|
+
| `custom()` | 使用自定义函数验证字段值 |
|
|
875
|
+
| `validate()` | 执行验证,失败时抛出错误 |
|
|
876
|
+
|
|
877
|
+
### Logger
|
|
878
|
+
|
|
879
|
+
全局单例日志管理器,为每个插件提供独立的日志控制:
|
|
880
|
+
|
|
881
|
+
```typescript
|
|
882
|
+
import { Logger } from '@meng-xi/vite-plugin/logger'
|
|
883
|
+
|
|
884
|
+
// 创建日志记录器(通常由 BasePlugin 自动调用)
|
|
885
|
+
Logger.create({ name: 'my-plugin', enabled: true })
|
|
886
|
+
|
|
887
|
+
// 注销插件日志配置(插件销毁时自动调用)
|
|
888
|
+
Logger.unregister('my-plugin')
|
|
889
|
+
|
|
890
|
+
// 销毁单例(测试场景使用)
|
|
891
|
+
Logger.destroy()
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
日志输出格式:
|
|
895
|
+
|
|
896
|
+
```
|
|
897
|
+
ℹ️ [@meng-xi/vite-plugin:my-plugin] Info message
|
|
898
|
+
✅ [@meng-xi/vite-plugin:my-plugin] Success message
|
|
899
|
+
⚠️ [@meng-xi/vite-plugin:my-plugin] Warning message
|
|
900
|
+
❌ [@meng-xi/vite-plugin:my-plugin] Error message
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
### 开发自定义插件示例
|
|
904
|
+
|
|
905
|
+
```typescript
|
|
906
|
+
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin'
|
|
907
|
+
import type { BasePluginOptions, PluginWithInstance } from '@meng-xi/vite-plugin/factory'
|
|
908
|
+
import type { Plugin } from 'vite'
|
|
909
|
+
|
|
910
|
+
interface MyPluginOptions extends BasePluginOptions {
|
|
911
|
+
path: string
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
class MyPlugin extends BasePlugin<MyPluginOptions> {
|
|
915
|
+
protected getDefaultOptions() {
|
|
916
|
+
return { path: './default' }
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
protected validateOptions(): void {
|
|
920
|
+
this.validator.field('path').required().string().validate()
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
protected getPluginName(): string {
|
|
924
|
+
return 'my-plugin'
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
protected addPluginHooks(plugin: Plugin): void {
|
|
928
|
+
plugin.buildStart = () => {
|
|
929
|
+
this.logger.info(`Plugin started with path: ${this.options.path}`)
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
protected destroy(): void {
|
|
934
|
+
super.destroy()
|
|
935
|
+
// 自定义清理逻辑,如关闭连接、停止监听等
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// 基本使用
|
|
940
|
+
export const myPlugin = createPluginFactory(MyPlugin)
|
|
941
|
+
|
|
942
|
+
// 带标准化器(支持字符串简写配置)
|
|
943
|
+
export const myPluginWithNormalizer = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
944
|
+
// 使用时支持简写:myPluginWithNormalizer('./custom-path')
|
|
945
|
+
```
|
|
946
|
+
|
|
752
947
|
## 子路径导出
|
|
753
948
|
|
|
754
949
|
支持按需导入模块,减少打包体积:
|
|
755
950
|
|
|
756
951
|
```typescript
|
|
757
952
|
// 完整导入
|
|
758
|
-
import { buildProgress, copyFile,
|
|
953
|
+
import { buildProgress, copyFile, htmlInject, loadingManager, BasePlugin, Logger } from '@meng-xi/vite-plugin'
|
|
759
954
|
|
|
760
955
|
// 按模块导入
|
|
761
956
|
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin/factory'
|
|
762
957
|
import { Logger } from '@meng-xi/vite-plugin/logger'
|
|
763
|
-
import { buildProgress, copyFile, generateRouter,
|
|
958
|
+
import { buildProgress, copyFile, generateRouter, htmlInject, loadingManager } from '@meng-xi/vite-plugin/plugins'
|
|
764
959
|
import { Validator, readFileContent, writeFileContent } from '@meng-xi/vite-plugin/common'
|
|
765
960
|
|
|
766
961
|
// 类型导入(从子路径按需导入类型定义)
|
|
767
962
|
import type { PluginWithInstance, PluginFactory, BasePluginOptions } from '@meng-xi/vite-plugin/factory'
|
|
768
|
-
import type { BuildProgressOptions, GenerateVersionOptions,
|
|
769
|
-
import type { DateFormatOptions } from '@meng-xi/vite-plugin/common'
|
|
963
|
+
import type { BuildProgressOptions, GenerateVersionOptions, VersionUpdateCheckerOptions, HtmlInjectOptions, InjectRule, FaviconManagerOptions, LoadingManagerOptions, Icon } from '@meng-xi/vite-plugin/plugins'
|
|
964
|
+
import type { DateFormatOptions } from '@meng-xi/vite-plugin/common/format'
|
|
965
|
+
import type { HtmlInjectResult, DualInjectResult } from '@meng-xi/vite-plugin/common/html'
|
|
966
|
+
import type { CopyOptions, CopyResult } from '@meng-xi/vite-plugin/common/fs'
|
|
770
967
|
```
|
|
771
968
|
|
|
772
969
|
## 更新日志
|