@meng-xi/vite-plugin 0.1.2 → 0.1.3

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.
Files changed (53) hide show
  1. package/README-en.md +492 -190
  2. package/README.md +464 -163
  3. package/dist/common/compress/index.cjs +1 -0
  4. package/dist/common/compress/index.d.cts +23 -0
  5. package/dist/common/compress/index.d.mts +23 -0
  6. package/dist/common/compress/index.d.ts +23 -0
  7. package/dist/common/compress/index.mjs +1 -0
  8. package/dist/common/format/index.cjs +1 -1
  9. package/dist/common/format/index.d.cts +33 -1
  10. package/dist/common/format/index.d.mts +33 -1
  11. package/dist/common/format/index.d.ts +33 -1
  12. package/dist/common/format/index.mjs +1 -1
  13. package/dist/common/fs/index.cjs +1 -1
  14. package/dist/common/fs/index.d.cts +70 -2
  15. package/dist/common/fs/index.d.mts +70 -2
  16. package/dist/common/fs/index.d.ts +70 -2
  17. package/dist/common/fs/index.mjs +1 -1
  18. package/dist/common/index.cjs +1 -1
  19. package/dist/common/index.d.cts +4 -2
  20. package/dist/common/index.d.mts +4 -2
  21. package/dist/common/index.d.ts +4 -2
  22. package/dist/common/index.mjs +1 -1
  23. package/dist/common/path/index.cjs +1 -0
  24. package/dist/common/path/index.d.cts +22 -0
  25. package/dist/common/path/index.d.mts +22 -0
  26. package/dist/common/path/index.d.ts +22 -0
  27. package/dist/common/path/index.mjs +1 -0
  28. package/dist/index.cjs +1 -1
  29. package/dist/index.d.cts +5 -2
  30. package/dist/index.d.mts +5 -2
  31. package/dist/index.d.ts +5 -2
  32. package/dist/index.mjs +1 -1
  33. package/dist/plugins/bundleAnalyzer/index.cjs +235 -0
  34. package/dist/plugins/bundleAnalyzer/index.d.cts +215 -0
  35. package/dist/plugins/bundleAnalyzer/index.d.mts +215 -0
  36. package/dist/plugins/bundleAnalyzer/index.d.ts +215 -0
  37. package/dist/plugins/bundleAnalyzer/index.mjs +235 -0
  38. package/dist/plugins/compressAssets/index.cjs +1 -1
  39. package/dist/plugins/compressAssets/index.mjs +1 -1
  40. package/dist/plugins/generateRouter/index.cjs +4 -4
  41. package/dist/plugins/generateRouter/index.mjs +1 -1
  42. package/dist/plugins/generateVersion/index.cjs +1 -1
  43. package/dist/plugins/generateVersion/index.mjs +1 -1
  44. package/dist/plugins/htmlInject/index.cjs +7 -7
  45. package/dist/plugins/htmlInject/index.mjs +2 -2
  46. package/dist/plugins/index.cjs +1 -1
  47. package/dist/plugins/index.d.cts +1 -0
  48. package/dist/plugins/index.d.mts +1 -0
  49. package/dist/plugins/index.d.ts +1 -0
  50. package/dist/plugins/index.mjs +1 -1
  51. package/dist/plugins/loadingManager/index.cjs +1 -1
  52. package/dist/plugins/loadingManager/index.mjs +1 -1
  53. package/package.json +16 -1
package/README-en.md CHANGED
@@ -15,9 +15,11 @@
15
15
 
16
16
  ## Features
17
17
 
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
- - **Plugin Development Framework** - Exports core components like BasePlugin, Logger, Validator for building custom Vite plugins
18
+ - **Ready to Use** - Provides 10 practical plugins covering build progress display, build artifact analysis & compression, file copying, router generation, version management, version update checking, HTML injection,
19
+ icon injection, and global Loading state management
20
+ - **Plugin Development Framework** - Exports core components like BasePlugin, Logger, Validator for building custom Vite plugins that follow conventions
21
+ - **Common Utility Library** - Built-in Common module providing reusable utility functions for formatting, file system, compression, path handling, HTML injection, object operations, script generation, and parameter
22
+ validation
21
23
  - **Complete Lifecycle** - Supports initialization, config resolution, destroy lifecycle management with automatic hook composition
22
24
  - **Type Safe** - Complete TypeScript type definitions with configuration validators ensuring parameter correctness
23
25
  - **Flexible Configuration** - All plugins support detailed configuration to meet diverse scenario requirements
@@ -47,11 +49,12 @@ pnpm add @meng-xi/vite-plugin -D
47
49
 
