@meng-xi/vite-plugin 0.1.1 → 0.1.2
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 +225 -615
- package/README.md +205 -594
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +1 -1
- package/dist/plugins/compressAssets/index.cjs +1 -0
- package/dist/plugins/compressAssets/index.d.cts +132 -0
- package/dist/plugins/compressAssets/index.d.mts +132 -0
- package/dist/plugins/compressAssets/index.d.ts +132 -0
- package/dist/plugins/compressAssets/index.mjs +1 -0
- package/dist/plugins/htmlInject/index.cjs +7 -7
- package/dist/plugins/htmlInject/index.mjs +2 -2
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.d.cts +1 -0
- package/dist/plugins/index.d.mts +1 -0
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.mjs +1 -1
- package/package.json +9 -2
package/README-en.md
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
## Features
|
|
17
17
|
|
|
18
|
-
- **Ready to Use** - Provides
|
|
19
|
-
management
|
|
18
|
+
- **Ready to Use** - Provides 9 practical plugins covering build progress display, build artifact compression, file copying, router generation, version management, version update checking, HTML injection, icon injection,
|
|
19
|
+
and global Loading state management
|
|
20
20
|
- **Plugin Development Framework** - Exports core components like BasePlugin, Logger, Validator for building custom Vite plugins
|
|
21
21
|
- **Complete Lifecycle** - Supports initialization, config resolution, destroy lifecycle management with automatic hook composition
|
|
22
22
|
- **Type Safe** - Complete TypeScript type definitions with configuration validators ensuring parameter correctness
|
|
@@ -47,53 +47,21 @@ pnpm add @meng-xi/vite-plugin -D
|
|
|
47
47
|
|
|
48
48
|
```typescript
|
|
49
49
|
import { defineConfig } from 'vite'
|
|
50
|
-
import { buildProgress, copyFile, generateRouter, generateVersion, versionUpdateChecker, htmlInject, faviconManager, loadingManager } from '@meng-xi/vite-plugin'
|
|
50
|
+
import { buildProgress, compressAssets, copyFile, generateRouter, generateVersion, versionUpdateChecker, htmlInject, faviconManager, loadingManager } from '@meng-xi/vite-plugin'
|
|
51
51
|
|
|
52
52
|
export default defineConfig({
|
|
53
53
|
plugins: [
|
|
54
|
-
// Build progress bar
|
|
55
54
|
buildProgress(),
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
targetDir: 'dist/assets'
|
|
61
|
-
}),
|
|
62
|
-
|
|
63
|
-
// Generate router config (uni-app)
|
|
64
|
-
generateRouter({
|
|
65
|
-
pagesJsonPath: 'src/pages.json',
|
|
66
|
-
outputPath: 'src/router.config.ts'
|
|
67
|
-
}),
|
|
68
|
-
|
|
69
|
-
// Generate version
|
|
70
|
-
generateVersion({
|
|
71
|
-
format: 'datetime',
|
|
72
|
-
outputType: 'both'
|
|
73
|
-
}),
|
|
74
|
-
|
|
75
|
-
// Version update checker (works with generateVersion)
|
|
55
|
+
compressAssets({ algorithm: 'gzip' }),
|
|
56
|
+
copyFile({ sourceDir: 'src/assets', targetDir: 'dist/assets' }),
|
|
57
|
+
generateRouter({ pagesJsonPath: 'src/pages.json', outputPath: 'src/router.config.ts' }),
|
|
58
|
+
generateVersion({ format: 'datetime', outputType: 'both' }),
|
|
76
59
|
versionUpdateChecker(),
|
|
77
|
-
|
|
78
|
-
// HTML content injection
|
|
79
60
|
htmlInject({
|
|
80
|
-
rules: [
|
|
81
|
-
{
|
|
82
|
-
id: 'meta-description',
|
|
83
|
-
content: '<meta name="description" content="My App">',
|
|
84
|
-
position: 'head-end'
|
|
85
|
-
}
|
|
86
|
-
]
|
|
61
|
+
rules: [{ id: 'meta-description', content: '<meta name="description" content="My App">', position: 'head-end' }]
|
|
87
62
|
}),
|
|
88
|
-
|
|
89
|
-
// Inject website icon (supports string shorthand)
|
|
90
63
|
faviconManager('/assets'),
|
|
91
|
-
|
|
92
|
-
// Global Loading state management
|
|
93
|
-
loadingManager({
|
|
94
|
-
defaultVisible: true,
|
|
95
|
-
autoHideOn: 'DOMContentLoaded'
|
|
96
|
-
})
|
|
64
|
+
loadingManager({ defaultVisible: true, autoHideOn: 'DOMContentLoaded' })
|
|
97
65
|
]
|
|
98
66
|
})
|
|
99
67
|
```
|
|
@@ -107,8 +75,6 @@ import type { PluginWithInstance } from '@meng-xi/vite-plugin/factory'
|
|
|
107
75
|
import type { GenerateRouterOptions } from '@meng-xi/vite-plugin'
|
|
108
76
|
|
|
109
77
|
const routerPlugin = generateRouter({ watch: true }) as PluginWithInstance<GenerateRouterOptions>
|
|
110
|
-
|
|
111
|
-
// Access plugin internals via pluginInstance
|
|
112
78
|
console.log(routerPlugin.pluginInstance?.options)
|
|
113
79
|
```
|
|
114
80
|
|
|
@@ -117,6 +83,7 @@ console.log(routerPlugin.pluginInstance?.options)
|
|
|
117
83
|
| Plugin | Description |
|
|
118
84
|
| -------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
119
85
|
| buildProgress | Real-time build progress bar in terminal, supports bar / spinner / minimal |
|
|
86
|
+
| compressAssets | Compress build artifacts with gzip / brotli / both, concurrent compression and statistics report |
|
|
120
87
|
| copyFile | Copy files or directories after build, supports incremental copying |
|
|
121
88
|
| generateRouter | Auto-generate router config from pages.json (uni-app) |
|
|
122
89
|
| generateVersion | Auto-generate version numbers, supports file output and global variable injection |
|
|
@@ -125,6 +92,8 @@ console.log(routerPlugin.pluginInstance?.options)
|
|
|
125
92
|
| faviconManager | Manage website favicon links injection into HTML files, supports string shorthand config |
|
|
126
93
|
| loadingManager | Global Loading state management with request interception and white-screen Loading |
|
|
127
94
|
|
|
95
|
+
---
|
|
96
|
+
|
|
128
97
|
### buildProgress
|
|
129
98
|
|
|
130
99
|
Display real-time build progress bar in terminal during Vite build, supporting three display formats.
|
|
@@ -155,24 +124,10 @@ Display real-time build progress bar in terminal during Vite build, supporting t
|
|
|
155
124
|
| moduleColor | `(text: string) => string` | Module name color |
|
|
156
125
|
|
|
157
126
|
```typescript
|
|
158
|
-
// Default bar format
|
|
159
127
|
buildProgress()
|
|
160
|
-
|
|
161
|
-
// Spinner format
|
|
162
128
|
buildProgress({ format: 'spinner' })
|
|
163
|
-
|
|
164
|
-
// Minimal format
|
|
165
129
|
buildProgress({ format: 'minimal' })
|
|
166
|
-
|
|
167
|
-
// Custom appearance
|
|
168
|
-
buildProgress({
|
|
169
|
-
width: 40,
|
|
170
|
-
completeChar: '■',
|
|
171
|
-
incompleteChar: '□',
|
|
172
|
-
clearOnComplete: false
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
// Custom color theme
|
|
130
|
+
buildProgress({ width: 40, completeChar: '■', incompleteChar: '□', clearOnComplete: false })
|
|
176
131
|
buildProgress({
|
|
177
132
|
theme: {
|
|
178
133
|
completeColor: t => `\x1b[32m${t}\x1b[39m`,
|
|
@@ -184,6 +139,35 @@ buildProgress({
|
|
|
184
139
|
})
|
|
185
140
|
```
|
|
186
141
|
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### compressAssets
|
|
145
|
+
|
|
146
|
+
Automatically compress files in the output directory after Vite build, supporting both gzip and brotli compression algorithms.
|
|
147
|
+
|
|
148
|
+
| Option | Type | Default | Description |
|
|
149
|
+
| ------------------ | ---------------------------------- | ----------------------------------------------------------- | -------------------------------------------------- |
|
|
150
|
+
| algorithm | `'gzip'` \| `'brotli'` \| `'both'` | `'gzip'` | Compression algorithm |
|
|
151
|
+
| threshold | `number` | `1024` | Minimum compression threshold (bytes) |
|
|
152
|
+
| deleteOriginalFile | `boolean` | `false` | Whether to delete original files after compression |
|
|
153
|
+
| includeExtensions | `string[]` | `['.js', '.css', '.html', '.svg', '.json', '.xml', '.txt']` | File extensions to compress |
|
|
154
|
+
| excludeExtensions | `string[]` | `[]` | File extensions to exclude |
|
|
155
|
+
| excludePaths | `string[]` | `[]` | Path prefixes to exclude |
|
|
156
|
+
| compressionLevel | `number` | `9` | Gzip compression level (1-9) |
|
|
157
|
+
| brotliQuality | `number` | `11` | Brotli compression quality (1-11) |
|
|
158
|
+
| reportOutput | `string` \| `false` | `'compress-report.json'` | Compression report output path, false to skip |
|
|
159
|
+
| parallelLimit | `number` | `10` | Maximum concurrent file compression count |
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
compressAssets()
|
|
163
|
+
compressAssets({ algorithm: 'brotli' })
|
|
164
|
+
compressAssets({ algorithm: 'both', threshold: 2048, compressionLevel: 9, brotliQuality: 11 })
|
|
165
|
+
compressAssets({ deleteOriginalFile: true, reportOutput: 'compress-report.json' })
|
|
166
|
+
compressAssets({ includeExtensions: ['.js', '.css'], excludePaths: ['assets/images'], parallelLimit: 5 })
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
187
171
|
### copyFile
|
|
188
172
|
|
|
189
173
|
Copy files or directories to specified locations after Vite build is completed, with `enforce: 'post'`.
|
|
@@ -197,21 +181,12 @@ Copy files or directories to specified locations after Vite build is completed,
|
|
|
197
181
|
| incremental | `boolean` | `true` | Whether to enable incremental copying |
|
|
198
182
|
|
|
199
183
|
```typescript
|
|
200
|
-
|
|
201
|
-
copyFile({
|
|
202
|
-
sourceDir: 'src/assets',
|
|
203
|
-
targetDir: 'dist/assets'
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
// Disable overwrite and incremental copy
|
|
207
|
-
copyFile({
|
|
208
|
-
sourceDir: 'src/static',
|
|
209
|
-
targetDir: 'dist/static',
|
|
210
|
-
overwrite: false,
|
|
211
|
-
incremental: false
|
|
212
|
-
})
|
|
184
|
+
copyFile({ sourceDir: 'src/assets', targetDir: 'dist/assets' })
|
|
185
|
+
copyFile({ sourceDir: 'src/static', targetDir: 'dist/static', overwrite: false, incremental: false })
|
|
213
186
|
```
|
|
214
187
|
|
|
188
|
+
---
|
|
189
|
+
|
|
215
190
|
### generateRouter
|
|
216
191
|
|
|
217
192
|
Automatically generate router configuration files based on uni-app project's `pages.json`.
|
|
@@ -229,38 +204,19 @@ Automatically generate router configuration files based on uni-app project's `pa
|
|
|
229
204
|
| exportTypes | `boolean` | `true` | Whether to export type definitions |
|
|
230
205
|
| preserveRouteChanges | `boolean` | `true` | Whether to preserve user modifications to routes |
|
|
231
206
|
|
|
232
|
-
> Default `metaMapping` is `{ navigationBarTitleText: 'title', requireAuth: 'requireAuth' }
|
|
233
|
-
> provided.
|
|
207
|
+
> Default `metaMapping` is `{ navigationBarTitleText: 'title', requireAuth: 'requireAuth' }`. When `nameStrategy` is `'custom'`, `customNameGenerator` must be provided.
|
|
234
208
|
|
|
235
209
|
```typescript
|
|
236
|
-
// Basic usage
|
|
237
210
|
generateRouter()
|
|
238
|
-
|
|
239
|
-
// Custom pages.json path
|
|
240
211
|
generateRouter({ pagesJsonPath: 'pages.json' })
|
|
241
|
-
|
|
242
|
-
// Output JavaScript file
|
|
243
212
|
generateRouter({ outputFormat: 'js', outputPath: 'src/router.config.js' })
|
|
244
|
-
|
|
245
|
-
// PascalCase naming strategy
|
|
246
213
|
generateRouter({ nameStrategy: 'pascalCase' })
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
generateRouter({
|
|
250
|
-
nameStrategy: 'custom',
|
|
251
|
-
customNameGenerator: path => `route_${path.replace(/\//g, '_')}`
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
// Custom meta mapping
|
|
255
|
-
generateRouter({
|
|
256
|
-
metaMapping: {
|
|
257
|
-
navigationBarTitleText: 'title',
|
|
258
|
-
requireAuth: 'requireAuth',
|
|
259
|
-
customField: 'custom'
|
|
260
|
-
}
|
|
261
|
-
})
|
|
214
|
+
generateRouter({ nameStrategy: 'custom', customNameGenerator: path => `route_${path.replace(/\//g, '_')}` })
|
|
215
|
+
generateRouter({ metaMapping: { navigationBarTitleText: 'title', requireAuth: 'requireAuth', customField: 'custom' } })
|
|
262
216
|
```
|
|
263
217
|
|
|
218
|
+
---
|
|
219
|
+
|
|
264
220
|
### generateVersion
|
|
265
221
|
|
|
266
222
|
Automatically generate version numbers during the Vite build process.
|
|
@@ -300,34 +256,16 @@ Automatically generate version numbers during the Vite build process.
|
|
|
300
256
|
> and timestamp.
|
|
301
257
|
|
|
302
258
|
```typescript
|
|
303
|
-
// Timestamp format (default)
|
|
304
259
|
generateVersion()
|
|
305
|
-
|
|
306
|
-
// Date format
|
|
307
260
|
generateVersion({ format: 'date' })
|
|
308
|
-
|
|
309
|
-
// Semantic version format
|
|
310
261
|
generateVersion({ format: 'semver', semverBase: '2.0.0', prefix: 'v' })
|
|
311
|
-
|
|
312
|
-
// Custom format
|
|
313
|
-
generateVersion({
|
|
314
|
-
format: 'custom',
|
|
315
|
-
customFormat: '{YYYY}.{MM}.{DD}-{hash}',
|
|
316
|
-
hashLength: 6
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
// Inject into code
|
|
262
|
+
generateVersion({ format: 'custom', customFormat: '{YYYY}.{MM}.{DD}-{hash}', hashLength: 6 })
|
|
320
263
|
generateVersion({ outputType: 'define', defineName: '__VERSION__' })
|
|
321
|
-
|
|
322
|
-
// Both file output and code injection
|
|
323
|
-
generateVersion({
|
|
324
|
-
outputType: 'both',
|
|
325
|
-
outputFile: 'build-info.json',
|
|
326
|
-
defineName: '__BUILD_VERSION__',
|
|
327
|
-
extra: { environment: 'production' }
|
|
328
|
-
})
|
|
264
|
+
generateVersion({ outputType: 'both', outputFile: 'build-info.json', defineName: '__BUILD_VERSION__', extra: { environment: 'production' } })
|
|
329
265
|
```
|
|
330
266
|
|
|
267
|
+
---
|
|
268
|
+
|
|
331
269
|
### versionUpdateChecker
|
|
332
270
|
|
|
333
271
|
Periodically check for version changes at runtime and prompt users to refresh when a new version is detected. Typically used in conjunction with the `generateVersion` plugin.
|
|
@@ -360,223 +298,135 @@ Periodically check for version changes at runtime and prompt users to refresh wh
|
|
|
360
298
|
> `{{newVersion}}`, `{{refreshButton}}`, `{{dismissButton}}` placeholders. Callbacks are provided as function body strings with available variables: `currentVersion`, `newVersion`.
|
|
361
299
|
|
|
362
300
|
```typescript
|
|
363
|
-
// Basic usage (with generateVersion)
|
|
364
301
|
generateVersion({ outputType: 'both' })
|
|
365
302
|
versionUpdateChecker()
|
|
366
|
-
|
|
367
|
-
// Read from version file only
|
|
368
303
|
versionUpdateChecker({ versionSource: 'file' })
|
|
369
|
-
|
|
370
|
-
// Custom check interval and prompt style
|
|
371
|
-
versionUpdateChecker({
|
|
372
|
-
checkInterval: 60000,
|
|
373
|
-
promptStyle: 'banner'
|
|
374
|
-
})
|
|
375
|
-
|
|
376
|
-
// Toast-style prompt
|
|
304
|
+
versionUpdateChecker({ checkInterval: 60000, promptStyle: 'banner' })
|
|
377
305
|
versionUpdateChecker({ promptStyle: 'toast' })
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
versionUpdateChecker({
|
|
381
|
-
promptMessage: 'System updated, refresh to experience new features',
|
|
382
|
-
refreshButtonText: 'Update',
|
|
383
|
-
dismissButtonText: 'Cancel'
|
|
384
|
-
})
|
|
385
|
-
|
|
386
|
-
// Custom callbacks
|
|
387
|
-
versionUpdateChecker({
|
|
388
|
-
onUpdateAvailable: 'console.log("New version:", newVersion); return true;',
|
|
389
|
-
onRefresh: 'console.log("User chose to refresh");',
|
|
390
|
-
onDismiss: 'console.log("User chose to dismiss");'
|
|
391
|
-
})
|
|
392
|
-
|
|
393
|
-
// Enable in development (for debugging)
|
|
306
|
+
versionUpdateChecker({ promptMessage: 'System updated, refresh to experience new features', refreshButtonText: 'Update', dismissButtonText: 'Cancel' })
|
|
307
|
+
versionUpdateChecker({ onUpdateAvailable: 'console.log("New version:", newVersion); return true;', onRefresh: 'console.log("User chose to refresh");', onDismiss: 'console.log("User chose to dismiss");' })
|
|
394
308
|
versionUpdateChecker({ enableInDev: true })
|
|
395
309
|
```
|
|
396
310
|
|
|
311
|
+
---
|
|
312
|
+
|
|
397
313
|
### htmlInject
|
|
398
314
|
|
|
399
|
-
Inject HTML content into target files during Vite build based on
|
|
315
|
+
Inject HTML content into target files during Vite build based on configurable rules, supporting multiple injection positions, conditional injection, template variable substitution, and security filtering.
|
|
400
316
|
|
|
401
317
|
**Injection positions:**
|
|
402
318
|
|
|
403
319
|
| Position | Description |
|
|
404
320
|
| ------------------ | ------------------------------------------ |
|
|
405
|
-
| `head-start` | Inject after the `<head>` tag
|
|
406
|
-
| `head-end` | Inject before the `</head>` tag
|
|
407
|
-
| `body-start` | Inject after the `<body>` tag
|
|
408
|
-
| `body-end` | Inject before the `</body>` tag
|
|
321
|
+
| `head-start` | Inject after the `<head>` tag opening |
|
|
322
|
+
| `head-end` | Inject before the `</head>` closing tag |
|
|
323
|
+
| `body-start` | Inject after the `<body>` tag opening |
|
|
324
|
+
| `body-end` | Inject before the `</body>` closing tag |
|
|
409
325
|
| `before-selector` | Inject before the selector-matched content |
|
|
410
326
|
| `after-selector` | Inject after the selector-matched content |
|
|
411
327
|
| `replace-selector` | Replace the selector-matched content |
|
|
412
328
|
|
|
413
|
-
| Option | Type | Default | Description
|
|
414
|
-
| ------------ | ------------------------ | -------------- |
|
|
415
|
-
| targetFile | `string` | `'index.html'` | Target HTML file path or filename
|
|
416
|
-
| rules | `InjectRule[]` | - |
|
|
417
|
-
| security | `SecurityConfig` | - | Security filtering configuration
|
|
418
|
-
| templateVars | `Record<string, string>` | - | Global template variables
|
|
419
|
-
| logInjection | `boolean` | `true` | Whether to output injection logs
|
|
329
|
+
| Option | Type | Default | Description |
|
|
330
|
+
| ------------ | ------------------------ | -------------- | ----------------------------------- |
|
|
331
|
+
| targetFile | `string` | `'index.html'` | Target HTML file path or filename |
|
|
332
|
+
| rules | `InjectRule[]` | - | Array of injection rules (required) |
|
|
333
|
+
| security | `SecurityConfig` | - | Security filtering configuration |
|
|
334
|
+
| templateVars | `Record<string, string>` | - | Global template variables |
|
|
335
|
+
| logInjection | `boolean` | `true` | Whether to output injection logs |
|
|
420
336
|
|
|
421
337
|
**InjectRule**
|
|
422
338
|
|
|
423
|
-
| Property | Type | Default | Description
|
|
424
|
-
| -------------------- | ------------------------ | ---------- |
|
|
425
|
-
| id | `string` | - | Unique rule identifier
|
|
426
|
-
| content | `string` | - | HTML content to inject
|
|
427
|
-
| position | `InjectPosition` | - | Injection position
|
|
428
|
-
| selector | `string` | - | Selector
|
|
429
|
-
| selectorMatch | `'string'` \| `'regex'` | `'string'` | Selector
|
|
430
|
-
| priority | `number` | `100` |
|
|
431
|
-
| condition | `InjectCondition` | - | Injection condition
|
|
432
|
-
| templateVars | `Record<string, string>` | - | Rule-level template variables
|
|
433
|
-
| allowScriptInjection | `boolean` | `false` | Whether to allow injecting
|
|
434
|
-
|
|
435
|
-
**InjectCondition**
|
|
436
|
-
|
|
437
|
-
| Property | Type | Default | Description |
|
|
438
|
-
| -------- | ------------------------------------------- | ------- | -------------------------------------- |
|
|
439
|
-
| type | `'env'` \| `'file-contains'` \| `'custom'` | - | Condition type (required) |
|
|
440
|
-
| value | `string` \| `((...args: any[]) => boolean)` | - | Condition value (required) |
|
|
441
|
-
| negate | `boolean` | `false` | Whether to negate the condition result |
|
|
339
|
+
| Property | Type | Default | Description |
|
|
340
|
+
| -------------------- | ------------------------ | ---------- | --------------------------------------------------------- |
|
|
341
|
+
| id | `string` | - | Unique rule identifier |
|
|
342
|
+
| content | `string` | - | HTML content to inject |
|
|
343
|
+
| position | `InjectPosition` | - | Injection position |
|
|
344
|
+
| selector | `string` | - | Selector (required for selector-related positions) |
|
|
345
|
+
| selectorMatch | `'string'` \| `'regex'` | `'string'` | Selector matching mode |
|
|
346
|
+
| priority | `number` | `100` | Rule priority, lower values execute first |
|
|
347
|
+
| condition | `InjectCondition` | - | Injection condition |
|
|
348
|
+
| templateVars | `Record<string, string>` | - | Rule-level template variables, override global vars |
|
|
349
|
+
| allowScriptInjection | `boolean` | `false` | Whether to allow injecting dangerous content like scripts |
|
|
442
350
|
|
|
443
351
|
**SecurityConfig**
|
|
444
352
|
|
|
445
|
-
| Property | Type | Default | Description
|
|
446
|
-
| ------------------------ | ---------- | ------- |
|
|
447
|
-
| blockDangerousTags | `boolean` | `true` |
|
|
448
|
-
| blockDangerousAttributes | `boolean` | `true` |
|
|
449
|
-
| allowedTags | `string[]` | - | Whitelist of allowed tags
|
|
450
|
-
| blockedTags | `string[]` | - | Custom blocked tags
|
|
451
|
-
| blockedAttributes | `string[]` | - | Custom blocked attributes
|
|
353
|
+
| Property | Type | Default | Description |
|
|
354
|
+
| ------------------------ | ---------- | ------- | --------------------------------- |
|
|
355
|
+
| blockDangerousTags | `boolean` | `true` | Block dangerous tags |
|
|
356
|
+
| blockDangerousAttributes | `boolean` | `true` | Block dangerous attributes |
|
|
357
|
+
| allowedTags | `string[]` | - | Whitelist of allowed tags |
|
|
358
|
+
| blockedTags | `string[]` | - | Custom list of blocked tags |
|
|
359
|
+
| blockedAttributes | `string[]` | - | Custom list of blocked attributes |
|
|
452
360
|
|
|
453
361
|
```typescript
|
|
454
|
-
// Basic usage
|
|
455
|
-
htmlInject({
|
|
456
|
-
rules: [{ id: 'meta-desc', content: '<meta name="description" content="My App">', position: 'head-end' }]
|
|
457
|
-
})
|
|
458
|
-
|
|
459
|
-
// Conditional injection (production only)
|
|
460
362
|
htmlInject({
|
|
461
363
|
rules: [
|
|
462
|
-
{
|
|
463
|
-
|
|
464
|
-
content: '<script src="/analytics.js"></script>',
|
|
465
|
-
position: 'body-end',
|
|
466
|
-
condition: { type: 'env', value: 'PRODUCTION' },
|
|
467
|
-
allowScriptInjection: true
|
|
468
|
-
}
|
|
364
|
+
{ id: 'meta-description', content: '<meta name="description" content="{{appName}}">', position: 'head-end', templateVars: { appName: 'My Application' } },
|
|
365
|
+
{ id: 'analytics', content: '<script src="/analytics.js"></script>', position: 'body-end', condition: { type: 'env', value: 'PRODUCTION' }, allowScriptInjection: true }
|
|
469
366
|
]
|
|
470
367
|
})
|
|
471
|
-
|
|
472
|
-
// Template variable replacement
|
|
473
|
-
htmlInject({
|
|
474
|
-
templateVars: { appName: 'My App', version: '1.0.0' },
|
|
475
|
-
rules: [{ id: 'meta', content: '<meta name="description" content="{{appName}}">', position: 'head-end' }]
|
|
476
|
-
})
|
|
477
|
-
|
|
478
|
-
// Selector injection
|
|
479
|
-
htmlInject({
|
|
480
|
-
rules: [{ id: 'replace-title', content: '<title>New Title</title>', position: 'replace-selector', selector: '<title>.*</title>', selectorMatch: 'regex' }]
|
|
481
|
-
})
|
|
482
|
-
|
|
483
|
-
// Security configuration
|
|
484
|
-
htmlInject({
|
|
485
|
-
security: { blockDangerousTags: true, allowedTags: ['iframe'] },
|
|
486
|
-
rules: [{ id: 'embed', content: '<iframe src="https://example.com"></iframe>', position: 'body-end' }]
|
|
487
|
-
})
|
|
488
368
|
```
|
|
489
369
|
|
|
490
|
-
|
|
370
|
+
---
|
|
491
371
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
| Option | Type | Default | Description |
|
|
495
|
-
| ----------- | -------- | ------- | ------------------------------- |
|
|
496
|
-
| base | `string` | `'/'` | Base path for icon files |
|
|
497
|
-
| url | `string` | - | Complete URL for the icon |
|
|
498
|
-
| link | `string` | - | Custom complete link tag HTML |
|
|
499
|
-
| icons | `Icon[]` | - | Custom icon array |
|
|
500
|
-
| copyOptions | `object` | - | Icon file copying configuration |
|
|
501
|
-
|
|
502
|
-
> Priority: `link` > `url` > `base`. When `link` is provided, custom HTML is injected directly; when `url` is provided, the complete URL is used; otherwise `base + '/favicon.ico'` is used.
|
|
372
|
+
### faviconManager
|
|
503
373
|
|
|
504
|
-
|
|
374
|
+
Manage website favicon links injection into HTML files, supporting string shorthand config and icon file copying.
|
|
505
375
|
|
|
506
|
-
|
|
|
507
|
-
|
|
|
508
|
-
|
|
|
509
|
-
|
|
|
510
|
-
|
|
|
511
|
-
|
|
|
376
|
+
| Option | Type | Default | Description |
|
|
377
|
+
| ----------- | -------- | ------- | ------------------------------------------------------ |
|
|
378
|
+
| base | `string` | `'/'` | Base path for icon files |
|
|
379
|
+
| url | `string` | - | Complete icon URL, takes precedence over base |
|
|
380
|
+
| link | `string` | - | Custom complete link tag HTML, highest priority |
|
|
381
|
+
| icons | `Icon[]` | - | Custom icon array, supports multiple formats and sizes |
|
|
382
|
+
| copyOptions | `object` | - | Icon file copy config (sourceDir, targetDir) |
|
|
512
383
|
|
|
513
|
-
|
|
384
|
+
**Icon**
|
|
514
385
|
|
|
515
|
-
| Property
|
|
516
|
-
|
|
|
517
|
-
|
|
|
518
|
-
|
|
|
519
|
-
|
|
|
520
|
-
|
|
|
386
|
+
| Property | Type | Description |
|
|
387
|
+
| -------- | -------- | ------------------ |
|
|
388
|
+
| rel | `string` | Icon relation type |
|
|
389
|
+
| href | `string` | Icon URL |
|
|
390
|
+
| sizes | `string` | Icon size |
|
|
391
|
+
| type | `string` | Icon MIME type |
|
|
521
392
|
|
|
522
393
|
```typescript
|
|
523
|
-
// Use default config
|
|
524
394
|
faviconManager()
|
|
525
|
-
|
|
526
|
-
// String shorthand (set base path)
|
|
527
395
|
faviconManager('/assets')
|
|
528
|
-
|
|
529
|
-
// Custom icon array
|
|
530
396
|
faviconManager({
|
|
531
397
|
base: '/assets',
|
|
532
398
|
icons: [
|
|
533
399
|
{ rel: 'icon', href: '/favicon.svg', type: 'image/svg+xml' },
|
|
534
|
-
{ rel: 'icon', href: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' }
|
|
535
|
-
{ rel: 'apple-touch-icon', href: '/apple-touch-icon.png', sizes: '180x180' }
|
|
400
|
+
{ rel: 'icon', href: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' }
|
|
536
401
|
]
|
|
537
402
|
})
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
faviconManager({
|
|
541
|
-
link: '<link rel="icon" href="/favicon.svg" type="image/svg+xml" />'
|
|
542
|
-
})
|
|
543
|
-
|
|
544
|
-
// With file copying
|
|
545
|
-
faviconManager({
|
|
546
|
-
base: '/assets',
|
|
547
|
-
copyOptions: {
|
|
548
|
-
sourceDir: 'src/assets/icons',
|
|
549
|
-
targetDir: 'dist/assets/icons'
|
|
550
|
-
}
|
|
551
|
-
})
|
|
403
|
+
faviconManager({ link: '<link rel="icon" href="/favicon.svg" type="image/svg+xml" />' })
|
|
404
|
+
faviconManager({ base: '/assets', copyOptions: { sourceDir: 'src/assets/icons', targetDir: 'dist/assets/icons' } })
|
|
552
405
|
```
|
|
553
406
|
|
|
407
|
+
---
|
|
408
|
+
|
|
554
409
|
### loadingManager
|
|
555
410
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
|
564
|
-
|
|
|
565
|
-
|
|
|
566
|
-
|
|
|
567
|
-
|
|
|
568
|
-
|
|
|
569
|
-
|
|
|
570
|
-
|
|
|
571
|
-
|
|
|
572
|
-
|
|
|
573
|
-
|
|
|
574
|
-
|
|
|
575
|
-
| globalName | `string` | `'__LOADING_MANAGER__'` | Global variable name injected into browser |
|
|
576
|
-
| customTemplate | `string` | - | Custom HTML template (must include `data-loading-text`) |
|
|
577
|
-
| defaultVisible | `boolean` | `false` | Whether initially visible (white-screen Loading) |
|
|
578
|
-
| autoHideOn | `'DOMContentLoaded'` \| `'load'` \| `'manual'` | `'DOMContentLoaded'` | Auto-hide timing (requires `defaultVisible: true`) |
|
|
579
|
-
| callbacks | `LoadingCallbacks` | - | Lifecycle callbacks |
|
|
411
|
+
Global Loading state management with request interception and white-screen Loading support.
|
|
412
|
+
|
|
413
|
+
| Option | Type | Default | Description |
|
|
414
|
+
| -------------- | ----------------------------------------------- | ----------------------- | ------------------------------------------ |
|
|
415
|
+
| position | `'center'` \| `'top'` \| `'bottom'` | `'center'` | Loading display position |
|
|
416
|
+
| defaultText | `string` | `'Loading...'` | Default display text |
|
|
417
|
+
| spinnerType | `'spinner'` \| `'dots'` \| `'pulse'` \| `'bar'` | `'spinner'` | Spinner icon type |
|
|
418
|
+
| autoBind | `'fetch'` \| `'xhr'` \| `'all'` \| `'none'` | `'none'` | Auto-bind request interception mode |
|
|
419
|
+
| globalName | `string` | `'__LOADING_MANAGER__'` | Global variable name injected into browser |
|
|
420
|
+
| defaultVisible | `boolean` | `false` | Loading DOM initial visibility state |
|
|
421
|
+
| autoHideOn | `'DOMContentLoaded'` \| `'load'` \| `'manual'` | `'DOMContentLoaded'` | Auto-hide timing |
|
|
422
|
+
| style | `LoadingStyle` | - | Custom style configuration |
|
|
423
|
+
| transition | `TransitionConfig` | - | Transition animation configuration |
|
|
424
|
+
| minDisplayTime | `MinDisplayTime` | - | Minimum display time configuration |
|
|
425
|
+
| delayShow | `DelayShow` | - | Delay show configuration |
|
|
426
|
+
| debounceHide | `DebounceHide` | - | Debounce hide configuration |
|
|
427
|
+
| requestFilter | `RequestFilter` | - | Request filter configuration |
|
|
428
|
+
| customTemplate | `string` | - | Custom HTML template |
|
|
429
|
+
| callbacks | `LoadingCallbacks` | - | Lifecycle callbacks |
|
|
580
430
|
|
|
581
431
|
**LoadingStyle**
|
|
582
432
|
|
|
@@ -587,388 +437,148 @@ Inject global Loading state management with XHR/Fetch request interception, whit
|
|
|
587
437
|
| spinnerSize | `string` | `'40px'` | Spinner icon size |
|
|
588
438
|
| textColor | `string` | `'#333'` | Text color |
|
|
589
439
|
| textSize | `string` | `'14px'` | Text size |
|
|
590
|
-
| customClass | `string` | - | Custom CSS class name |
|
|
591
|
-
| customStyle | `string` | - | Custom inline style |
|
|
592
440
|
| zIndex | `number` | `9999` | z-index value |
|
|
593
441
|
| pointerEvents | `boolean` | `true` | Whether to enable overlay pointer events |
|
|
594
|
-
| backdropBlur | `boolean` | `false` | Whether to enable
|
|
595
|
-
| backdropBlurAmount | `number` | `4` |
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
| Property | Type | Default | Description |
|
|
600
|
-
| -------- | --------- | ------------ | ---------------------------- |
|
|
601
|
-
| enabled | `boolean` | `true` | Whether to enable transition |
|
|
602
|
-
| duration | `number` | `200` | Transition duration (ms) |
|
|
603
|
-
| easing | `string` | `'ease-out'` | Easing function |
|
|
604
|
-
|
|
605
|
-
**MinDisplayTime**
|
|
606
|
-
|
|
607
|
-
| Property | Type | Default | Description |
|
|
608
|
-
| -------- | --------- | ------- | --------------------------------------------------------- |
|
|
609
|
-
| enabled | `boolean` | `true` | Whether to enable |
|
|
610
|
-
| duration | `number` | `300` | Minimum display time (ms), prevents Loading from flashing |
|
|
611
|
-
|
|
612
|
-
**DelayShow**
|
|
613
|
-
|
|
614
|
-
| Property | Type | Default | Description |
|
|
615
|
-
| -------- | --------- | ------- | ------------------------------------------------------------------------------ |
|
|
616
|
-
| enabled | `boolean` | `true` | Whether to enable |
|
|
617
|
-
| duration | `number` | `200` | Delay duration (ms); if request completes within this time, Loading won't show |
|
|
618
|
-
|
|
619
|
-
**DebounceHide**
|
|
620
|
-
|
|
621
|
-
| Property | Type | Default | Description |
|
|
622
|
-
| -------- | --------- | ------- | ----------------------- |
|
|
623
|
-
| enabled | `boolean` | `false` | Whether to enable |
|
|
624
|
-
| duration | `number` | `100` | Debounce wait time (ms) |
|
|
625
|
-
|
|
626
|
-
**RequestFilter**
|
|
627
|
-
|
|
628
|
-
| Property | Type | Description |
|
|
629
|
-
| ------------------ | ---------- | --------------------------------------------------------------------- |
|
|
630
|
-
| excludeUrls | `RegExp[]` | Array of URL regex patterns to exclude |
|
|
631
|
-
| includeUrls | `RegExp[]` | Array of URL regex patterns to include (higher priority than exclude) |
|
|
632
|
-
| excludeMethods | `string[]` | Array of HTTP methods to exclude |
|
|
633
|
-
| excludeUrlPrefixes | `string[]` | Array of URL prefixes to exclude (prefix matching, more efficient) |
|
|
634
|
-
|
|
635
|
-
**LoadingCallbacks**
|
|
636
|
-
|
|
637
|
-
Callbacks are provided as **function body strings** (injected into browser at build time, function references cannot be passed).
|
|
638
|
-
|
|
639
|
-
| Property | Type | Description |
|
|
640
|
-
| ------------ | -------- | ----------------------------------------------- |
|
|
641
|
-
| onBeforeShow | `string` | Before show callback, `return false` to prevent |
|
|
642
|
-
| onShow | `string` | After show callback |
|
|
643
|
-
| onBeforeHide | `string` | Before hide callback, `return false` to prevent |
|
|
644
|
-
| onHide | `string` | After hide callback |
|
|
645
|
-
| onDestroy | `string` | On destroy callback |
|
|
646
|
-
|
|
647
|
-
**LoadingManager API**
|
|
648
|
-
|
|
649
|
-
Access via `window.__LOADING_MANAGER__`:
|
|
650
|
-
|
|
651
|
-
| Method | Description |
|
|
652
|
-
| -------------------------- | ------------------------------------------------------------------- |
|
|
653
|
-
| `show(text?)` | Show Loading, optionally pass text |
|
|
654
|
-
| `hide()` | Hide Loading (subject to min display time and debounce constraints) |
|
|
655
|
-
| `forceHide()` | Force hide, ignoring min display time and debounce |
|
|
656
|
-
| `toggle(text?)` | Toggle Loading show/hide state |
|
|
657
|
-
| `updateText(text)` | Update text content |
|
|
658
|
-
| `isVisible()` | Get whether Loading is currently visible |
|
|
659
|
-
| `isPointerEventsEnabled()` | Get whether pointer events are currently enabled |
|
|
660
|
-
| `enablePointerEvents()` | Enable overlay pointer events, intercept all clicks and scrolls |
|
|
661
|
-
| `disablePointerEvents()` | Disable overlay pointer events, allow interaction passthrough |
|
|
662
|
-
| `togglePointerEvents()` | Toggle overlay pointer events state |
|
|
663
|
-
| `getPendingCount()` | Get the number of pending requests |
|
|
664
|
-
| `destroy()` | Destroy instance, clean up DOM and restore original interceptors |
|
|
665
|
-
|
|
666
|
-
```typescript
|
|
667
|
-
// White-screen Loading: visible on page load, auto-hide on DOMContentLoaded
|
|
668
|
-
loadingManager({ defaultVisible: true, autoHideOn: 'DOMContentLoaded' })
|
|
669
|
-
|
|
670
|
-
// White-screen Loading: auto-hide after all resources loaded
|
|
671
|
-
loadingManager({ defaultVisible: true, autoHideOn: 'load' })
|
|
672
|
-
|
|
673
|
-
// Vue/React SPA: visible on white screen, manually hide after framework renders
|
|
674
|
-
loadingManager({ defaultVisible: true, autoHideOn: 'manual' })
|
|
675
|
-
// In app entry: window.__LOADING_MANAGER__.hide()
|
|
676
|
-
|
|
677
|
-
// Auto-intercept all requests
|
|
678
|
-
loadingManager({ autoBind: 'all' })
|
|
679
|
-
|
|
680
|
-
// Custom styles + request filtering
|
|
681
|
-
loadingManager({
|
|
682
|
-
style: { overlayColor: 'rgba(0,0,0,0.5)', spinnerColor: '#fff', backdropBlur: true },
|
|
683
|
-
autoBind: 'fetch',
|
|
684
|
-
requestFilter: { excludeUrls: [/\/api\/health/], excludeUrlPrefixes: ['http://localhost'] }
|
|
685
|
-
})
|
|
686
|
-
|
|
687
|
-
// Debounced hide (prevent rapid flashing)
|
|
688
|
-
loadingManager({ debounceHide: { enabled: true, duration: 100 } })
|
|
442
|
+
| backdropBlur | `boolean` | `false` | Whether to enable background blur |
|
|
443
|
+
| backdropBlurAmount | `number` | `4` | Background blur amount (px) |
|
|
444
|
+
| customClass | `string` | - | Custom CSS class name |
|
|
445
|
+
| customStyle | `string` | - | Custom inline style string |
|
|
689
446
|
|
|
690
|
-
|
|
691
|
-
loadingManager({
|
|
692
|
-
callbacks: {
|
|
693
|
-
onBeforeShow: 'if (shouldSkip) return false;',
|
|
694
|
-
onShow: 'console.log("loading shown")',
|
|
695
|
-
onBeforeHide: 'if (shouldKeepVisible) return false;',
|
|
696
|
-
onHide: 'console.log("loading hidden")'
|
|
697
|
-
}
|
|
698
|
-
})
|
|
447
|
+
**Runtime API:**
|
|
699
448
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
window.__LOADING_MANAGER__.show('Saving...')
|
|
449
|
+
```typescript
|
|
450
|
+
window.__LOADING_MANAGER__.show('Loading...')
|
|
703
451
|
window.__LOADING_MANAGER__.hide()
|
|
452
|
+
window.__LOADING_MANAGER__.forceHide()
|
|
704
453
|
window.__LOADING_MANAGER__.toggle()
|
|
454
|
+
window.__LOADING_MANAGER__.updateText('Processing...')
|
|
455
|
+
window.__LOADING_MANAGER__.isVisible()
|
|
456
|
+
window.__LOADING_MANAGER__.getPendingCount()
|
|
457
|
+
window.__LOADING_MANAGER__.destroy()
|
|
458
|
+
window.__LOADING_MANAGER__.enablePointerEvents()
|
|
705
459
|
window.__LOADING_MANAGER__.disablePointerEvents()
|
|
460
|
+
window.__LOADING_MANAGER__.togglePointerEvents()
|
|
461
|
+
window.__LOADING_MANAGER__.isPointerEventsEnabled()
|
|
706
462
|
```
|
|
707
463
|
|
|
708
|
-
## Common Utilities
|
|
709
|
-
|
|
710
|
-
Exported via `@meng-xi/vite-plugin/common`, reusable in custom plugins:
|
|
711
|
-
|
|
712
464
|
```typescript
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
465
|
+
loadingManager()
|
|
466
|
+
loadingManager({ position: 'top', defaultText: 'Please wait...' })
|
|
467
|
+
loadingManager({ spinnerType: 'dots' })
|
|
468
|
+
loadingManager({ autoBind: 'fetch', requestFilter: { excludeUrls: [/\/api\/health/], excludeUrlPrefixes: ['http://localhost'] } })
|
|
469
|
+
loadingManager({ style: { overlayColor: 'rgba(0,0,0,0.5)', spinnerColor: '#ff6b6b', backdropBlur: true, backdropBlurAmount: 6 } })
|
|
470
|
+
loadingManager({ transition: { enabled: true, duration: 300, easing: 'cubic-bezier(0.4,0,0.2,1)' } })
|
|
471
|
+
loadingManager({ debounceHide: { enabled: true, duration: 100 } })
|
|
472
|
+
loadingManager({ callbacks: { onShow: 'console.log("loading shown")', onBeforeShow: 'return true', onHide: 'console.log("loading hidden")' } })
|
|
473
|
+
loadingManager({ customTemplate: '<div class="my-loader"><span data-loading-text></span></div>' })
|
|
474
|
+
loadingManager({ defaultVisible: true, autoHideOn: 'DOMContentLoaded' })
|
|
475
|
+
loadingManager({ defaultVisible: true, autoHideOn: 'manual' })
|
|
718
476
|
```
|
|
719
477
|
|
|
720
|
-
|
|
721
|
-
| ------------------------------- | ----------------------------------------------------------------------------- | ------------------- |
|
|
722
|
-
| `deepMerge()` | Deep merge objects (undefined skipped, arrays overwritten) | `common/object` |
|
|
723
|
-
| `formatDate()` | Format date with `{YYYY}`, `{MM}`, `{DD}` etc. placeholders | `common/format` |
|
|
724
|
-
| `parseTemplate()` | Parse template string, replace placeholders | `common/format` |
|
|
725
|
-
| `toCamelCase()` | Convert to camelCase | `common/format` |
|
|
726
|
-
| `toPascalCase()` | Convert to PascalCase | `common/format` |
|
|
727
|
-
| `stripJsonComments()` | Remove comments from JSON string | `common/format` |
|
|
728
|
-
| `generateRandomHash()` | Generate random hash string (1-64 characters) | `common/format` |
|
|
729
|
-
| `escapeHtmlAttr()` | Escape special characters in HTML attribute values, prevent XSS injection | `common/format` |
|
|
730
|
-
| `readFileContent()` | Async read file content | `common/fs` |
|
|
731
|
-
| `writeFileContent()` | Async write file content | `common/fs` |
|
|
732
|
-
| `fileExists()` | Async check if file exists | `common/fs` |
|
|
733
|
-
| `copySourceToTarget()` | Copy files or directories with incremental copy and concurrency | `common/fs` |
|
|
734
|
-
| `injectBeforeTag()` | Inject code before a specified closing HTML tag | `common/html` |
|
|
735
|
-
| `injectHtmlByPriority()` | Inject code into HTML by priority (`</head>` → `</body>` → `</html>`) | `common/html` |
|
|
736
|
-
| `injectBeforeTagWithFallback()` | Inject with fallback strategy (`</body>` → `</html>` → append) | `common/html` |
|
|
737
|
-
| `injectHeadAndBody()` | Dual-zone HTML injection (head + body) | `common/html` |
|
|
738
|
-
| `makeCallback()` | Wrap callback function body as safe function expression (with try-catch) | `common/script` |
|
|
739
|
-
| `containsScriptTag()` | Detect if a string contains `<script>` tags | `common/script` |
|
|
740
|
-
| `validateIdentifierName()` | Validate string as a legal JavaScript identifier, prevent prototype pollution | `common/script` |
|
|
741
|
-
| `validateGlobalName()` | Validate global variable name legality | `common/validation` |
|
|
742
|
-
| `validateNoScriptInTemplate()` | Validate template string does not contain script tags (XSS protection) | `common/validation` |
|
|
743
|
-
| `validateCallbackFields()` | Validate callback fields do not contain script tags | `common/validation` |
|
|
744
|
-
| `validateNonNegativeNumber()` | Validate number is non-negative | `common/validation` |
|
|
745
|
-
| `validateNestedDuration()` | Validate nested config duration legality | `common/validation` |
|
|
746
|
-
| `validateEnumValue()` | Validate string value is in allowed enum list | `common/validation` |
|
|
478
|
+
---
|
|
747
479
|
|
|
748
480
|
## Plugin Development Framework
|
|
749
481
|
|
|
750
|
-
### BasePlugin
|
|
751
|
-
|
|
752
|
-
`BasePlugin` is the base class for all plugins, providing complete lifecycle management and development conventions:
|
|
753
|
-
|
|
754
|
-
#### Lifecycle
|
|
755
|
-
|
|
756
|
-
| Phase | Method | Description |
|
|
757
|
-
| ----------------- | ------------------ | -------------------------------------------------------------- |
|
|
758
|
-
| Initialization | `constructor` | Merge options, initialize logger and validator |
|
|
759
|
-
| Config Resolution | `onConfigResolved` | Called when Vite config is resolved |
|
|
760
|
-
| Hook Registration | `addPluginHooks` | Register Vite plugin hooks |
|
|
761
|
-
| Destroy | `destroy` | Automatically called during `closeBundle` for resource cleanup |
|
|
762
|
-
|
|
763
|
-
#### Automatic Hook Composition
|
|
764
|
-
|
|
765
|
-
The `toPlugin()` method automatically composes the following hooks:
|
|
766
|
-
|
|
767
|
-
- **configResolved** - Base class `onConfigResolved` runs first, then subclass hook
|
|
768
|
-
- **closeBundle** - Subclass hook runs first, then base class `destroy`
|
|
769
|
-
|
|
770
|
-
> Subclasses don't need to manually register `closeBundle` hooks for cleanup — just override the `destroy()` method.
|
|
771
|
-
|
|
772
|
-
#### Required Methods
|
|
773
|
-
|
|
774
|
-
| Method | Description |
|
|
775
|
-
| ------------------------ | --------------------- |
|
|
776
|
-
| `getPluginName()` | Return plugin name |
|
|
777
|
-
| `addPluginHooks(plugin)` | Add Vite plugin hooks |
|
|
778
|
-
|
|
779
|
-
#### Optional Methods
|
|
780
|
-
|
|
781
|
-
| Method | Default Behavior | Description |
|
|
782
|
-
| -------------------------- | ----------------- | ------------------------------------------- |
|
|
783
|
-
| `getDefaultOptions()` | Returns `{}` | Provide plugin default options |
|
|
784
|
-
| `validateOptions()` | No validation | Validate configuration parameters |
|
|
785
|
-
| `getEnforce()` | `undefined` | Plugin execution order (`'pre'` / `'post'`) |
|
|
786
|
-
| `onConfigResolved(config)` | Store config | Config resolved callback |
|
|
787
|
-
| `destroy()` | Unregister logger | Cleanup logic when plugin is destroyed |
|
|
788
|
-
|
|
789
|
-
#### Built-in Properties
|
|
790
|
-
|
|
791
|
-
| Property | Type | Description |
|
|
792
|
-
| ------------ | ------------------------ | ----------------------------- |
|
|
793
|
-
| `options` | `Required<T>` | Merged complete configuration |
|
|
794
|
-
| `logger` | `PluginLogger` | Plugin logger |
|
|
795
|
-
| `validator` | `Validator<T>` | Configuration validator |
|
|
796
|
-
| `viteConfig` | `ResolvedConfig \| null` | Resolved Vite configuration |
|
|
797
|
-
|
|
798
|
-
#### Error Handling Strategy
|
|
799
|
-
|
|
800
|
-
Control error behavior via the `errorStrategy` configuration option:
|
|
801
|
-
|
|
802
|
-
- `'throw'` (default) - Log error and throw exception, halting the build
|
|
803
|
-
- `'log'` - Log error but don't throw, continue execution
|
|
804
|
-
- `'ignore'` - Log error but don't throw, continue execution
|
|
805
|
-
|
|
806
|
-
Wrap error-prone operations with `safeExecute` / `safeExecuteSync`:
|
|
807
|
-
|
|
808
|
-
```typescript
|
|
809
|
-
// Async safe execution
|
|
810
|
-
const result = await this.safeExecute(async () => {
|
|
811
|
-
return await someAsyncOperation()
|
|
812
|
-
}, 'Execute async operation')
|
|
813
|
-
|
|
814
|
-
// Sync safe execution
|
|
815
|
-
const value = this.safeExecuteSync(() => {
|
|
816
|
-
return someSyncOperation()
|
|
817
|
-
}, 'Execute sync operation')
|
|
818
|
-
```
|
|
819
|
-
|
|
820
|
-
### createPluginFactory
|
|
482
|
+
### BasePlugin
|
|
821
483
|
|
|
822
|
-
|
|
484
|
+
The base class for all built-in plugins, providing core functionality such as configuration management, logging, lifecycle management, and safe execution.
|
|
823
485
|
|
|
824
486
|
```typescript
|
|
825
|
-
|
|
826
|
-
const myPlugin = createPluginFactory(MyPlugin)
|
|
827
|
-
|
|
828
|
-
// With normalizer (supports shorthand string config)
|
|
829
|
-
const myPlugin = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
830
|
-
|
|
831
|
-
// Usage with shorthand
|
|
832
|
-
myPlugin('./custom-path')
|
|
833
|
-
```
|
|
834
|
-
|
|
835
|
-
### Validator
|
|
836
|
-
|
|
837
|
-
Fluent configuration validator with chainable API:
|
|
838
|
-
|
|
839
|
-
```typescript
|
|
840
|
-
import { Validator } from '@meng-xi/vite-plugin/common'
|
|
841
|
-
|
|
842
|
-
const validator = new Validator(options)
|
|
843
|
-
validator
|
|
844
|
-
.field('sourceDir')
|
|
845
|
-
.required()
|
|
846
|
-
.string()
|
|
847
|
-
.field('targetDir')
|
|
848
|
-
.required()
|
|
849
|
-
.string()
|
|
850
|
-
.field('overwrite')
|
|
851
|
-
.boolean()
|
|
852
|
-
.default(true)
|
|
853
|
-
.field('port')
|
|
854
|
-
.number()
|
|
855
|
-
.field('list')
|
|
856
|
-
.array()
|
|
857
|
-
.field('config')
|
|
858
|
-
.object()
|
|
859
|
-
.field('name')
|
|
860
|
-
.custom(val => val.length > 0, 'name cannot be empty')
|
|
861
|
-
.validate()
|
|
862
|
-
```
|
|
863
|
-
|
|
864
|
-
| Method | Description |
|
|
865
|
-
| ------------ | ----------------------------------------------------------------- |
|
|
866
|
-
| `field()` | Specify the field to validate |
|
|
867
|
-
| `required()` | Mark field as required |
|
|
868
|
-
| `string()` | Validate field value is a string type |
|
|
869
|
-
| `boolean()` | Validate field value is a boolean type |
|
|
870
|
-
| `number()` | Validate field value is a number type |
|
|
871
|
-
| `array()` | Validate field value is an array type |
|
|
872
|
-
| `object()` | Validate field value is an object type |
|
|
873
|
-
| `enum()` | Validate field value is in allowed enum list |
|
|
874
|
-
| `minValue()` | Validate number field value is not less than specified minimum |
|
|
875
|
-
| `maxValue()` | Validate number field value is not greater than specified maximum |
|
|
876
|
-
| `default()` | Set default value for field (only when value is undefined/null) |
|
|
877
|
-
| `custom()` | Validate field value with a custom function |
|
|
878
|
-
| `validate()` | Execute validation, throws error on failure |
|
|
879
|
-
|
|
880
|
-
### Logger
|
|
881
|
-
|
|
882
|
-
Global singleton log manager providing independent log control for each plugin:
|
|
883
|
-
|
|
884
|
-
```typescript
|
|
885
|
-
import { Logger } from '@meng-xi/vite-plugin/logger'
|
|
886
|
-
|
|
887
|
-
// Create logger (usually called automatically by BasePlugin)
|
|
888
|
-
Logger.create({ name: 'my-plugin', enabled: true })
|
|
889
|
-
|
|
890
|
-
// Unregister plugin log config (automatically called on plugin destroy)
|
|
891
|
-
Logger.unregister('my-plugin')
|
|
892
|
-
|
|
893
|
-
// Destroy singleton (for test scenarios)
|
|
894
|
-
Logger.destroy()
|
|
895
|
-
```
|
|
896
|
-
|
|
897
|
-
Log output format:
|
|
898
|
-
|
|
899
|
-
```
|
|
900
|
-
ℹ️ [@meng-xi/vite-plugin:my-plugin] Info message
|
|
901
|
-
✅ [@meng-xi/vite-plugin:my-plugin] Success message
|
|
902
|
-
⚠️ [@meng-xi/vite-plugin:my-plugin] Warning message
|
|
903
|
-
❌ [@meng-xi/vite-plugin:my-plugin] Error message
|
|
904
|
-
```
|
|
905
|
-
|
|
906
|
-
### Custom Plugin Example
|
|
907
|
-
|
|
908
|
-
```typescript
|
|
909
|
-
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin'
|
|
910
|
-
import type { BasePluginOptions, PluginWithInstance } from '@meng-xi/vite-plugin/factory'
|
|
487
|
+
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin/factory'
|
|
911
488
|
import type { Plugin } from 'vite'
|
|
912
489
|
|
|
913
|
-
interface MyPluginOptions
|
|
914
|
-
|
|
490
|
+
interface MyPluginOptions {
|
|
491
|
+
enabled?: boolean
|
|
492
|
+
message?: string
|
|
915
493
|
}
|
|
916
494
|
|
|
917
495
|
class MyPlugin extends BasePlugin<MyPluginOptions> {
|
|
496
|
+
protected getPluginName() {
|
|
497
|
+
return 'my-plugin'
|
|
498
|
+
}
|
|
918
499
|
protected getDefaultOptions() {
|
|
919
|
-
return {
|
|
500
|
+
return { enabled: true, message: 'Hello' }
|
|
920
501
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
this.validator.field('path').required().string().validate()
|
|
502
|
+
protected validateOptions() {
|
|
503
|
+
this.validator.field('message').string().validate()
|
|
924
504
|
}
|
|
925
|
-
|
|
926
|
-
protected getPluginName(): string {
|
|
927
|
-
return 'my-plugin'
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
protected addPluginHooks(plugin: Plugin): void {
|
|
505
|
+
protected addPluginHooks(plugin: Plugin) {
|
|
931
506
|
plugin.buildStart = () => {
|
|
932
|
-
this.logger.info(
|
|
507
|
+
this.logger.info(this.options.message)
|
|
933
508
|
}
|
|
934
509
|
}
|
|
935
|
-
|
|
936
|
-
protected destroy(): void {
|
|
937
|
-
super.destroy()
|
|
938
|
-
// Custom cleanup logic, e.g. close connections, stop watchers
|
|
939
|
-
}
|
|
940
510
|
}
|
|
941
511
|
|
|
942
|
-
// Basic usage
|
|
943
512
|
export const myPlugin = createPluginFactory(MyPlugin)
|
|
944
|
-
|
|
945
|
-
// With normalizer (supports shorthand string config)
|
|
946
|
-
export const myPluginWithNormalizer = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
947
|
-
// Usage with shorthand: myPluginWithNormalizer('./custom-path')
|
|
948
513
|
```
|
|
949
514
|
|
|
515
|
+
### Core Components
|
|
516
|
+
|
|
517
|
+
| Component | Export Path | Description |
|
|
518
|
+
| --------------------- | ------------------------------ | ----------------------------------- |
|
|
519
|
+
| `BasePlugin` | `@meng-xi/vite-plugin/factory` | Plugin base class |
|
|
520
|
+
| `createPluginFactory` | `@meng-xi/vite-plugin/factory` | Plugin factory function creator |
|
|
521
|
+
| `PluginWithInstance` | `@meng-xi/vite-plugin/factory` | Plugin type with instance reference |
|
|
522
|
+
| `Logger` | `@meng-xi/vite-plugin/logger` | Log manager (singleton pattern) |
|
|
523
|
+
| `Validator` | `@meng-xi/vite-plugin/common` | Fluent API configuration validator |
|
|
524
|
+
|
|
525
|
+
### Common Utilities
|
|
526
|
+
|
|
527
|
+
| Module | Export Path | Description |
|
|
528
|
+
| ---------- | ---------------------------------------- | ----------------------------------------------------------------- |
|
|
529
|
+
| format | `@meng-xi/vite-plugin/common/format` | Date formatting, name conversion, template parsing, HTML escaping |
|
|
530
|
+
| fs | `@meng-xi/vite-plugin/common/fs` | File copying, directory traversal, concurrency control |
|
|
531
|
+
| html | `@meng-xi/vite-plugin/common/html` | HTML injection (injectBeforeTag, injectHeadAndBody, etc.) |
|
|
532
|
+
| object | `@meng-xi/vite-plugin/common/object` | Deep merge objects |
|
|
533
|
+
| script | `@meng-xi/vite-plugin/common/script` | Callback wrapping, script tag detection, identifier validation |
|
|
534
|
+
| validation | `@meng-xi/vite-plugin/common/validation` | Global name validation, XSS prevention, enum validation, etc. |
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
950
538
|
## Sub-path Exports
|
|
951
539
|
|
|
952
540
|
Support importing modules on demand to reduce bundle size:
|
|
953
541
|
|
|
954
542
|
```typescript
|
|
955
|
-
// Full import
|
|
956
543
|
import { buildProgress, copyFile, htmlInject, loadingManager, BasePlugin, Logger } from '@meng-xi/vite-plugin'
|
|
957
544
|
|
|
958
|
-
// Module-level import
|
|
959
545
|
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin/factory'
|
|
960
546
|
import { Logger } from '@meng-xi/vite-plugin/logger'
|
|
961
|
-
import { buildProgress, copyFile, generateRouter, htmlInject, loadingManager } from '@meng-xi/vite-plugin/plugins'
|
|
962
|
-
import { Validator, readFileContent, writeFileContent } from '@meng-xi/vite-plugin/common'
|
|
547
|
+
import { buildProgress, compressAssets, copyFile, generateRouter, generateVersion, versionUpdateChecker, htmlInject, faviconManager, loadingManager } from '@meng-xi/vite-plugin/plugins'
|
|
548
|
+
import { Validator, readFileContent, writeFileContent, injectHeadAndBody, deepMerge } from '@meng-xi/vite-plugin/common'
|
|
963
549
|
|
|
964
|
-
// Type imports (on-demand type definitions from sub-paths)
|
|
965
550
|
import type { PluginWithInstance, PluginFactory, BasePluginOptions } from '@meng-xi/vite-plugin/factory'
|
|
966
|
-
import type { BuildProgressOptions, GenerateVersionOptions, VersionUpdateCheckerOptions, HtmlInjectOptions,
|
|
551
|
+
import type { BuildProgressOptions, CompressAssetsOptions, GenerateVersionOptions, VersionUpdateCheckerOptions, HtmlInjectOptions, FaviconManagerOptions, LoadingManagerOptions } from '@meng-xi/vite-plugin/plugins'
|
|
967
552
|
import type { DateFormatOptions } from '@meng-xi/vite-plugin/common/format'
|
|
968
553
|
import type { HtmlInjectResult, DualInjectResult } from '@meng-xi/vite-plugin/common/html'
|
|
969
554
|
import type { CopyOptions, CopyResult } from '@meng-xi/vite-plugin/common/fs'
|
|
970
555
|
```
|
|
971
556
|
|
|
557
|
+
**All available sub-paths:**
|
|
558
|
+
|
|
559
|
+
```
|
|
560
|
+
@meng-xi/vite-plugin
|
|
561
|
+
@meng-xi/vite-plugin/factory
|
|
562
|
+
@meng-xi/vite-plugin/logger
|
|
563
|
+
@meng-xi/vite-plugin/plugins
|
|
564
|
+
@meng-xi/vite-plugin/plugins/build-progress
|
|
565
|
+
@meng-xi/vite-plugin/plugins/compress-assets
|
|
566
|
+
@meng-xi/vite-plugin/plugins/copy-file
|
|
567
|
+
@meng-xi/vite-plugin/plugins/favicon-manager
|
|
568
|
+
@meng-xi/vite-plugin/plugins/generate-router
|
|
569
|
+
@meng-xi/vite-plugin/plugins/generate-version
|
|
570
|
+
@meng-xi/vite-plugin/plugins/html-inject
|
|
571
|
+
@meng-xi/vite-plugin/plugins/loading-manager
|
|
572
|
+
@meng-xi/vite-plugin/plugins/version-update-checker
|
|
573
|
+
@meng-xi/vite-plugin/common
|
|
574
|
+
@meng-xi/vite-plugin/common/format
|
|
575
|
+
@meng-xi/vite-plugin/common/fs
|
|
576
|
+
@meng-xi/vite-plugin/common/html
|
|
577
|
+
@meng-xi/vite-plugin/common/object
|
|
578
|
+
@meng-xi/vite-plugin/common/script
|
|
579
|
+
@meng-xi/vite-plugin/common/validation
|
|
580
|
+
```
|
|
581
|
+
|
|
972
582
|
## Changelog
|
|
973
583
|
|
|
974
584
|
View [GitHub Releases](https://github.com/MengXi-Studio/vite-plugin/releases)
|