@meng-xi/vite-plugin 0.0.9 → 0.1.0
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 +345 -268
- package/README.md +331 -254
- package/dist/common/index.cjs +1 -1
- package/dist/common/index.d.cts +101 -2
- package/dist/common/index.d.mts +101 -2
- package/dist/common/index.d.ts +101 -2
- package/dist/common/index.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.d.cts +361 -167
- package/dist/plugins/index.d.mts +361 -167
- package/dist/plugins/index.d.ts +361 -167
- package/dist/plugins/index.mjs +1 -1
- package/dist/shared/vite-plugin.D6Law9Ke.mjs +706 -0
- package/dist/shared/vite-plugin.D8L9KzuW.cjs +706 -0
- package/dist/shared/vite-plugin.DFjf9wFM.mjs +2 -0
- package/dist/shared/vite-plugin.Tab4qcIM.cjs +2 -0
- package/package.json +1 -1
- 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.CsdNNQ-4.cjs +0 -526
package/README-en.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
## Features
|
|
17
17
|
|
|
18
|
-
- **Ready to Use** - Provides
|
|
18
|
+
- **Ready to Use** - Provides 7 practical plugins covering build progress display, file copying, router generation, version management, version update checking, icon injection, and global Loading state management
|
|
19
19
|
- **Plugin Development Framework** - Exports core components like BasePlugin, Logger, Validator for building custom Vite plugins
|
|
20
20
|
- **Complete Lifecycle** - Supports initialization, config resolution, destroy lifecycle management with automatic hook composition
|
|
21
21
|
- **Type Safe** - Complete TypeScript type definitions with configuration validators ensuring parameter correctness
|
|
@@ -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, faviconManager, loadingManager } from '@meng-xi/vite-plugin'
|
|
50
50
|
|
|
51
51
|
export default defineConfig({
|
|
52
52
|
plugins: [
|
|
@@ -71,11 +71,14 @@ export default defineConfig({
|
|
|
71
71
|
outputType: 'both'
|
|
72
72
|
}),
|
|
73
73
|
|
|
74
|
+
// Version update checker (works with generateVersion)
|
|
75
|
+
versionUpdateChecker(),
|
|
76
|
+
|
|
74
77
|
// Inject website icon (supports string shorthand)
|
|
75
|
-
|
|
78
|
+
faviconManager('/assets'),
|
|
76
79
|
|
|
77
|
-
//
|
|
78
|
-
|
|
80
|
+
// Global Loading state management
|
|
81
|
+
loadingManager({
|
|
79
82
|
defaultVisible: true,
|
|
80
83
|
autoHideOn: 'DOMContentLoaded'
|
|
81
84
|
})
|
|
@@ -97,238 +100,17 @@ const routerPlugin = generateRouter({ watch: true }) as PluginWithInstance<Gener
|
|
|
97
100
|
console.log(routerPlugin.pluginInstance?.options)
|
|
98
101
|
```
|
|
99
102
|
|
|
100
|
-
### Developing Custom Plugins
|
|
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
|
-
// Custom cleanup logic, e.g. close connections, stop watchers
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Basic usage
|
|
137
|
-
export const myPlugin = createPluginFactory(MyPlugin)
|
|
138
|
-
|
|
139
|
-
// With normalizer (supports shorthand string config)
|
|
140
|
-
export const myPluginWithNormalizer = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
141
|
-
// Usage with shorthand: myPluginWithNormalizer('./custom-path')
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## Plugin Development Framework
|
|
145
|
-
|
|
146
|
-
### BasePlugin Core Concepts
|
|
147
|
-
|
|
148
|
-
`BasePlugin` is the base class for all plugins, providing complete lifecycle management and development conventions:
|
|
149
|
-
|
|
150
|
-
#### Lifecycle
|
|
151
|
-
|
|
152
|
-
| Phase | Method | Description |
|
|
153
|
-
| ----------------- | ------------------ | -------------------------------------------------------------- |
|
|
154
|
-
| Initialization | `constructor` | Merge options, initialize logger and validator |
|
|
155
|
-
| Config Resolution | `onConfigResolved` | Called when Vite config is resolved |
|
|
156
|
-
| Hook Registration | `addPluginHooks` | Register Vite plugin hooks |
|
|
157
|
-
| Destroy | `destroy` | Automatically called during `closeBundle` for resource cleanup |
|
|
158
|
-
|
|
159
|
-
#### Automatic Hook Composition
|
|
160
|
-
|
|
161
|
-
The `toPlugin()` method automatically composes the following hooks:
|
|
162
|
-
|
|
163
|
-
- **configResolved** - Base class `onConfigResolved` runs first, then subclass hook
|
|
164
|
-
- **closeBundle** - Subclass hook runs first, then base class `destroy`
|
|
165
|
-
|
|
166
|
-
> Subclasses don't need to manually register `closeBundle` hooks for cleanup — just override the `destroy()` method.
|
|
167
|
-
|
|
168
|
-
#### Required Methods
|
|
169
|
-
|
|
170
|
-
| Method | Description |
|
|
171
|
-
| ------------------------ | --------------------- |
|
|
172
|
-
| `getPluginName()` | Return plugin name |
|
|
173
|
-
| `addPluginHooks(plugin)` | Add Vite plugin hooks |
|
|
174
|
-
|
|
175
|
-
#### Optional Methods
|
|
176
|
-
|
|
177
|
-
| Method | Default Behavior | Description |
|
|
178
|
-
| -------------------------- | ----------------- | ------------------------------------------- |
|
|
179
|
-
| `getDefaultOptions()` | Returns `{}` | Provide plugin default options |
|
|
180
|
-
| `validateOptions()` | No validation | Validate configuration parameters |
|
|
181
|
-
| `getEnforce()` | `undefined` | Plugin execution order (`'pre'` / `'post'`) |
|
|
182
|
-
| `onConfigResolved(config)` | Store config | Config resolved callback |
|
|
183
|
-
| `destroy()` | Unregister logger | Cleanup logic when plugin is destroyed |
|
|
184
|
-
|
|
185
|
-
#### Built-in Properties
|
|
186
|
-
|
|
187
|
-
| Property | Type | Description |
|
|
188
|
-
| ------------ | ------------------------ | ----------------------------- |
|
|
189
|
-
| `options` | `Required<T>` | Merged complete configuration |
|
|
190
|
-
| `logger` | `PluginLogger` | Plugin logger |
|
|
191
|
-
| `validator` | `Validator<T>` | Configuration validator |
|
|
192
|
-
| `viteConfig` | `ResolvedConfig \| null` | Resolved Vite configuration |
|
|
193
|
-
|
|
194
|
-
#### Error Handling Strategy
|
|
195
|
-
|
|
196
|
-
Control error behavior via the `errorStrategy` configuration option:
|
|
197
|
-
|
|
198
|
-
- `'throw'` (default) - Log error and throw exception, halting the build
|
|
199
|
-
- `'log'` - Log error but don't throw, continue execution
|
|
200
|
-
- `'ignore'` - Log error but don't throw, continue execution
|
|
201
|
-
|
|
202
|
-
Wrap error-prone operations with `safeExecute` / `safeExecuteSync`:
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
// Async safe execution
|
|
206
|
-
const result = await this.safeExecute(async () => {
|
|
207
|
-
return await someAsyncOperation()
|
|
208
|
-
}, 'Execute async operation')
|
|
209
|
-
|
|
210
|
-
// Sync safe execution
|
|
211
|
-
const value = this.safeExecuteSync(() => {
|
|
212
|
-
return someSyncOperation()
|
|
213
|
-
}, 'Execute sync operation')
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### createPluginFactory
|
|
217
|
-
|
|
218
|
-
Create plugin factory functions with optional normalizer support:
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
// Basic usage
|
|
222
|
-
const myPlugin = createPluginFactory(MyPlugin)
|
|
223
|
-
|
|
224
|
-
// With normalizer (supports shorthand string config)
|
|
225
|
-
const myPlugin = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
226
|
-
|
|
227
|
-
// Usage with shorthand
|
|
228
|
-
myPlugin('./custom-path')
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### Validator
|
|
232
|
-
|
|
233
|
-
Fluent configuration validator with chainable API:
|
|
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 cannot be empty')
|
|
257
|
-
.validate()
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
| Method | Description |
|
|
261
|
-
| ------------ | --------------------------------------------------------------- |
|
|
262
|
-
| `field()` | Specify the field to validate |
|
|
263
|
-
| `required()` | Mark field as required |
|
|
264
|
-
| `string()` | Validate field value is a string type |
|
|
265
|
-
| `boolean()` | Validate field value is a boolean type |
|
|
266
|
-
| `number()` | Validate field value is a number type |
|
|
267
|
-
| `array()` | Validate field value is an array type |
|
|
268
|
-
| `object()` | Validate field value is an object type |
|
|
269
|
-
| `default()` | Set default value for field (only when value is undefined/null) |
|
|
270
|
-
| `custom()` | Validate field value with a custom function |
|
|
271
|
-
| `validate()` | Execute validation, throws error on failure |
|
|
272
|
-
|
|
273
|
-
### Logger
|
|
274
|
-
|
|
275
|
-
Global singleton log manager providing independent log control for each plugin:
|
|
276
|
-
|
|
277
|
-
```typescript
|
|
278
|
-
import { Logger } from '@meng-xi/vite-plugin/logger'
|
|
279
|
-
|
|
280
|
-
// Create logger (usually called automatically by BasePlugin)
|
|
281
|
-
Logger.create({ name: 'my-plugin', enabled: true })
|
|
282
|
-
|
|
283
|
-
// Unregister plugin log config (automatically called on plugin destroy)
|
|
284
|
-
Logger.unregister('my-plugin')
|
|
285
|
-
|
|
286
|
-
// Destroy singleton (for test scenarios)
|
|
287
|
-
Logger.destroy()
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
Log output format:
|
|
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
|
-
### Common Utilities
|
|
300
|
-
|
|
301
|
-
Exported via `@meng-xi/vite-plugin/common`, reusable in custom plugins:
|
|
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
|
-
| Function | Description |
|
|
309
|
-
| ---------------------- | --------------------------------------------------------------- |
|
|
310
|
-
| `deepMerge()` | Deep merge objects (undefined skipped, arrays overwritten) |
|
|
311
|
-
| `formatDate()` | Format date with `{YYYY}`, `{MM}`, `{DD}` etc. placeholders |
|
|
312
|
-
| `parseTemplate()` | Parse template string, replace placeholders |
|
|
313
|
-
| `toCamelCase()` | Convert to camelCase |
|
|
314
|
-
| `toPascalCase()` | Convert to PascalCase |
|
|
315
|
-
| `stripJsonComments()` | Remove comments from JSON string |
|
|
316
|
-
| `generateRandomHash()` | Generate random hash string (1-64 characters) |
|
|
317
|
-
| `readFileContent()` | Async read file content |
|
|
318
|
-
| `writeFileContent()` | Async write file content |
|
|
319
|
-
| `fileExists()` | Async check if file exists |
|
|
320
|
-
| `copySourceToTarget()` | Copy files or directories with incremental copy and concurrency |
|
|
321
|
-
|
|
322
103
|
## Built-in Plugins
|
|
323
104
|
|
|
324
|
-
| Plugin
|
|
325
|
-
|
|
|
326
|
-
| buildProgress
|
|
327
|
-
| copyFile
|
|
328
|
-
| generateRouter
|
|
329
|
-
| generateVersion
|
|
330
|
-
|
|
|
331
|
-
|
|
|
105
|
+
| Plugin | Description |
|
|
106
|
+
| -------------------- | ---------------------------------------------------------------------------------------- |
|
|
107
|
+
| buildProgress | Real-time build progress bar in terminal, supports bar / spinner / minimal |
|
|
108
|
+
| copyFile | Copy files or directories after build, supports incremental copying |
|
|
109
|
+
| generateRouter | Auto-generate router config from pages.json (uni-app) |
|
|
110
|
+
| generateVersion | Auto-generate version numbers, supports file output and global variable injection |
|
|
111
|
+
| versionUpdateChecker | Runtime version update checking with multiple prompt styles and custom callbacks |
|
|
112
|
+
| faviconManager | Manage website favicon links injection into HTML files, supports string shorthand config |
|
|
113
|
+
| loadingManager | Global Loading state management with request interception and white-screen Loading |
|
|
332
114
|
|
|
333
115
|
### buildProgress
|
|
334
116
|
|
|
@@ -470,18 +252,18 @@ generateRouter({
|
|
|
470
252
|
|
|
471
253
|
Automatically generate version numbers during the Vite build process.
|
|
472
254
|
|
|
473
|
-
| Option | Type | Default | Description
|
|
474
|
-
| ------------ | --------------------------------------------------------------------------------- | ------------------- |
|
|
475
|
-
| format | `'timestamp'` \| `'date'` \| `'datetime'` \| `'semver'` \| `'hash'` \| `'custom'` | `'timestamp'` | Version format
|
|
476
|
-
| customFormat | `string` | - | Custom format template
|
|
477
|
-
| semverBase | `string` | `'1.0.0'` | Semantic version base
|
|
478
|
-
| outputType | `'file'` \| `'define'` \| `'both'` | `'file'` | Output type
|
|
479
|
-
| outputFile | `string` | `'version.json'` | Output file path
|
|
480
|
-
| defineName | `string` | `'__APP_VERSION__'` |
|
|
481
|
-
| hashLength | `number` | `8` | Hash length (1-32)
|
|
482
|
-
| prefix | `string` | - | Version number prefix
|
|
483
|
-
| suffix | `string` | - | Version number suffix
|
|
484
|
-
| extra | `Record<string, unknown>` | - |
|
|
255
|
+
| Option | Type | Default | Description |
|
|
256
|
+
| ------------ | --------------------------------------------------------------------------------- | ------------------- | -------------------------------- |
|
|
257
|
+
| format | `'timestamp'` \| `'date'` \| `'datetime'` \| `'semver'` \| `'hash'` \| `'custom'` | `'timestamp'` | Version number format |
|
|
258
|
+
| customFormat | `string` | - | Custom format template |
|
|
259
|
+
| semverBase | `string` | `'1.0.0'` | Semantic version base value |
|
|
260
|
+
| outputType | `'file'` \| `'define'` \| `'both'` | `'file'` | Output type |
|
|
261
|
+
| outputFile | `string` | `'version.json'` | Output file path |
|
|
262
|
+
| defineName | `string` | `'__APP_VERSION__'` | Injected global variable name |
|
|
263
|
+
| hashLength | `number` | `8` | Hash length (1-32) |
|
|
264
|
+
| prefix | `string` | - | Version number prefix |
|
|
265
|
+
| suffix | `string` | - | Version number suffix |
|
|
266
|
+
| extra | `Record<string, unknown>` | - | Additional info (JSON file only) |
|
|
485
267
|
|
|
486
268
|
**customFormat placeholders:**
|
|
487
269
|
|
|
@@ -533,7 +315,73 @@ generateVersion({
|
|
|
533
315
|
})
|
|
534
316
|
```
|
|
535
317
|
|
|
536
|
-
###
|
|
318
|
+
### versionUpdateChecker
|
|
319
|
+
|
|
320
|
+
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.
|
|
321
|
+
|
|
322
|
+
**How it works:**
|
|
323
|
+
|
|
324
|
+
1. `generateVersion` generates a version file (`version.json`) or injects a global variable at build time
|
|
325
|
+
2. `versionUpdateChecker` periodically requests the version file at runtime and compares it with the current version
|
|
326
|
+
3. When a version mismatch is detected, a prompt is shown to guide the user to refresh
|
|
327
|
+
|
|
328
|
+
| Option | Type | Default | Description |
|
|
329
|
+
| ----------------------- | ------------------------------------ | -------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
330
|
+
| versionSource | `'define'` \| `'file'` \| `'auto'` | `'auto'` | Current version source |
|
|
331
|
+
| defineName | `string` | `'__APP_VERSION__'` | Global variable name in define mode |
|
|
332
|
+
| checkUrl | `string` | `'/version.json'` | URL path for version check file |
|
|
333
|
+
| checkInterval | `number` | `300000` | Check interval in milliseconds (default 5 minutes) |
|
|
334
|
+
| checkOnVisibilityChange | `boolean` | `true` | Whether to check immediately on page visibility change |
|
|
335
|
+
| enableInDev | `boolean` | `false` | Whether to enable in development mode |
|
|
336
|
+
| promptStyle | `'modal'` \| `'banner'` \| `'toast'` | `'modal'` | Update prompt UI style |
|
|
337
|
+
| promptMessage | `string` | `'A new version is available. Refresh now to get the latest?'` | Prompt message text |
|
|
338
|
+
| refreshButtonText | `string` | `'Refresh'` | Refresh button text |
|
|
339
|
+
| dismissButtonText | `string` | `'Later'` | Dismiss button text |
|
|
340
|
+
| customPromptTemplate | `string` | - | Custom HTML template for the prompt UI |
|
|
341
|
+
| customStyle | `string` | - | Custom CSS style string |
|
|
342
|
+
| onUpdateAvailable | `string` | - | Callback when new version is found (function body string) |
|
|
343
|
+
| onRefresh | `string` | - | Callback when user chooses to refresh (function body string) |
|
|
344
|
+
| onDismiss | `string` | - | Callback when user chooses to dismiss (function body string) |
|
|
345
|
+
|
|
346
|
+
> `versionSource` explanation: `'define'` reads from global variable, `'file'` reads from version file, `'auto'` prefers define and falls back to file. Custom templates can use `{{message}}`, `{{currentVersion}}`,
|
|
347
|
+
> `{{newVersion}}`, `{{refreshButton}}`, `{{dismissButton}}` placeholders. Callbacks are provided as function body strings with available variables: `currentVersion`, `newVersion`.
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
// Basic usage (with generateVersion)
|
|
351
|
+
generateVersion({ outputType: 'both' })
|
|
352
|
+
versionUpdateChecker()
|
|
353
|
+
|
|
354
|
+
// Read from version file only
|
|
355
|
+
versionUpdateChecker({ versionSource: 'file' })
|
|
356
|
+
|
|
357
|
+
// Custom check interval and prompt style
|
|
358
|
+
versionUpdateChecker({
|
|
359
|
+
checkInterval: 60000,
|
|
360
|
+
promptStyle: 'banner'
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
// Toast-style prompt
|
|
364
|
+
versionUpdateChecker({ promptStyle: 'toast' })
|
|
365
|
+
|
|
366
|
+
// Custom prompt text
|
|
367
|
+
versionUpdateChecker({
|
|
368
|
+
promptMessage: 'System updated, refresh to experience new features',
|
|
369
|
+
refreshButtonText: 'Update',
|
|
370
|
+
dismissButtonText: 'Cancel'
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
// Custom callbacks
|
|
374
|
+
versionUpdateChecker({
|
|
375
|
+
onUpdateAvailable: 'console.log("New version:", newVersion); return true;',
|
|
376
|
+
onRefresh: 'console.log("User chose to refresh");',
|
|
377
|
+
onDismiss: 'console.log("User chose to dismiss");'
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
// Enable in development (for debugging)
|
|
381
|
+
versionUpdateChecker({ enableInDev: true })
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### faviconManager
|
|
537
385
|
|
|
538
386
|
Inject website icon links into the head of HTML files during the Vite build process. Supports string shorthand config.
|
|
539
387
|
|
|
@@ -567,13 +415,13 @@ Inject website icon links into the head of HTML files during the Vite build proc
|
|
|
567
415
|
|
|
568
416
|
```typescript
|
|
569
417
|
// Use default config
|
|
570
|
-
|
|
418
|
+
faviconManager()
|
|
571
419
|
|
|
572
420
|
// String shorthand (set base path)
|
|
573
|
-
|
|
421
|
+
faviconManager('/assets')
|
|
574
422
|
|
|
575
423
|
// Custom icon array
|
|
576
|
-
|
|
424
|
+
faviconManager({
|
|
577
425
|
base: '/assets',
|
|
578
426
|
icons: [
|
|
579
427
|
{ rel: 'icon', href: '/favicon.svg', type: 'image/svg+xml' },
|
|
@@ -583,12 +431,12 @@ injectIco({
|
|
|
583
431
|
})
|
|
584
432
|
|
|
585
433
|
// Custom complete link tag
|
|
586
|
-
|
|
434
|
+
faviconManager({
|
|
587
435
|
link: '<link rel="icon" href="/favicon.svg" type="image/svg+xml" />'
|
|
588
436
|
})
|
|
589
437
|
|
|
590
438
|
// With file copying
|
|
591
|
-
|
|
439
|
+
faviconManager({
|
|
592
440
|
base: '/assets',
|
|
593
441
|
copyOptions: {
|
|
594
442
|
sourceDir: 'src/assets/icons',
|
|
@@ -597,7 +445,7 @@ injectIco({
|
|
|
597
445
|
})
|
|
598
446
|
```
|
|
599
447
|
|
|
600
|
-
###
|
|
448
|
+
### loadingManager
|
|
601
449
|
|
|
602
450
|
Inject global Loading state management with XHR/Fetch request interception, white-screen Loading, custom styles, and lifecycle callbacks.
|
|
603
451
|
|
|
@@ -711,30 +559,30 @@ Access via `window.__LOADING_MANAGER__`:
|
|
|
711
559
|
|
|
712
560
|
```typescript
|
|
713
561
|
// White-screen Loading: visible on page load, auto-hide on DOMContentLoaded
|
|
714
|
-
|
|
562
|
+
loadingManager({ defaultVisible: true, autoHideOn: 'DOMContentLoaded' })
|
|
715
563
|
|
|
716
564
|
// White-screen Loading: auto-hide after all resources loaded
|
|
717
|
-
|
|
565
|
+
loadingManager({ defaultVisible: true, autoHideOn: 'load' })
|
|
718
566
|
|
|
719
567
|
// Vue/React SPA: visible on white screen, manually hide after framework renders
|
|
720
|
-
|
|
568
|
+
loadingManager({ defaultVisible: true, autoHideOn: 'manual' })
|
|
721
569
|
// In app entry: window.__LOADING_MANAGER__.hide()
|
|
722
570
|
|
|
723
571
|
// Auto-intercept all requests
|
|
724
|
-
|
|
572
|
+
loadingManager({ autoBind: 'all' })
|
|
725
573
|
|
|
726
574
|
// Custom styles + request filtering
|
|
727
|
-
|
|
575
|
+
loadingManager({
|
|
728
576
|
style: { overlayColor: 'rgba(0,0,0,0.5)', spinnerColor: '#fff', backdropBlur: true },
|
|
729
577
|
autoBind: 'fetch',
|
|
730
578
|
requestFilter: { excludeUrls: [/\/api\/health/], excludeUrlPrefixes: ['http://localhost'] }
|
|
731
579
|
})
|
|
732
580
|
|
|
733
581
|
// Debounced hide (prevent rapid flashing)
|
|
734
|
-
|
|
582
|
+
loadingManager({ debounceHide: { enabled: true, duration: 100 } })
|
|
735
583
|
|
|
736
584
|
// Lifecycle callbacks
|
|
737
|
-
|
|
585
|
+
loadingManager({
|
|
738
586
|
callbacks: {
|
|
739
587
|
onBeforeShow: 'if (shouldSkip) return false;',
|
|
740
588
|
onShow: 'console.log("loading shown")',
|
|
@@ -744,45 +592,274 @@ injectLoading({
|
|
|
744
592
|
})
|
|
745
593
|
|
|
746
594
|
// Manual control
|
|
747
|
-
|
|
595
|
+
loadingManager()
|
|
748
596
|
window.__LOADING_MANAGER__.show('Saving...')
|
|
749
597
|
window.__LOADING_MANAGER__.hide()
|
|
750
598
|
window.__LOADING_MANAGER__.toggle()
|
|
751
599
|
window.__LOADING_MANAGER__.disablePointerEvents()
|
|
752
600
|
```
|
|
753
601
|
|
|
602
|
+
## Common Utilities
|
|
603
|
+
|
|
604
|
+
Exported via `@meng-xi/vite-plugin/common`, reusable in custom plugins:
|
|
605
|
+
|
|
606
|
+
```typescript
|
|
607
|
+
import { deepMerge, formatDate, parseTemplate, toCamelCase, toPascalCase, stripJsonComments, generateRandomHash, Validator } from '@meng-xi/vite-plugin/common'
|
|
608
|
+
import { readFileContent, writeFileContent, fileExists, copySourceToTarget } from '@meng-xi/vite-plugin/common'
|
|
609
|
+
import { injectBeforeTag, injectHtmlByPriority } from '@meng-xi/vite-plugin/common'
|
|
610
|
+
import { makeCallback, containsScriptTag, validateIdentifierName } from '@meng-xi/vite-plugin/common'
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
| Function | Description |
|
|
614
|
+
| -------------------------- | ----------------------------------------------------------------------------- |
|
|
615
|
+
| `deepMerge()` | Deep merge objects (undefined skipped, arrays overwritten) |
|
|
616
|
+
| `formatDate()` | Format date with `{YYYY}`, `{MM}`, `{DD}` etc. placeholders |
|
|
617
|
+
| `parseTemplate()` | Parse template string, replace placeholders |
|
|
618
|
+
| `toCamelCase()` | Convert to camelCase |
|
|
619
|
+
| `toPascalCase()` | Convert to PascalCase |
|
|
620
|
+
| `stripJsonComments()` | Remove comments from JSON string |
|
|
621
|
+
| `generateRandomHash()` | Generate random hash string (1-64 characters) |
|
|
622
|
+
| `readFileContent()` | Async read file content |
|
|
623
|
+
| `writeFileContent()` | Async write file content |
|
|
624
|
+
| `fileExists()` | Async check if file exists |
|
|
625
|
+
| `copySourceToTarget()` | Copy files or directories with incremental copy and concurrency |
|
|
626
|
+
| `injectBeforeTag()` | Inject code before a specified closing HTML tag |
|
|
627
|
+
| `injectHtmlByPriority()` | Inject code into HTML by priority (`</head>` → `</body>` → `</html>`) |
|
|
628
|
+
| `makeCallback()` | Wrap callback function body as safe function expression (with try-catch) |
|
|
629
|
+
| `containsScriptTag()` | Detect if a string contains `<script>` tags |
|
|
630
|
+
| `validateIdentifierName()` | Validate string as a legal JavaScript identifier, prevent prototype pollution |
|
|
631
|
+
|
|
632
|
+
## Plugin Development Framework
|
|
633
|
+
|
|
634
|
+
### BasePlugin Core Concepts
|
|
635
|
+
|
|
636
|
+
`BasePlugin` is the base class for all plugins, providing complete lifecycle management and development conventions:
|
|
637
|
+
|
|
638
|
+
#### Lifecycle
|
|
639
|
+
|
|
640
|
+
| Phase | Method | Description |
|
|
641
|
+
| ----------------- | ------------------ | -------------------------------------------------------------- |
|
|
642
|
+
| Initialization | `constructor` | Merge options, initialize logger and validator |
|
|
643
|
+
| Config Resolution | `onConfigResolved` | Called when Vite config is resolved |
|
|
644
|
+
| Hook Registration | `addPluginHooks` | Register Vite plugin hooks |
|
|
645
|
+
| Destroy | `destroy` | Automatically called during `closeBundle` for resource cleanup |
|
|
646
|
+
|
|
647
|
+
#### Automatic Hook Composition
|
|
648
|
+
|
|
649
|
+
The `toPlugin()` method automatically composes the following hooks:
|
|
650
|
+
|
|
651
|
+
- **configResolved** - Base class `onConfigResolved` runs first, then subclass hook
|
|
652
|
+
- **closeBundle** - Subclass hook runs first, then base class `destroy`
|
|
653
|
+
|
|
654
|
+
> Subclasses don't need to manually register `closeBundle` hooks for cleanup — just override the `destroy()` method.
|
|
655
|
+
|
|
656
|
+
#### Required Methods
|
|
657
|
+
|
|
658
|
+
| Method | Description |
|
|
659
|
+
| ------------------------ | --------------------- |
|
|
660
|
+
| `getPluginName()` | Return plugin name |
|
|
661
|
+
| `addPluginHooks(plugin)` | Add Vite plugin hooks |
|
|
662
|
+
|
|
663
|
+
#### Optional Methods
|
|
664
|
+
|
|
665
|
+
| Method | Default Behavior | Description |
|
|
666
|
+
| -------------------------- | ----------------- | ------------------------------------------- |
|
|
667
|
+
| `getDefaultOptions()` | Returns `{}` | Provide plugin default options |
|
|
668
|
+
| `validateOptions()` | No validation | Validate configuration parameters |
|
|
669
|
+
| `getEnforce()` | `undefined` | Plugin execution order (`'pre'` / `'post'`) |
|
|
670
|
+
| `onConfigResolved(config)` | Store config | Config resolved callback |
|
|
671
|
+
| `destroy()` | Unregister logger | Cleanup logic when plugin is destroyed |
|
|
672
|
+
|
|
673
|
+
#### Built-in Properties
|
|
674
|
+
|
|
675
|
+
| Property | Type | Description |
|
|
676
|
+
| ------------ | ------------------------ | ----------------------------- |
|
|
677
|
+
| `options` | `Required<T>` | Merged complete configuration |
|
|
678
|
+
| `logger` | `PluginLogger` | Plugin logger |
|
|
679
|
+
| `validator` | `Validator<T>` | Configuration validator |
|
|
680
|
+
| `viteConfig` | `ResolvedConfig \| null` | Resolved Vite configuration |
|
|
681
|
+
|
|
682
|
+
#### Error Handling Strategy
|
|
683
|
+
|
|
684
|
+
Control error behavior via the `errorStrategy` configuration option:
|
|
685
|
+
|
|
686
|
+
- `'throw'` (default) - Log error and throw exception, halting the build
|
|
687
|
+
- `'log'` - Log error but don't throw, continue execution
|
|
688
|
+
- `'ignore'` - Log error but don't throw, continue execution
|
|
689
|
+
|
|
690
|
+
Wrap error-prone operations with `safeExecute` / `safeExecuteSync`:
|
|
691
|
+
|
|
692
|
+
```typescript
|
|
693
|
+
// Async safe execution
|
|
694
|
+
const result = await this.safeExecute(async () => {
|
|
695
|
+
return await someAsyncOperation()
|
|
696
|
+
}, 'Execute async operation')
|
|
697
|
+
|
|
698
|
+
// Sync safe execution
|
|
699
|
+
const value = this.safeExecuteSync(() => {
|
|
700
|
+
return someSyncOperation()
|
|
701
|
+
}, 'Execute sync operation')
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### createPluginFactory
|
|
705
|
+
|
|
706
|
+
Create plugin factory functions with optional normalizer support:
|
|
707
|
+
|
|
708
|
+
```typescript
|
|
709
|
+
// Basic usage
|
|
710
|
+
const myPlugin = createPluginFactory(MyPlugin)
|
|
711
|
+
|
|
712
|
+
// With normalizer (supports shorthand string config)
|
|
713
|
+
const myPlugin = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
714
|
+
|
|
715
|
+
// Usage with shorthand
|
|
716
|
+
myPlugin('./custom-path')
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
### Validator
|
|
720
|
+
|
|
721
|
+
Fluent configuration validator with chainable API:
|
|
722
|
+
|
|
723
|
+
```typescript
|
|
724
|
+
import { Validator } from '@meng-xi/vite-plugin/common'
|
|
725
|
+
|
|
726
|
+
const validator = new Validator(options)
|
|
727
|
+
validator
|
|
728
|
+
.field('sourceDir')
|
|
729
|
+
.required()
|
|
730
|
+
.string()
|
|
731
|
+
.field('targetDir')
|
|
732
|
+
.required()
|
|
733
|
+
.string()
|
|
734
|
+
.field('overwrite')
|
|
735
|
+
.boolean()
|
|
736
|
+
.default(true)
|
|
737
|
+
.field('port')
|
|
738
|
+
.number()
|
|
739
|
+
.field('list')
|
|
740
|
+
.array()
|
|
741
|
+
.field('config')
|
|
742
|
+
.object()
|
|
743
|
+
.field('name')
|
|
744
|
+
.custom(val => val.length > 0, 'name cannot be empty')
|
|
745
|
+
.validate()
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
| Method | Description |
|
|
749
|
+
| ------------ | --------------------------------------------------------------- |
|
|
750
|
+
| `field()` | Specify the field to validate |
|
|
751
|
+
| `required()` | Mark field as required |
|
|
752
|
+
| `string()` | Validate field value is a string type |
|
|
753
|
+
| `boolean()` | Validate field value is a boolean type |
|
|
754
|
+
| `number()` | Validate field value is a number type |
|
|
755
|
+
| `array()` | Validate field value is an array type |
|
|
756
|
+
| `object()` | Validate field value is an object type |
|
|
757
|
+
| `default()` | Set default value for field (only when value is undefined/null) |
|
|
758
|
+
| `custom()` | Validate field value with a custom function |
|
|
759
|
+
| `validate()` | Execute validation, throws error on failure |
|
|
760
|
+
|
|
761
|
+
### Logger
|
|
762
|
+
|
|
763
|
+
Global singleton log manager providing independent log control for each plugin:
|
|
764
|
+
|
|
765
|
+
```typescript
|
|
766
|
+
import { Logger } from '@meng-xi/vite-plugin/logger'
|
|
767
|
+
|
|
768
|
+
// Create logger (usually called automatically by BasePlugin)
|
|
769
|
+
Logger.create({ name: 'my-plugin', enabled: true })
|
|
770
|
+
|
|
771
|
+
// Unregister plugin log config (automatically called on plugin destroy)
|
|
772
|
+
Logger.unregister('my-plugin')
|
|
773
|
+
|
|
774
|
+
// Destroy singleton (for test scenarios)
|
|
775
|
+
Logger.destroy()
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
Log output format:
|
|
779
|
+
|
|
780
|
+
```
|
|
781
|
+
ℹ️ [@meng-xi/vite-plugin:my-plugin] Info message
|
|
782
|
+
✅ [@meng-xi/vite-plugin:my-plugin] Success message
|
|
783
|
+
⚠️ [@meng-xi/vite-plugin:my-plugin] Warning message
|
|
784
|
+
❌ [@meng-xi/vite-plugin:my-plugin] Error message
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
### Custom Plugin Example
|
|
788
|
+
|
|
789
|
+
```typescript
|
|
790
|
+
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin'
|
|
791
|
+
import type { BasePluginOptions, PluginWithInstance } from '@meng-xi/vite-plugin/factory'
|
|
792
|
+
import type { Plugin } from 'vite'
|
|
793
|
+
|
|
794
|
+
interface MyPluginOptions extends BasePluginOptions {
|
|
795
|
+
path: string
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
class MyPlugin extends BasePlugin<MyPluginOptions> {
|
|
799
|
+
protected getDefaultOptions() {
|
|
800
|
+
return { path: './default' }
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
protected validateOptions(): void {
|
|
804
|
+
this.validator.field('path').required().string().validate()
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
protected getPluginName(): string {
|
|
808
|
+
return 'my-plugin'
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
protected addPluginHooks(plugin: Plugin): void {
|
|
812
|
+
plugin.buildStart = () => {
|
|
813
|
+
this.logger.info(`Plugin started with path: ${this.options.path}`)
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
protected destroy(): void {
|
|
818
|
+
super.destroy()
|
|
819
|
+
// Custom cleanup logic, e.g. close connections, stop watchers
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// Basic usage
|
|
824
|
+
export const myPlugin = createPluginFactory(MyPlugin)
|
|
825
|
+
|
|
826
|
+
// With normalizer (supports shorthand string config)
|
|
827
|
+
export const myPluginWithNormalizer = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
828
|
+
// Usage with shorthand: myPluginWithNormalizer('./custom-path')
|
|
829
|
+
```
|
|
830
|
+
|
|
754
831
|
## Sub-path Exports
|
|
755
832
|
|
|
756
833
|
Support importing modules on demand to reduce bundle size:
|
|
757
834
|
|
|
758
835
|
```typescript
|
|
759
836
|
// Full import
|
|
760
|
-
import { buildProgress, copyFile,
|
|
837
|
+
import { buildProgress, copyFile, loadingManager, BasePlugin, Logger } from '@meng-xi/vite-plugin'
|
|
761
838
|
|
|
762
839
|
// Module-level import
|
|
763
840
|
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin/factory'
|
|
764
841
|
import { Logger } from '@meng-xi/vite-plugin/logger'
|
|
765
|
-
import { buildProgress, copyFile, generateRouter,
|
|
842
|
+
import { buildProgress, copyFile, generateRouter, loadingManager } from '@meng-xi/vite-plugin/plugins'
|
|
766
843
|
import { Validator, readFileContent, writeFileContent } from '@meng-xi/vite-plugin/common'
|
|
767
844
|
|
|
768
845
|
// Type imports (on-demand type definitions from sub-paths)
|
|
769
846
|
import type { PluginWithInstance, PluginFactory, BasePluginOptions } from '@meng-xi/vite-plugin/factory'
|
|
770
|
-
import type { BuildProgressOptions, GenerateVersionOptions,
|
|
847
|
+
import type { BuildProgressOptions, GenerateVersionOptions, VersionUpdateCheckerOptions, FaviconManagerOptions, LoadingManagerOptions, Icon } from '@meng-xi/vite-plugin/plugins'
|
|
771
848
|
import type { DateFormatOptions } from '@meng-xi/vite-plugin/common'
|
|
772
849
|
```
|
|
773
850
|
|
|
774
851
|
## Changelog
|
|
775
852
|
|
|
776
|
-
|
|
853
|
+
View [GitHub Releases](https://github.com/MengXi-Studio/vite-plugin/releases)
|
|
777
854
|
|
|
778
855
|
## Contributing
|
|
779
856
|
|
|
780
857
|
Contributions are welcome! Please follow these steps:
|
|
781
858
|
|
|
782
|
-
1. Fork
|
|
859
|
+
1. Fork this project
|
|
783
860
|
2. Create a feature branch: `git checkout -b feature/your-feature`
|
|
784
861
|
3. Commit changes: `git commit -m "feat: your feature description"`
|
|
785
|
-
4. Push
|
|
862
|
+
4. Push branch: `git push origin feature/your-feature`
|
|
786
863
|
5. Create a Pull Request
|
|
787
864
|
|
|
788
865
|
## License
|