48
50
  ```typescript
49
51
  import { defineConfig } from 'vite'
50
- import { buildProgress, compressAssets, copyFile, generateRouter, generateVersion, versionUpdateChecker, htmlInject, faviconManager, loadingManager } from '@meng-xi/vite-plugin'
52
+ import { buildProgress, bundleAnalyzer, compressAssets, copyFile, generateRouter, generateVersion, versionUpdateChecker, htmlInject, faviconManager, loadingManager } from '@meng-xi/vite-plugin'
51
53
 
52
54
  export default defineConfig({
53
55
  plugins: [
54
56
  buildProgress(),
57
+ bundleAnalyzer({ outputFormat: 'both', sizeThreshold: 200 }),
55
58
  compressAssets({ algorithm: 'gzip' }),
56
59
  copyFile({ sourceDir: 'src/assets', targetDir: 'dist/assets' }),
57
60
  generateRouter({ pagesJsonPath: 'src/pages.json', outputPath: 'src/router.config.ts' }),
@@ -80,17 +83,18 @@ console.log(routerPlugin.pluginInstance?.options)
80
83
 
81
84
  ## Built-in Plugins
82
85
 
83
- | Plugin | Description |
84
- | -------------------- | ----------------------------------------------------------------------------------------------------------------- |
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 |
87
- | copyFile | Copy files or directories after build, supports incremental copying |
88
- | generateRouter | Auto-generate router config from pages.json (uni-app) |
89
- | generateVersion | Auto-generate version numbers, supports file output and global variable injection |
90
- | versionUpdateChecker | Runtime version update checking with multiple prompt styles and custom callbacks |
91
- | htmlInject | HTML content injection with multiple positions, conditional injection, template variables, and security filtering |
92
- | faviconManager | Manage website favicon links injection into HTML files, supports string shorthand config |
93
- | loadingManager | Global Loading state management with request interception and white-screen Loading |
86
+ | Plugin | Description |
87
+ | -------------------- | -------------------------------------------------------------------------------------------------------------------- |
88
+ | buildProgress | Real-time build progress bar in terminal, supports bar / spinner / minimal |
89
+ | bundleAnalyzer | Build artifact size analysis with JSON/HTML reports, gzip calculation, threshold alerts, and build comparison |
90
+ | compressAssets | Compress build artifacts with gzip / brotli / both, concurrent compression and statistics report |
91
+ | copyFile | Copy files or directories after build, supports incremental copying |
92
+ | generateRouter | Auto-generate router config from pages.json (uni-app) |
93
+ | generateVersion | Auto-generate version numbers, supports file output and global variable injection |
94
+ | versionUpdateChecker | Runtime version update checking with multiple prompt styles and custom callbacks |
95
+ | htmlInject | HTML content injection with multiple positions, conditional injection, template variables, and security filtering |
96
+ | faviconManager | Manage website favicon links injection and file copying, supports string shorthand config |
97
+ | loadingManager | Global Loading state management with request interception, debounce, transition animations, and white-screen Loading |
94
98
 
95
99
  ---
96
100
 
@@ -141,6 +145,44 @@ buildProgress({
141
145
 
142
146
  ---
143
147
 
148
+ ### bundleAnalyzer
149
+
150
+ Automatically analyze build artifacts in the output directory after Vite build, generating size statistics, module rankings, file type distribution, and other key metrics, with JSON report and HTML visualization support.
151
+
152
+ **Core Features:**
153
+
154
+ - Scan build output directory, analyze chunks, modules, and asset files
155
+ - Calculate original size and gzip compressed size
156
+ - File type distribution statistics by extension
157
+ - Top N largest modules ranking
158
+ - Size threshold alerts (2x threshold marked as critical)
159
+ - Compare with previous build results and generate diff report
160
+ - HTML reports support treemap / sunburst / list visualization charts
161
+
162
+ | Option | Type | Default | Description |
163
+ | ------------------ | --------------------------------------- | ------------------- | --------------------------------------------------------- |
164
+ | outputFormat | `'json'` \| `'html'` \| `'both'` | `'json'` | Report output format |
165
+ | outputFile | `string` | `'bundle-analysis'` | Report output filename (without extension) |
166
+ | openAnalyzer | `boolean` | `false` | Whether to auto-open browser after generating HTML report |
167
+ | sizeThreshold | `number` | `100` | Size alert threshold (KB) |
168
+ | topModules | `number` | `20` | Top N largest modules ranking count |
169
+ | gzipSize | `boolean` | `true` | Whether to calculate gzip size |
170
+ | excludeNodeModules | `boolean` | `false` | Whether to exclude node_modules modules |
171
+ | excludePatterns | `string[]` | `[]` | File path patterns to exclude |
172
+ | includeExtensions | `string[]` | `[]` | File extensions to include, empty means all |
173
+ | compareWith | `string` \| `null` | `null` | Path to previous analysis report for comparison |
174
+ | defaultChartType | `'treemap'` \| `'sunburst'` \| `'list'` | `'treemap'` | Default chart type in HTML report |
175
+
176
+ ```typescript
177
+ bundleAnalyzer()
178
+ bundleAnalyzer({ outputFormat: 'both', openAnalyzer: true })
179
+ bundleAnalyzer({ sizeThreshold: 200, topModules: 30, gzipSize: true })
180
+ bundleAnalyzer({ compareWith: 'dist/bundle-analysis.json', defaultChartType: 'sunburst' })
181
+ bundleAnalyzer({ excludeNodeModules: true, includeExtensions: ['.js', '.css'] })
182
+ ```
183
+
184
+ ---
185
+
144
186
  ### compressAssets
145
187
 
146
188
  Automatically compress files in the output directory after Vite build, supporting both gzip and brotli compression algorithms.
@@ -268,7 +310,7 @@ generateVersion({ outputType: 'both', outputFile: 'build-info.json', defineName:
268
310
 
269
311
  ### versionUpdateChecker
270
312
 
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.
313
+ Periodically check for version changes at runtime, prompting users to refresh when a new version is detected. Typically used with the `generateVersion` plugin.
272
314
 
273
315
  **How it works:**
274
316
 
@@ -276,26 +318,26 @@ Periodically check for version changes at runtime and prompt users to refresh wh
276
318
  2. `versionUpdateChecker` periodically requests the version file at runtime and compares it with the current version
277
319
  3. When a version mismatch is detected, a prompt is shown to guide the user to refresh
278
320
 
279
- | Option | Type | Default | Description |
280
- | ----------------------- | ------------------------------------ | -------------------------------------------------------------- | ------------------------------------------------------------ |
281
- | versionSource | `'define'` \| `'file'` \| `'auto'` | `'auto'` | Current version source |
282
- | defineName | `string` | `'__APP_VERSION__'` | Global variable name in define mode |
283
- | checkUrl | `string` | `'/version.json'` | URL path for version check file |
284
- | checkInterval | `number` | `300000` | Check interval in milliseconds (default 5 minutes) |
285
- | checkOnVisibilityChange | `boolean` | `true` | Whether to check immediately on page visibility change |
286
- | enableInDev | `boolean` | `false` | Whether to enable in development mode |
287
- | promptStyle | `'modal'` \| `'banner'` \| `'toast'` | `'modal'` | Update prompt UI style |
288
- | promptMessage | `string` | `'A new version is available. Refresh now to get the latest?'` | Prompt message text |
289
- | refreshButtonText | `string` | `'Refresh'` | Refresh button text |
290
- | dismissButtonText | `string` | `'Later'` | Dismiss button text |
291
- | customPromptTemplate | `string` | - | Custom HTML template for the prompt UI |
292
- | customStyle | `string` | - | Custom CSS style string |
293
- | onUpdateAvailable | `string` | - | Callback when new version is found (function body string) |
294
- | onRefresh | `string` | - | Callback when user chooses to refresh (function body string) |
295
- | onDismiss | `string` | - | Callback when user chooses to dismiss (function body string) |
321
+ | Option | Type | Default | Description |
322
+ | ----------------------- | ------------------------------------ | -------------------------------------------- | ------------------------------------------------------------ |
323
+ | versionSource | `'define'` \| `'file'` \| `'auto'` | `'auto'` | Current version source |
324
+ | defineName | `string` | `'__APP_VERSION__'` | Global variable name in define mode |
325
+ | checkUrl | `string` | `'/version.json'` | URL path for version check file |
326
+ | checkInterval | `number` | `300000` | Check interval (ms, default 5 minutes) |
327
+ | checkOnVisibilityChange | `boolean` | `true` | Whether to check immediately on page visibility change |
328
+ | enableInDev | `boolean` | `false` | Whether to enable in development mode |
329
+ | promptStyle | `'modal'` \| `'banner'` \| `'toast'` | `'modal'` | Update prompt UI style |
330
+ | promptMessage | `string` | `'A new version is available. Refresh now?'` | Prompt message text |
331
+ | refreshButtonText | `string` | `'Refresh Now'` | Refresh button text |
332
+ | dismissButtonText | `string` | `'Later'` | Dismiss button text |
333
+ | customPromptTemplate | `string` | - | Custom HTML template for the prompt UI |
334
+ | customStyle | `string` | - | Custom CSS style string |
335
+ | onUpdateAvailable | `string` | - | Callback when new version is found (function body string) |
336
+ | onRefresh | `string` | - | Callback when user chooses to refresh (function body string) |
337
+ | onDismiss | `string` | - | Callback when user chooses to dismiss (function body string) |
296
338
 
297
339
  > `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}}`,
298
- > `{{newVersion}}`, `{{refreshButton}}`, `{{dismissButton}}` placeholders. Callbacks are provided as function body strings with available variables: `currentVersion`, `newVersion`.
340
+ > `{{newVersion}}`, `{{refreshButton}}`, `{{dismissButton}}` placeholders. Callbacks are provided as function body strings, available variables: `currentVersion`, `newVersion`.
299
341
 
300
342
  ```typescript
301
343
  generateVersion({ outputType: 'both' })
@@ -304,7 +346,7 @@ versionUpdateChecker({ versionSource: 'file' })
304
346
  versionUpdateChecker({ checkInterval: 60000, promptStyle: 'banner' })
305
347
  versionUpdateChecker({ promptStyle: 'toast' })
306
348
  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");' })
349
+ versionUpdateChecker({ onUpdateAvailable: 'console.log("New version:", newVersion); return true;', onRefresh: 'console.log("User chose refresh");', onDismiss: 'console.log("User chose dismiss");' })
308
350
  versionUpdateChecker({ enableInDev: true })
309
351
  ```
310
352
 
@@ -312,57 +354,56 @@ versionUpdateChecker({ enableInDev: true })
312
354
 
313
355
  ### htmlInject
314
356
 
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.
316
-
317
- **Injection positions:**
318
-
319
- | Position | Description |
320
- | ------------------ | ------------------------------------------ |
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 |
325
- | `before-selector` | Inject before the selector-matched content |
326
- | `after-selector` | Inject after the selector-matched content |
327
- | `replace-selector` | Replace the selector-matched content |
357
+ Inject custom content into HTML files, supporting multiple positions, selector targeting, conditional injection, template variable replacement, and security filtering.
328
358
 
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 |
359
+ | Option | Type | Default | Description |
360
+ | ------------ | ------------------------ | -------------- | ------------------------------------------- |
361
+ | targetFile | `string` | `'index.html'` | Target HTML file path or filename |
362
+ | rules | `InjectRule[]` | - | Injection rules list (required) |
363
+ | security | `SecurityConfig` | - | Security filtering config |
364
+ | templateVars | `Record<string, string>` | `{}` | Global template variable mapping |
365
+ | logInjection | `boolean` | `true` | Whether to output injection logs to console |
336
366
 
337
367
  **InjectRule**
338
368
 
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 |
369
+ | Property | Type | Default | Description |
370
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ---------- | --------------------------------------------------------- |
371
+ | id | `string` | - | Unique rule identifier |
372
+ | content | `string` | - | Content to inject |
373
+ | position | `'head-start'` \| `'head-end'` \| `'body-start'` \| `'body-end'` \| `'before-selector'` \| `'after-selector'` \| `'replace-selector'` | - | Injection position |
374
+ | selector | `string` | - | Selector string (required for selector-related positions) |
375
+ | selectorMatch | `'string'` \| `'regex'` | `'string'` | Selector match mode |
376
+ | priority | `number` | `100` | Rule priority, lower values execute first |
377
+ | condition | `InjectCondition` | - | Injection condition |
378
+ | templateVars | `Record<string, string>` | - | Rule-level template variables (override global) |
379
+ | allowScriptInjection | `boolean` | `false` | Whether to allow injecting scripts and dangerous content |
380
+
381
+ **InjectCondition**
382
+
383
+ | Property | Type | Default | Description |
384
+ | -------- | ------------------------------------------ | ------- | -------------------------------------- |
385
+ | type | `'env'` \| `'file-contains'` \| `'custom'` | - | Condition type |
386
+ | value | `string` \| `(...args: any[]) => boolean` | - | Condition value |
387
+ | negate | `boolean` | `false` | Whether to negate the condition result |
350
388
 
351
389
  **SecurityConfig**
352
390
 
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 |
391
+ | Property | Type | Default | Description |
392
+ | ------------------------ | ---------- | ------- | ----------------------------------------------------- |
393
+ | blockDangerousTags | `boolean` | `true` | Whether to block dangerous tags (script, etc.) |
394
+ | blockDangerousAttributes | `boolean` | `true` | Whether to block dangerous attributes (onclick, etc.) |
395
+ | allowedTags | `string[]` | - | Whitelist of allowed tags |
396
+ | blockedTags | `string[]` | - | Custom blocked tags list |
397
+ | blockedAttributes | `string[]` | - | Custom blocked attributes list |
360
398
 
361
399
  ```typescript
362
400
  htmlInject({
363
401
  rules: [
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 }
402
+ { id: 'meta-description', content: '<meta name="description" content="My App">', position: 'head-end' },
403
+ { id: 'analytics', content: '<script src="https://analytics.example.com/track.js"></script>', position: 'body-end', allowScriptInjection: true },
404
+ { id: 'env-var', content: '<script>window.__ENV__ = "{{env}}"</script>', position: 'head-end', templateVars: { env: 'production' }, allowScriptInjection: true },
405
+ { id: 'before-app', content: '<div>Before App</div>', position: 'before-selector', selector: '<div id="app">' },
406
+ { id: 'prod-only', content: '<meta name="robots" content="noindex">', position: 'head-end', condition: { type: 'env', value: 'PRODUCTION' } }
366
407
  ]
367
408
  })
368
409
  ```
@@ -371,15 +412,15 @@ htmlInject({
371
412
 
372
413
  ### faviconManager
373
414
 
374
- Manage website favicon links injection into HTML files, supporting string shorthand config and icon file copying.
415
+ Manage website favicon links injection into HTML files, supports icon file copying, supports string shorthand config.
375
416
 
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) |
417
+ | Option | Type | Default | Description |
418
+ | ----------- | ------------- | ------- | ------------------------------------------------------ |
419
+ | base | `string` | `'/'` | Base path for icon files |
420
+ | url | `string` | - | Complete icon URL (overrides base + favicon.ico) |
421
+ | link | `string` | - | Custom complete link tag HTML (highest priority) |
422
+ | icons | `Icon[]` | - | Custom icon array, supports multiple formats and sizes |
423
+ | copyOptions | `CopyOptions` | - | Icon file copying config |
383
424
 
384
425
  **Icon**
385
426
 
@@ -387,12 +428,21 @@ Manage website favicon links injection into HTML files, supporting string shorth
387
428
  | -------- | -------- | ------------------ |
388
429
  | rel | `string` | Icon relation type |
389
430
  | href | `string` | Icon URL |
390
- | sizes | `string` | Icon size |
431
+ | sizes | `string` | Icon sizes |
391
432
  | type | `string` | Icon MIME type |
392
433
 
434
+ **CopyOptions**
435
+
436
+ | Property | Type | Default | Description |
437
+ | --------- | --------- | ------- | ----------------------------------- |
438
+ | sourceDir | `string` | - | Icon source directory (required) |
439
+ | targetDir | `string` | - | Icon target directory (required) |
440
+ | overwrite | `boolean` | `true` | Whether to overwrite existing files |
441
+ | recursive | `boolean` | `true` | Whether to copy recursively |
442
+
393
443
  ```typescript
394
- faviconManager()
395
444
  faviconManager('/assets')
445
+ faviconManager({ base: '/assets', url: '/assets/favicon.ico' })
396
446
  faviconManager({
397
447
  base: '/assets',
398
448
  icons: [
@@ -400,49 +450,109 @@ faviconManager({
400
450
  { rel: 'icon', href: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' }
401
451
  ]
402
452
  })
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' } })
453
+ faviconManager({
454
+ base: '/assets',
455
+ copyOptions: { sourceDir: 'src/assets/icons', targetDir: 'dist/assets/icons' }
456
+ })
405
457
  ```
406
458
 
407
459
  ---
408
460
 
409
461
  ### loadingManager
410
462
 
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 |
463
+ Global Loading state management with request interception, debounce, transition animations, and white-screen Loading.
464
+
465
+ | Option | Type | Default | Description |
466
+ | -------------- | ------------------ | ----------------------- | ------------------------------------------------------------- |
467
+ | position | `LoadingPosition` | `'center'` | Loading display position |
468
+ | defaultText | `string` | `'Loading...'` | Default display text |
469
+ | spinnerType | `SpinnerType` | `'spinner'` | Spinner icon type |
470
+ | style | `LoadingStyle` | - | Custom style config |
471
+ | transition | `TransitionConfig` | - | Transition animation config |
472
+ | minDisplayTime | `MinDisplayTime` | - | Minimum display time config |
473
+ | delayShow | `DelayShow` | - | Delay show config |
474
+ | debounceHide | `DebounceHide` | - | Debounce hide config |
475
+ | autoBind | `AutoBindMode` | `'none'` | Auto-bind request interception mode |
476
+ | requestFilter | `RequestFilter` | - | Request filter config |
477
+ | globalName | `string` | `'__LOADING_MANAGER__'` | Injected global variable name |
478
+ | customTemplate | `string` | - | Custom Loading HTML template |
479
+ | defaultVisible | `boolean` | `false` | Loading DOM initial visibility (white-screen Loading) |
480
+ | autoHideOn | `AutoHideOn` | `'DOMContentLoaded'` | Auto-hide timing (only effective when defaultVisible is true) |
481
+ | callbacks | `LoadingCallbacks` | - | Lifecycle callbacks |
482
+
483
+ **LoadingPosition**: `'center'` | `'top'` | `'bottom'`
484
+
485
+ **SpinnerType**: `'spinner'` | `'dots'` | `'pulse'` | `'bar'`
486
+
487
+ **AutoBindMode**: `'fetch'` | `'xhr'` | `'all'` | `'none'`
488
+
489
+ **AutoHideOn**: `'DOMContentLoaded'` | `'load'` | `'manual'`
430
490
 
431
491
  **LoadingStyle**
432
492
 
433
493
  | Property | Type | Default | Description |
434
494
  | ------------------ | --------- | ------------------------- | ---------------------------------------- |
435
495
  | overlayColor | `string` | `'rgba(255,255,255,0.7)'` | Overlay background color |
436
- | spinnerColor | `string` | `'#4361ee'` | Spinner icon color |
437
- | spinnerSize | `string` | `'40px'` | Spinner icon size |
496
+ | spinnerColor | `string` | `'#4361ee'` | Loading icon color |
497
+ | spinnerSize | `string` | `'40px'` | Loading icon size |
438
498
  | textColor | `string` | `'#333'` | Text color |
439
499
  | textSize | `string` | `'14px'` | Text size |
440
- | zIndex | `number` | `9999` | z-index value |
441
- | pointerEvents | `boolean` | `true` | Whether to enable overlay pointer events |
442
- | backdropBlur | `boolean` | `false` | Whether to enable background blur |
443
- | backdropBlurAmount | `number` | `4` | Background blur amount (px) |
444
500
  | customClass | `string` | - | Custom CSS class name |
445
501
  | customStyle | `string` | - | Custom inline style string |
502
+ | zIndex | `number` | `9999` | Overlay z-index |
503
+ | pointerEvents | `boolean` | `true` | Whether to enable overlay pointer events |
504
+ | backdropBlur | `boolean` | `false` | Whether to enable backdrop blur |
505
+ | backdropBlurAmount | `number` | `4` | Backdrop blur amount (px) |
506
+
507
+ **TransitionConfig**
508
+
509
+ | Property | Type | Default | Description |
510
+ | -------- | --------- | ------------ | ------------------------------ |
511
+ | enabled | `boolean` | `true` | Whether to enable transition |
512
+ | duration | `number` | `200` | Transition duration (ms) |
513
+ | easing | `string` | `'ease-out'` | CSS transition easing function |
514
+
515
+ **MinDisplayTime**
516
+
517
+ | Property | Type | Default | Description |
518
+ | -------- | --------- | ------- | -------------------------------------- |
519
+ | enabled | `boolean` | `true` | Whether to enable minimum display time |
520
+ | duration | `number` | `300` | Minimum display time (ms) |
521
+
522
+ **DelayShow**
523
+
524
+ | Property | Type | Default | Description |
525
+ | -------- | --------- | ------- | --------------------------------------------------------------- |
526
+ | enabled | `boolean` | `true` | Whether to enable delay show |
527
+ | duration | `number` | `200` | Delay time (ms), requests completed within this time won't show |
528
+
529
+ **DebounceHide**
530
+
531
+ | Property | Type | Default | Description |
532
+ | -------- | --------- | ------- | ------------------------------- |
533
+ | enabled | `boolean` | `false` | Whether to enable debounce hide |
534
+ | duration | `number` | `100` | Debounce wait time (ms) |
535
+
536
+ **RequestFilter**
537
+
538
+ | Property | Type | Description |
539
+ | ------------------ | ---------- | ------------------------------ |
540
+ | excludeUrls | `RegExp[]` | URL regex patterns to exclude |
541
+ | includeUrls | `RegExp[]` | URL regex patterns to include |
542
+ | excludeMethods | `string[]` | HTTP methods to exclude |
543
+ | excludeUrlPrefixes | `string[]` | URL string prefixes to exclude |
544
+
545
+ **LoadingCallbacks**
546
+
547
+ | Property | Type | Description |
548
+ | ------------ | -------- | -------------------------------------------------------- |
549
+ | onBeforeShow | `string` | Before show callback (`return false` to prevent showing) |
550
+ | onShow | `string` | After show callback |
551
+ | onBeforeHide | `string` | Before hide callback (`return false` to prevent hiding) |
552
+ | onHide | `string` | After hide callback |
553
+ | onDestroy | `string` | On destroy callback |
554
+
555
+ > Callbacks are provided as function body strings because they need to be injected into client-side code. `customTemplate` must contain an element with the `data-loading-text` attribute for text display.
446
556
 
447
557
  **Runtime API:**
448
558
 
@@ -450,28 +560,27 @@ Global Loading state management with request interception and white-screen Loadi
450
560
  window.__LOADING_MANAGER__.show('Loading...')
451
561
  window.__LOADING_MANAGER__.hide()
452
562
  window.__LOADING_MANAGER__.forceHide()
453
- window.__LOADING_MANAGER__.toggle()
563
+ window.__LOADING_MANAGER__.toggle('Loading...')
454
564
  window.__LOADING_MANAGER__.updateText('Processing...')
455
565
  window.__LOADING_MANAGER__.isVisible()
456
566
  window.__LOADING_MANAGER__.getPendingCount()
457
- window.__LOADING_MANAGER__.destroy()
458
567
  window.__LOADING_MANAGER__.enablePointerEvents()
459
568
  window.__LOADING_MANAGER__.disablePointerEvents()
460
- window.__LOADING_MANAGER__.togglePointerEvents()
461
- window.__LOADING_MANAGER__.isPointerEventsEnabled()
569
+ window.__LOADING_MANAGER__.destroy()
462
570
  ```
463
571
 
464
572
  ```typescript
465
573
  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 } })
574
+ loadingManager({ defaultVisible: true, autoHideOn: 'DOMContentLoaded' })
575
+ loadingManager({ position: 'top', defaultText: 'Please wait...', spinnerType: 'dots' })
576
+ loadingManager({ autoBind: 'fetch', requestFilter: { excludeUrls: [/\/api\/health/] } })
577
+ loadingManager({
578
+ style: { overlayColor: 'rgba(0,0,0,0.5)', spinnerColor: '#ff6b6b', backdropBlur: true, backdropBlurAmount: 6 }
579
+ })
470
580
  loadingManager({ transition: { enabled: true, duration: 300, easing: 'cubic-bezier(0.4,0,0.2,1)' } })
471
581
  loadingManager({ debounceHide: { enabled: true, duration: 100 } })
472
- loadingManager({ callbacks: { onShow: 'console.log("loading shown")', onBeforeShow: 'return true', onHide: 'console.log("loading hidden")' } })
582
+ loadingManager({ callbacks: { onShow: 'console.log("shown")', onBeforeShow: 'return true' } })
473
583
  loadingManager({ customTemplate: '<div class="my-loader"><span data-loading-text></span></div>' })
474
- loadingManager({ defaultVisible: true, autoHideOn: 'DOMContentLoaded' })
475
584
  loadingManager({ defaultVisible: true, autoHideOn: 'manual' })
476
585
  ```
477
586
 
@@ -479,32 +588,41 @@ loadingManager({ defaultVisible: true, autoHideOn: 'manual' })
479
588
 
480
589
  ## Plugin Development Framework
481
590
 
591
+ This package not only provides built-in plugins but also exports a complete plugin development framework to help quickly build custom Vite plugins that follow conventions.
592
+
482
593
  ### BasePlugin
483
594
 
484
- The base class for all built-in plugins, providing core functionality such as configuration management, logging, lifecycle management, and safe execution.
595
+ The base class for all built-in plugins, providing core capabilities such as configuration management, logging, error handling, and lifecycle management.
485
596
 
486
597
  ```typescript
487
- import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin/factory'
598
+ import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin'
488
599
  import type { Plugin } from 'vite'
489
600
 
490
601
  interface MyPluginOptions {
491
- enabled?: boolean
492
- message?: string
602
+ prefix?: string
493
603
  }
494
604
 
495
605
  class MyPlugin extends BasePlugin<MyPluginOptions> {
496
606
  protected getPluginName() {
497
607
  return 'my-plugin'
498
608
  }
609
+
499
610
  protected getDefaultOptions() {
500
- return { enabled: true, message: 'Hello' }
611
+ return { prefix: '[app]' }
501
612
  }
613
+
502
614
  protected validateOptions() {
503
- this.validator.field('message').string().validate()
615
+ this.validator.field('prefix').string().notEmpty().validate()
504
616
  }
617
+
505
618
  protected addPluginHooks(plugin: Plugin) {
506
- plugin.buildStart = () => {
507
- this.logger.info(this.options.message)
619
+ plugin.writeBundle = {
620
+ order: 'post',
621
+ handler: async () => {
622
+ await this.safeExecute(async () => {
623
+ this.logger.info('Plugin executing...')
624
+ }, 'Execute custom logic')
625
+ }
508
626
  }
509
627
  }
510
628
  }
@@ -512,86 +630,270 @@ class MyPlugin extends BasePlugin<MyPluginOptions> {
512
630
  export const myPlugin = createPluginFactory(MyPlugin)
513
631
  ```
514
632
 
515
- ### Core Components
633
+ **BasePlugin Core Methods:**
634
+
635
+ | Method | Description |
636
+ | ------------------- | -------------------------------------------------------------- |
637
+ | `getDefaultOptions` | Returns plugin default config, can be overridden by subclasses |
638
+ | `validateOptions` | Validates user config, can be overridden by subclasses |
639
+ | `getPluginName` | Returns plugin name (abstract method, must be implemented) |
640
+ | `getEnforce` | Returns plugin execution timing (pre / post / undefined) |
641
+ | `addPluginHooks` | Registers Vite hooks (abstract method, must be implemented) |
642
+ | `onConfigResolved` | Config resolution complete callback |
643
+ | `destroy` | Plugin destroy callback |
644
+ | `safeExecute` | Safely execute async function with automatic error handling |
645
+ | `safeExecuteSync` | Safely execute sync function with automatic error handling |
646
+ | `handleError` | Handle errors based on errorStrategy |
647
+ | `toPlugin` | Convert to Vite plugin object |
648
+
649
+ **BasePluginOptions Base Config:**
650
+
651
+ | Option | Type | Default | Description |
652
+ | ------------- | ---------------------------------- | --------- | ----------------------- |
653
+ | enabled | `boolean` | `true` | Whether to enable |
654
+ | verbose | `boolean` | `true` | Whether to log |
655
+ | errorStrategy | `'throw'` \| `'log'` \| `'ignore'` | `'throw'` | Error handling strategy |
656
+
657
+ ### createPluginFactory
658
+
659
+ Creates a plugin factory function that converts a BasePlugin subclass into a directly usable Vite plugin function.
660
+
661
+ ```typescript
662
+ import { createPluginFactory } from '@meng-xi/vite-plugin'
663
+
664
+ const myPlugin = createPluginFactory(MyPlugin)
665
+
666
+ // Supports options normalizer (e.g. string shorthand config)
667
+ const myPluginWithNormalizer = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { prefix: opt } : opt))
668
+ ```
669
+
670
+ ### Logger
671
+
672
+ Global singleton log manager, providing independent log proxies for each plugin.
673
+
674
+ ```typescript
675
+ import { Logger } from '@meng-xi/vite-plugin/logger'
676
+
677
+ const logger = Logger.create({ name: 'my-plugin', enabled: true })
678
+ logger.info('Info log')
679
+ logger.success('Success log')
680
+ logger.warn('Warning log')
681
+ logger.error('Error log')
682
+ ```
683
+
684
+ ### Validator
516
685
 
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 |
686
+ Chain-style configuration validator for validating plugin configuration parameters.
524
687
 
525
- ### Common Utilities
688
+ ```typescript
689
+ import { Validator } from '@meng-xi/vite-plugin/common/validation'
526
690
 
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. |
691
+ const validator = new Validator(myOptions)
692
+ validator.field('port').number().minValue(1).maxValue(65535).field('host').string().notEmpty().field('mode').enum(['development', 'production']).validate()
693
+ ```
535
694
 
536
695
  ---
537
696
 
538
- ## Sub-path Exports
697
+ ## Common Utility Modules
539
698
 
540
- Support importing modules on demand to reduce bundle size:
699
+ Built-in general-purpose utility function library, organized by functional modules, supporting on-demand sub-path imports.
700
+
701
+ ### Import Methods
541
702
 
542
703
  ```typescript
543
- import { buildProgress, copyFile, htmlInject, loadingManager, BasePlugin, Logger } from '@meng-xi/vite-plugin'
704
+ // Import all utilities
705
+ import { formatFileSize, scanDirectory } from '@meng-xi/vite-plugin/common'
706
+
707
+ // Import by module
708
+ import { formatFileSize } from '@meng-xi/vite-plugin/common/format'
709
+ import { scanDirectory, writeJsonReport } from '@meng-xi/vite-plugin/common/fs'
710
+ import { calculateGzipSize } from '@meng-xi/vite-plugin/common/compress'
711
+ import { isNodeModule } from '@meng-xi/vite-plugin/common/path'
712
+ ```
544
713
 
545
- import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin/factory'
546
- import { Logger } from '@meng-xi/vite-plugin/logger'
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'
549
-
550
- import type { PluginWithInstance, PluginFactory, BasePluginOptions } from '@meng-xi/vite-plugin/factory'
551
- import type { BuildProgressOptions, CompressAssetsOptions, GenerateVersionOptions, VersionUpdateCheckerOptions, HtmlInjectOptions, FaviconManagerOptions, LoadingManagerOptions } from '@meng-xi/vite-plugin/plugins'
552
- import type { DateFormatOptions } from '@meng-xi/vite-plugin/common/format'
553
- import type { HtmlInjectResult, DualInjectResult } from '@meng-xi/vite-plugin/common/html'
554
- import type { CopyOptions, CopyResult } from '@meng-xi/vite-plugin/common/fs'
714
+ ### Module List
715
+
716
+ | Sub-path | Description |
717
+ | ---------------------------------------- | ----------------------- |
718
+ | `@meng-xi/vite-plugin/common/compress` | Compression utilities |
719
+ | `@meng-xi/vite-plugin/common/format` | Formatting utilities |
720
+ | `@meng-xi/vite-plugin/common/fs` | File system utilities |
721
+ | `@meng-xi/vite-plugin/common/html` | HTML injection utils |
722
+ | `@meng-xi/vite-plugin/common/object` | Object operation utils |
723
+ | `@meng-xi/vite-plugin/common/path` | Path handling utils |
724
+ | `@meng-xi/vite-plugin/common/script` | Script generation utils |
725
+ | `@meng-xi/vite-plugin/common/validation` | Validation utilities |
726
+
727
+ ### compress — Compression
728
+
729
+ | Function | Description |
730
+ | ------------------- | ---------------------------------------------------- |
731
+ | `calculateGzipSize` | Calculate gzip compressed size of given data (bytes) |
732
+
733
+ ```typescript
734
+ import { calculateGzipSize } from '@meng-xi/vite-plugin/common/compress'
735
+
736
+ const size = await calculateGzipSize(Buffer.from('hello world'))
555
737
  ```
556
738
 
557
- **All available sub-paths:**
739
+ ### format — Formatting
740
+
741
+ | Function | Description |
742
+ | --------------------- | -------------------------------------------------- |
743
+ | `formatFileSize` | Format bytes to human-readable file size string |
744
+ | `getExtension` | Get file extension (lowercase) |
745
+ | `formatDate` | Format date |
746
+ | `parseTemplate` | Parse template string, replace placeholders |
747
+ | `toCamelCase` | Convert string to camelCase |
748
+ | `toPascalCase` | Convert string to PascalCase |
749
+ | `padNumber` | Pad number with leading zeros |
750
+ | `generateRandomHash` | Generate random hash string |
751
+ | `getDateFormatParams` | Get date formatting parameters |
752
+ | `stripJsonComments` | Remove comments from JSON string |
753
+ | `escapeHtmlAttr` | Escape special characters in HTML attribute values |
558
754
 
755
+ ```typescript
756
+ import { formatFileSize, formatDate, toCamelCase } from '@meng-xi/vite-plugin/common/format'
757
+
758
+ formatFileSize(2461726) // '2.35MB'
759
+ formatDate(new Date(), '{YYYY}-{MM}-{DD}') // '2026-05-31'
760
+ toCamelCase('pages/user/profile') // 'pagesUserProfile'
559
761
  ```
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
762
+
763
+ ### fs — File System
764
+
765
+ | Function | Description |
766
+ | -------------------- | --------------------------------------------- |
767
+ | `scanDirectory` | Recursively scan directory, collect file info |
768
+ | `writeJsonReport` | Write data to JSON file |
769
+ | `writeFileContent` | Write file content |
770
+ | `readFileContent` | Read file content |
771
+ | `fileExists` | Check if file exists |
772
+ | `checkSourceExists` | Check if source file exists |
773
+ | `ensureTargetDir` | Create target directory |
774
+ | `copySourceToTarget` | Execute file copy operation |
775
+ | `runWithConcurrency` | Batch execution with concurrency limit |
776
+
777
+ ```typescript
778
+ import { scanDirectory, writeJsonReport } from '@meng-xi/vite-plugin/common/fs'
779
+
780
+ const files = await scanDirectory('dist', {
781
+ includeExtensions: ['.js', '.css'],
782
+ excludePatterns: ['node_modules'],
783
+ filter: (filePath, ext, size) => size > 1024
784
+ })
785
+
786
+ await writeJsonReport('dist/report.json', { timestamp: Date.now(), files })
580
787
  ```
581
788
 
582
- ## Changelog
789
+ ### html — HTML Injection
583
790
 
584
- View [GitHub Releases](https://github.com/MengXi-Studio/vite-plugin/releases)
791
+ | Function | Description |
792
+ | ----------------------------- | ---------------------------------------- |
793
+ | `injectBeforeTag` | Inject code before specified closing tag |
794
+ | `injectHtmlByPriority` | Inject code into HTML by priority |
795
+ | `injectBeforeTagWithFallback` | Inject code with fallback strategy |
796
+ | `injectHeadAndBody` | Dual-zone HTML injection (head + body) |
585
797
 
586
- ## Contributing
798
+ ```typescript
799
+ import { injectBeforeTag, injectHeadAndBody } from '@meng-xi/vite-plugin/common/html'
587
800
 
588
- Contributions are welcome! Please follow these steps:
801
+ const result = injectBeforeTag(html, '</head>', '<style>body{margin:0}</style>')
802
+ const dual = injectHeadAndBody(html, '<style>...</style>', '<script>...</script>')
803
+ ```
589
804
 
590
- 1. Fork this project
591
- 2. Create a feature branch: `git checkout -b feature/your-feature`
592
- 3. Commit changes: `git commit -m "feat: your feature description"`
593
- 4. Push branch: `git push origin feature/your-feature`
594
- 5. Create a Pull Request
805
+ ### object Object Operations
806
+
807
+ | Function | Description |
808
+ | ----------- | ------------------ |
809
+ | `deepMerge` | Deep merge objects |
810
+
811
+ ```typescript
812
+ import { deepMerge } from '@meng-xi/vite-plugin/common/object'
813
+
814
+ deepMerge({ a: { b: 1 } }, { a: { c: 2 } }) // { a: { b: 1, c: 2 } }
815
+ ```
816
+
817
+ ### path — Path Handling
818
+
819
+ | Function | Description |
820
+ | -------------- | --------------------------------------- |
821
+ | `isNodeModule` | Check if module ID is from node_modules |
822
+
823
+ ```typescript
824
+ import { isNodeModule } from '@meng-xi/vite-plugin/common/path'
825
+
826
+ isNodeModule('node_modules/lodash/index.js') // true
827
+ isNodeModule('src/utils/helper.ts') // false
828
+ ```
829
+
830
+ ### script — Script Generation
831
+
832
+ | Function | Description |
833
+ | ------------------------ | -------------------------------------------------------------- |
834
+ | `makeCallback` | Wrap callback function body string as safe function expression |
835
+ | `containsScriptTag` | Detect if string contains `<script>` tag |
836
+ | `validateIdentifierName` | Validate if string is a valid JS identifier |
837
+
838
+ ```typescript
839
+ import { makeCallback, validateIdentifierName } from '@meng-xi/vite-plugin/common/script'
840
+
841
+ makeCallback('console.log("done")')
842
+ // 'function() { try { console.log("done") } catch(e) { console.error("[callback] error:", e); } }'
843
+
844
+ validateIdentifierName('__APP_VERSION__') // passes
845
+ ```
846
+
847
+ ### validation — Validation
848
+
849
+ | Function | Description |
850
+ | ---------------------------- | ----------------------------------- |
851
+ | `Validator` | Chain-style configuration validator |
852
+ | `validateGlobalName` | Validate global variable name |
853
+ | `validateNoScriptInTemplate` | Validate no script tag in template |
854
+ | `validateCallbackFields` | Validate callback function fields |
855
+ | `validateNonNegativeNumber` | Validate non-negative number |
856
+ | `validateNestedDuration` | Validate nested duration config |
857
+ | `validateEnumValue` | Validate enum value |
858
+
859
+ ```typescript
860
+ import { Validator } from '@meng-xi/vite-plugin/common/validation'
861
+
862
+ const validator = new Validator(options)
863
+ validator.field('port').number().minValue(1).maxValue(65535).validate()
864
+ ```
865
+
866
+ ---
867
+
868
+ ## Sub-path Exports
869
+
870
+ | Sub-path | Description |
871
+ | ----------------------------------------------------- | ------------------------------------ |
872
+ | `@meng-xi/vite-plugin` | Main entry (all plugins + framework) |
873
+ | `@meng-xi/vite-plugin/factory` | Plugin development framework |
874
+ | `@meng-xi/vite-plugin/logger` | Log manager |
875
+ | `@meng-xi/vite-plugin/plugins` | All plugins |
876
+ | `@meng-xi/vite-plugin/common` | All utility functions |
877
+ | `@meng-xi/vite-plugin/common/compress` | Compression utilities |
878
+ | `@meng-xi/vite-plugin/common/format` | Formatting utilities |
879
+ | `@meng-xi/vite-plugin/common/fs` | File system utilities |
880
+ | `@meng-xi/vite-plugin/common/html` | HTML injection utilities |
881
+ | `@meng-xi/vite-plugin/common/object` | Object operation utilities |
882
+ | `@meng-xi/vite-plugin/common/path` | Path handling utilities |
883
+ | `@meng-xi/vite-plugin/common/script` | Script generation utilities |
884
+ | `@meng-xi/vite-plugin/common/validation` | Validation utilities |
885
+ | `@meng-xi/vite-plugin/plugins/build-progress` | buildProgress plugin |
886
+ | `@meng-xi/vite-plugin/plugins/bundle-analyzer` | bundleAnalyzer plugin |
887
+ | `@meng-xi/vite-plugin/plugins/compress-assets` | compressAssets plugin |
888
+ | `@meng-xi/vite-plugin/plugins/copy-file` | copyFile plugin |
889
+ | `@meng-xi/vite-plugin/plugins/favicon-manager` | faviconManager plugin |
890
+ | `@meng-xi/vite-plugin/plugins/generate-router` | generateRouter plugin |
891
+ | `@meng-xi/vite-plugin/plugins/generate-version` | generateVersion plugin |
892
+ | `@meng-xi/vite-plugin/plugins/html-inject` | htmlInject plugin |
893
+ | `@meng-xi/vite-plugin/plugins/loading-manager` | loadingManager plugin |
894
+ | `@meng-xi/vite-plugin/plugins/version-update-checker` | versionUpdateChecker plugin |
895
+
896
+ ---
595
897
 
596
898
  ## License
597
899