@meng-xi/vite-plugin 0.1.0 → 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.
Files changed (110) hide show
  1. package/README-en.md +264 -533
  2. package/README.md +253 -522
  3. package/dist/common/format/index.cjs +1 -0
  4. package/dist/common/format/index.d.cts +156 -0
  5. package/dist/common/format/index.d.mts +156 -0
  6. package/dist/common/format/index.d.ts +156 -0
  7. package/dist/common/format/index.mjs +1 -0
  8. package/dist/common/fs/index.cjs +1 -0
  9. package/dist/common/fs/index.d.cts +150 -0
  10. package/dist/common/fs/index.d.mts +150 -0
  11. package/dist/common/fs/index.d.ts +150 -0
  12. package/dist/common/fs/index.mjs +1 -0
  13. package/dist/common/html/index.cjs +2 -0
  14. package/dist/common/html/index.d.cts +109 -0
  15. package/dist/common/html/index.d.mts +109 -0
  16. package/dist/common/html/index.d.ts +109 -0
  17. package/dist/common/html/index.mjs +2 -0
  18. package/dist/common/index.cjs +1 -1
  19. package/dist/common/index.d.cts +7 -417
  20. package/dist/common/index.d.mts +7 -417
  21. package/dist/common/index.d.ts +7 -417
  22. package/dist/common/index.mjs +1 -1
  23. package/dist/common/object/index.cjs +1 -0
  24. package/dist/common/object/index.d.cts +30 -0
  25. package/dist/common/object/index.d.mts +30 -0
  26. package/dist/common/object/index.d.ts +30 -0
  27. package/dist/common/object/index.mjs +1 -0
  28. package/dist/common/script/index.cjs +1 -0
  29. package/dist/common/script/index.d.cts +54 -0
  30. package/dist/common/script/index.d.mts +54 -0
  31. package/dist/common/script/index.d.ts +54 -0
  32. package/dist/common/script/index.mjs +1 -0
  33. package/dist/common/validation/index.cjs +1 -0
  34. package/dist/common/validation/index.d.cts +93 -0
  35. package/dist/common/validation/index.d.mts +93 -0
  36. package/dist/common/validation/index.d.ts +93 -0
  37. package/dist/common/validation/index.mjs +1 -0
  38. package/dist/factory/index.cjs +1 -1
  39. package/dist/factory/index.d.cts +1 -1
  40. package/dist/factory/index.d.mts +1 -1
  41. package/dist/factory/index.d.ts +1 -1
  42. package/dist/factory/index.mjs +1 -1
  43. package/dist/index.cjs +1 -1
  44. package/dist/index.d.cts +16 -3
  45. package/dist/index.d.mts +16 -3
  46. package/dist/index.d.ts +16 -3
  47. package/dist/index.mjs +1 -1
  48. package/dist/plugins/buildProgress/index.cjs +2 -0
  49. package/dist/plugins/buildProgress/index.d.cts +187 -0
  50. package/dist/plugins/buildProgress/index.d.mts +187 -0
  51. package/dist/plugins/buildProgress/index.d.ts +187 -0
  52. package/dist/plugins/buildProgress/index.mjs +2 -0
  53. package/dist/plugins/compressAssets/index.cjs +1 -0
  54. package/dist/plugins/compressAssets/index.d.cts +132 -0
  55. package/dist/plugins/compressAssets/index.d.mts +132 -0
  56. package/dist/plugins/compressAssets/index.d.ts +132 -0
  57. package/dist/plugins/compressAssets/index.mjs +1 -0
  58. package/dist/plugins/copyFile/index.cjs +1 -0
  59. package/dist/plugins/copyFile/index.d.cts +78 -0
  60. package/dist/plugins/copyFile/index.d.mts +78 -0
  61. package/dist/plugins/copyFile/index.d.ts +78 -0
  62. package/dist/plugins/copyFile/index.mjs +1 -0
  63. package/dist/plugins/faviconManager/index.cjs +1 -0
  64. package/dist/plugins/faviconManager/index.d.cts +143 -0
  65. package/dist/plugins/faviconManager/index.d.mts +143 -0
  66. package/dist/plugins/faviconManager/index.d.ts +143 -0
  67. package/dist/plugins/faviconManager/index.mjs +1 -0
  68. package/dist/plugins/generateRouter/index.cjs +35 -0
  69. package/dist/plugins/generateRouter/index.d.cts +215 -0
  70. package/dist/plugins/generateRouter/index.d.mts +215 -0
  71. package/dist/plugins/generateRouter/index.d.ts +215 -0
  72. package/dist/plugins/generateRouter/index.mjs +35 -0
  73. package/dist/plugins/generateVersion/index.cjs +1 -0
  74. package/dist/plugins/generateVersion/index.d.cts +184 -0
  75. package/dist/plugins/generateVersion/index.d.mts +184 -0
  76. package/dist/plugins/generateVersion/index.d.ts +184 -0
  77. package/dist/plugins/generateVersion/index.mjs +1 -0
  78. package/dist/plugins/htmlInject/index.cjs +7 -0
  79. package/dist/plugins/htmlInject/index.d.cts +278 -0
  80. package/dist/plugins/htmlInject/index.d.mts +278 -0
  81. package/dist/plugins/htmlInject/index.d.ts +278 -0
  82. package/dist/plugins/htmlInject/index.mjs +7 -0
  83. package/dist/plugins/index.cjs +1 -1
  84. package/dist/plugins/index.d.cts +11 -1714
  85. package/dist/plugins/index.d.mts +11 -1714
  86. package/dist/plugins/index.d.ts +11 -1714
  87. package/dist/plugins/index.mjs +1 -1
  88. package/dist/plugins/loadingManager/index.cjs +487 -0
  89. package/dist/plugins/loadingManager/index.d.cts +769 -0
  90. package/dist/plugins/loadingManager/index.d.mts +769 -0
  91. package/dist/plugins/loadingManager/index.d.ts +769 -0
  92. package/dist/plugins/loadingManager/index.mjs +487 -0
  93. package/dist/plugins/versionUpdateChecker/index.cjs +185 -0
  94. package/dist/plugins/versionUpdateChecker/index.d.cts +200 -0
  95. package/dist/plugins/versionUpdateChecker/index.d.mts +200 -0
  96. package/dist/plugins/versionUpdateChecker/index.d.ts +200 -0
  97. package/dist/plugins/versionUpdateChecker/index.mjs +185 -0
  98. package/dist/shared/vite-plugin.Bcg6RW2N.cjs +3 -0
  99. package/dist/shared/{vite-plugin.CiHfwMiN.d.ts → vite-plugin.DRRlWY8P.d.cts} +50 -0
  100. package/dist/shared/{vite-plugin.CiHfwMiN.d.cts → vite-plugin.DRRlWY8P.d.mts} +50 -0
  101. package/dist/shared/{vite-plugin.CiHfwMiN.d.mts → vite-plugin.DRRlWY8P.d.ts} +50 -0
  102. package/dist/shared/{vite-plugin.B88RyRN8.mjs → vite-plugin.DcExl6jd.mjs} +2 -2
  103. package/package.json +80 -3
  104. package/dist/shared/vite-plugin.CawoITTT.cjs +0 -1
  105. package/dist/shared/vite-plugin.D6Law9Ke.mjs +0 -706
  106. package/dist/shared/vite-plugin.D8L9KzuW.cjs +0 -706
  107. package/dist/shared/vite-plugin.DFjf9wFM.mjs +0 -2
  108. package/dist/shared/vite-plugin.DSb6XzBn.mjs +0 -1
  109. package/dist/shared/vite-plugin.IGZeStMa.cjs +0 -3
  110. package/dist/shared/vite-plugin.Tab4qcIM.cjs +0 -2
@@ -0,0 +1,278 @@
1
+ import { BasePluginOptions, PluginFactory } from '../../factory/index.mjs';
2
+ import 'vite';
3
+ import '../../shared/vite-plugin.CLr0ttuO.mjs';
4
+ import '../../shared/vite-plugin.DRRlWY8P.mjs';
5
+
6
+ /**
7
+ * 选择器匹配模式
8
+ *
9
+ * @description
10
+ * - 'string': 使用字符串精确匹配(默认)
11
+ * - 'regex': 使用正则表达式匹配,支持更灵活的模式
12
+ */
13
+ type SelectorMatch = 'string' | 'regex';
14
+ /**
15
+ * HTML 内容注入位置
16
+ *
17
+ * @description
18
+ * - 'head-start': 注入到 `<head>` 标签开始之后
19
+ * - 'head-end': 注入到 `</head>` 标签之前
20
+ * - 'body-start': 注入到 `<body>` 标签开始之后
21
+ * - 'body-end': 注入到 `</body>` 标签之前
22
+ * - 'before-selector': 注入到指定选择器之前
23
+ * - 'after-selector': 注入到指定选择器之后
24
+ * - 'replace-selector': 替换指定选择器匹配的内容
25
+ */
26
+ type InjectPosition = 'head-start' | 'head-end' | 'body-start' | 'body-end' | 'before-selector' | 'after-selector' | 'replace-selector';
27
+ /**
28
+ * 条件类型
29
+ *
30
+ * @description
31
+ * - 'env': 基于环境变量判断
32
+ * - 'file-contains': 基于 HTML 文件内容判断
33
+ * - 'custom': 基于自定义函数判断
34
+ */
35
+ type ConditionType = 'env' | 'file-contains' | 'custom';
36
+ /**
37
+ * 注入条件接口
38
+ *
39
+ * @interface InjectCondition
40
+ * @description 定义内容注入的触发条件,支持环境变量检测、文件内容检测和自定义函数
41
+ */
42
+ interface InjectCondition {
43
+ /**
44
+ * 条件类型
45
+ */
46
+ type: ConditionType;
47
+ /**
48
+ * 条件值
49
+ *
50
+ * @description
51
+ * - 当 type 为 'env' 时,为环境变量名(字符串)
52
+ * - 当 type 为 'file-contains' 时,为要搜索的字符串(字符串)
53
+ * - 当 type 为 'custom' 时,为返回布尔值的判断函数
54
+ */
55
+ value: string | ((...args: any[]) => boolean);
56
+ /**
57
+ * 是否对条件结果取反
58
+ *
59
+ * @default false
60
+ */
61
+ negate?: boolean;
62
+ }
63
+ /**
64
+ * 注入规则接口
65
+ *
66
+ * @interface InjectRule
67
+ * @description 定义单条 HTML 内容注入规则,包括注入内容、位置、条件、优先级等
68
+ */
69
+ interface InjectRule {
70
+ /**
71
+ * 规则唯一标识符,用于日志记录和调试
72
+ */
73
+ id?: string;
74
+ /**
75
+ * 要注入的 HTML 内容
76
+ *
77
+ * @example '<meta name="description" content="My App">'
78
+ */
79
+ content: string;
80
+ /**
81
+ * 注入位置
82
+ */
83
+ position: InjectPosition;
84
+ /**
85
+ * 选择器字符串,当 position 为 selector 相关位置时必填
86
+ *
87
+ * @description 当 selectorMatch 为 'string' 时,使用字符串精确匹配;
88
+ * 当 selectorMatch 为 'regex' 时,使用正则表达式匹配
89
+ *
90
+ * @example '<div id="app">'
91
+ */
92
+ selector?: string;
93
+ /**
94
+ * 选择器匹配模式
95
+ *
96
+ * @default 'string'
97
+ */
98
+ selectorMatch?: SelectorMatch;
99
+ /**
100
+ * 规则优先级,数值越小优先级越高,越先执行
101
+ *
102
+ * @default 100
103
+ */
104
+ priority?: number;
105
+ /**
106
+ * 注入条件,满足条件时才执行注入
107
+ */
108
+ condition?: InjectCondition;
109
+ /**
110
+ * 规则级模板变量,会覆盖全局模板变量
111
+ *
112
+ * @description 使用 `{{变量名}}` 语法在 content 中引用变量
113
+ *
114
+ * @example { greeting: 'Hello', name: 'World' }
115
+ */
116
+ templateVars?: Record<string, string>;
117
+ /**
118
+ * 是否允许注入脚本等危险内容
119
+ *
120
+ * @default false
121
+ * @remarks 启用此选项将跳过安全检查,请确保注入内容来源可信
122
+ */
123
+ allowScriptInjection?: boolean;
124
+ }
125
+ /**
126
+ * 安全配置接口
127
+ *
128
+ * @interface SecurityConfig
129
+ * @description 控制 HTML 注入内容的安全过滤行为,防止 XSS 攻击
130
+ */
131
+ interface SecurityConfig {
132
+ /**
133
+ * 是否阻止危险标签(script、iframe、object 等)
134
+ *
135
+ * @default true
136
+ */
137
+ blockDangerousTags?: boolean;
138
+ /**
139
+ * 是否阻止危险属性(onclick、onload 等事件处理器)
140
+ *
141
+ * @default true
142
+ */
143
+ blockDangerousAttributes?: boolean;
144
+ /**
145
+ * 允许通过的标签白名单,白名单中的标签不会被阻止
146
+ *
147
+ * @example ['iframe', 'object']
148
+ */
149
+ allowedTags?: string[];
150
+ /**
151
+ * 自定义阻止标签列表,覆盖默认阻止列表
152
+ *
153
+ * @example ['div', 'span']
154
+ */
155
+ blockedTags?: string[];
156
+ /**
157
+ * 自定义阻止属性列表,覆盖默认阻止列表
158
+ *
159
+ * @example ['data-custom', 'data-track']
160
+ */
161
+ blockedAttributes?: string[];
162
+ }
163
+ /**
164
+ * 注入日志条目接口
165
+ *
166
+ * @interface InjectionLogEntry
167
+ * @description 记录单条注入规则的执行结果,用于调试和问题排查
168
+ */
169
+ interface InjectionLogEntry {
170
+ /**
171
+ * 规则标识符
172
+ */
173
+ ruleId: string;
174
+ /**
175
+ * 注入位置
176
+ */
177
+ position: InjectPosition;
178
+ /**
179
+ * 使用的选择器
180
+ */
181
+ selector?: string;
182
+ /**
183
+ * 是否注入成功
184
+ */
185
+ injected: boolean;
186
+ /**
187
+ * 注入失败原因
188
+ */
189
+ reason?: string;
190
+ /**
191
+ * 日志时间戳
192
+ */
193
+ timestamp: number;
194
+ }
195
+ /**
196
+ * HTML 注入插件的配置选项接口
197
+ *
198
+ * @interface HtmlInjectOptions
199
+ * @extends {BasePluginOptions}
200
+ */
201
+ interface HtmlInjectOptions extends BasePluginOptions {
202
+ /**
203
+ * 目标 HTML 文件路径或文件名
204
+ *
205
+ * @default 'index.html'
206
+ * @description 支持相对路径和文件名匹配,默认匹配所有 index.html 文件
207
+ *
208
+ * @example 'index.html'
209
+ * @example 'src/views/home.html'
210
+ */
211
+ targetFile?: string;
212
+ /**
213
+ * 注入规则数组
214
+ *
215
+ * @description 定义要注入的 HTML 内容及其注入位置和条件,规则按 priority 升序执行
216
+ */
217
+ rules: InjectRule[];
218
+ /**
219
+ * 安全配置
220
+ *
221
+ * @description 控制注入内容的安全过滤行为,防止 XSS 攻击
222
+ */
223
+ security?: SecurityConfig;
224
+ /**
225
+ * 全局模板变量,可被规则级 templateVars 覆盖
226
+ *
227
+ * @description 使用 `{{变量名}}` 语法在 content 中引用变量
228
+ *
229
+ * @example { appName: 'My App', version: '1.0.0' }
230
+ */
231
+ templateVars?: Record<string, string>;
232
+ /**
233
+ * 是否在控制台输出注入日志
234
+ *
235
+ * @default true
236
+ */
237
+ logInjection?: boolean;
238
+ }
239
+
240
+ /**
241
+ * HTML 内容注入插件工厂函数
242
+ *
243
+ * @description 创建 htmlInject Vite 插件实例,用于在构建过程中将自定义 HTML 内容注入到目标 HTML 文件中
244
+ *
245
+ * @param {HtmlInjectOptions} options - 插件配置选项
246
+ * @returns {Plugin} Vite 插件实例
247
+ *
248
+ * @example
249
+ * ```ts
250
+ * import { htmlInject } from '@mengxi-studio/vite-plugin'
251
+ *
252
+ * export default defineConfig({
253
+ * plugins: [
254
+ * htmlInject({
255
+ * rules: [
256
+ * {
257
+ * id: 'meta-description',
258
+ * content: '<meta name="description" content="{{appName}}">',
259
+ * position: 'head-end',
260
+ * templateVars: { appName: 'My Application' }
261
+ * },
262
+ * {
263
+ * id: 'analytics',
264
+ * content: '<script src="/analytics.js"></script>',
265
+ * position: 'body-end',
266
+ * condition: { type: 'env', value: 'PRODUCTION' },
267
+ * allowScriptInjection: true
268
+ * }
269
+ * ]
270
+ * })
271
+ * ]
272
+ * })
273
+ * ```
274
+ */
275
+ declare const htmlInject: PluginFactory<HtmlInjectOptions, HtmlInjectOptions>;
276
+
277
+ export { htmlInject };
278
+ export type { ConditionType, HtmlInjectOptions, InjectCondition, InjectPosition, InjectRule, InjectionLogEntry, SecurityConfig, SelectorMatch };
@@ -0,0 +1,278 @@
1
+ import { BasePluginOptions, PluginFactory } from '../../factory/index.js';
2
+ import 'vite';
3
+ import '../../shared/vite-plugin.CLr0ttuO.js';
4
+ import '../../shared/vite-plugin.DRRlWY8P.js';
5
+
6
+ /**
7
+ * 选择器匹配模式
8
+ *
9
+ * @description
10
+ * - 'string': 使用字符串精确匹配(默认)
11
+ * - 'regex': 使用正则表达式匹配,支持更灵活的模式
12
+ */
13
+ type SelectorMatch = 'string' | 'regex';
14
+ /**
15
+ * HTML 内容注入位置
16
+ *
17
+ * @description
18
+ * - 'head-start': 注入到 `<head>` 标签开始之后
19
+ * - 'head-end': 注入到 `</head>` 标签之前
20
+ * - 'body-start': 注入到 `<body>` 标签开始之后
21
+ * - 'body-end': 注入到 `</body>` 标签之前
22
+ * - 'before-selector': 注入到指定选择器之前
23
+ * - 'after-selector': 注入到指定选择器之后
24
+ * - 'replace-selector': 替换指定选择器匹配的内容
25
+ */
26
+ type InjectPosition = 'head-start' | 'head-end' | 'body-start' | 'body-end' | 'before-selector' | 'after-selector' | 'replace-selector';
27
+ /**
28
+ * 条件类型
29
+ *
30
+ * @description
31
+ * - 'env': 基于环境变量判断
32
+ * - 'file-contains': 基于 HTML 文件内容判断
33
+ * - 'custom': 基于自定义函数判断
34
+ */
35
+ type ConditionType = 'env' | 'file-contains' | 'custom';
36
+ /**
37
+ * 注入条件接口
38
+ *
39
+ * @interface InjectCondition
40
+ * @description 定义内容注入的触发条件,支持环境变量检测、文件内容检测和自定义函数
41
+ */
42
+ interface InjectCondition {
43
+ /**
44
+ * 条件类型
45
+ */
46
+ type: ConditionType;
47
+ /**
48
+ * 条件值
49
+ *
50
+ * @description
51
+ * - 当 type 为 'env' 时,为环境变量名(字符串)
52
+ * - 当 type 为 'file-contains' 时,为要搜索的字符串(字符串)
53
+ * - 当 type 为 'custom' 时,为返回布尔值的判断函数
54
+ */
55
+ value: string | ((...args: any[]) => boolean);
56
+ /**
57
+ * 是否对条件结果取反
58
+ *
59
+ * @default false
60
+ */
61
+ negate?: boolean;
62
+ }
63
+ /**
64
+ * 注入规则接口
65
+ *
66
+ * @interface InjectRule
67
+ * @description 定义单条 HTML 内容注入规则,包括注入内容、位置、条件、优先级等
68
+ */
69
+ interface InjectRule {
70
+ /**
71
+ * 规则唯一标识符,用于日志记录和调试
72
+ */
73
+ id?: string;
74
+ /**
75
+ * 要注入的 HTML 内容
76
+ *
77
+ * @example '<meta name="description" content="My App">'
78
+ */
79
+ content: string;
80
+ /**
81
+ * 注入位置
82
+ */
83
+ position: InjectPosition;
84
+ /**
85
+ * 选择器字符串,当 position 为 selector 相关位置时必填
86
+ *
87
+ * @description 当 selectorMatch 为 'string' 时,使用字符串精确匹配;
88
+ * 当 selectorMatch 为 'regex' 时,使用正则表达式匹配
89
+ *
90
+ * @example '<div id="app">'
91
+ */
92
+ selector?: string;
93
+ /**
94
+ * 选择器匹配模式
95
+ *
96
+ * @default 'string'
97
+ */
98
+ selectorMatch?: SelectorMatch;
99
+ /**
100
+ * 规则优先级,数值越小优先级越高,越先执行
101
+ *
102
+ * @default 100
103
+ */
104
+ priority?: number;
105
+ /**
106
+ * 注入条件,满足条件时才执行注入
107
+ */
108
+ condition?: InjectCondition;
109
+ /**
110
+ * 规则级模板变量,会覆盖全局模板变量
111
+ *
112
+ * @description 使用 `{{变量名}}` 语法在 content 中引用变量
113
+ *
114
+ * @example { greeting: 'Hello', name: 'World' }
115
+ */
116
+ templateVars?: Record<string, string>;
117
+ /**
118
+ * 是否允许注入脚本等危险内容
119
+ *
120
+ * @default false
121
+ * @remarks 启用此选项将跳过安全检查,请确保注入内容来源可信
122
+ */
123
+ allowScriptInjection?: boolean;
124
+ }
125
+ /**
126
+ * 安全配置接口
127
+ *
128
+ * @interface SecurityConfig
129
+ * @description 控制 HTML 注入内容的安全过滤行为,防止 XSS 攻击
130
+ */
131
+ interface SecurityConfig {
132
+ /**
133
+ * 是否阻止危险标签(script、iframe、object 等)
134
+ *
135
+ * @default true
136
+ */
137
+ blockDangerousTags?: boolean;
138
+ /**
139
+ * 是否阻止危险属性(onclick、onload 等事件处理器)
140
+ *
141
+ * @default true
142
+ */
143
+ blockDangerousAttributes?: boolean;
144
+ /**
145
+ * 允许通过的标签白名单,白名单中的标签不会被阻止
146
+ *
147
+ * @example ['iframe', 'object']
148
+ */
149
+ allowedTags?: string[];
150
+ /**
151
+ * 自定义阻止标签列表,覆盖默认阻止列表
152
+ *
153
+ * @example ['div', 'span']
154
+ */
155
+ blockedTags?: string[];
156
+ /**
157
+ * 自定义阻止属性列表,覆盖默认阻止列表
158
+ *
159
+ * @example ['data-custom', 'data-track']
160
+ */
161
+ blockedAttributes?: string[];
162
+ }
163
+ /**
164
+ * 注入日志条目接口
165
+ *
166
+ * @interface InjectionLogEntry
167
+ * @description 记录单条注入规则的执行结果,用于调试和问题排查
168
+ */
169
+ interface InjectionLogEntry {
170
+ /**
171
+ * 规则标识符
172
+ */
173
+ ruleId: string;
174
+ /**
175
+ * 注入位置
176
+ */
177
+ position: InjectPosition;
178
+ /**
179
+ * 使用的选择器
180
+ */
181
+ selector?: string;
182
+ /**
183
+ * 是否注入成功
184
+ */
185
+ injected: boolean;
186
+ /**
187
+ * 注入失败原因
188
+ */
189
+ reason?: string;
190
+ /**
191
+ * 日志时间戳
192
+ */
193
+ timestamp: number;
194
+ }
195
+ /**
196
+ * HTML 注入插件的配置选项接口
197
+ *
198
+ * @interface HtmlInjectOptions
199
+ * @extends {BasePluginOptions}
200
+ */
201
+ interface HtmlInjectOptions extends BasePluginOptions {
202
+ /**
203
+ * 目标 HTML 文件路径或文件名
204
+ *
205
+ * @default 'index.html'
206
+ * @description 支持相对路径和文件名匹配,默认匹配所有 index.html 文件
207
+ *
208
+ * @example 'index.html'
209
+ * @example 'src/views/home.html'
210
+ */
211
+ targetFile?: string;
212
+ /**
213
+ * 注入规则数组
214
+ *
215
+ * @description 定义要注入的 HTML 内容及其注入位置和条件,规则按 priority 升序执行
216
+ */
217
+ rules: InjectRule[];
218
+ /**
219
+ * 安全配置
220
+ *
221
+ * @description 控制注入内容的安全过滤行为,防止 XSS 攻击
222
+ */
223
+ security?: SecurityConfig;
224
+ /**
225
+ * 全局模板变量,可被规则级 templateVars 覆盖
226
+ *
227
+ * @description 使用 `{{变量名}}` 语法在 content 中引用变量
228
+ *
229
+ * @example { appName: 'My App', version: '1.0.0' }
230
+ */
231
+ templateVars?: Record<string, string>;
232
+ /**
233
+ * 是否在控制台输出注入日志
234
+ *
235
+ * @default true
236
+ */
237
+ logInjection?: boolean;
238
+ }
239
+
240
+ /**
241
+ * HTML 内容注入插件工厂函数
242
+ *
243
+ * @description 创建 htmlInject Vite 插件实例,用于在构建过程中将自定义 HTML 内容注入到目标 HTML 文件中
244
+ *
245
+ * @param {HtmlInjectOptions} options - 插件配置选项
246
+ * @returns {Plugin} Vite 插件实例
247
+ *
248
+ * @example
249
+ * ```ts
250
+ * import { htmlInject } from '@mengxi-studio/vite-plugin'
251
+ *
252
+ * export default defineConfig({
253
+ * plugins: [
254
+ * htmlInject({
255
+ * rules: [
256
+ * {
257
+ * id: 'meta-description',
258
+ * content: '<meta name="description" content="{{appName}}">',
259
+ * position: 'head-end',
260
+ * templateVars: { appName: 'My Application' }
261
+ * },
262
+ * {
263
+ * id: 'analytics',
264
+ * content: '<script src="/analytics.js"></script>',
265
+ * position: 'body-end',
266
+ * condition: { type: 'env', value: 'PRODUCTION' },
267
+ * allowScriptInjection: true
268
+ * }
269
+ * ]
270
+ * })
271
+ * ]
272
+ * })
273
+ * ```
274
+ */
275
+ declare const htmlInject: PluginFactory<HtmlInjectOptions, HtmlInjectOptions>;
276
+
277
+ export { htmlInject };
278
+ export type { ConditionType, HtmlInjectOptions, InjectCondition, InjectPosition, InjectRule, InjectionLogEntry, SecurityConfig, SelectorMatch };
@@ -0,0 +1,7 @@
1
+ import{createPluginFactory as p,BasePlugin as g}from"../../factory/index.mjs";import{containsScriptTag as B}from"../../common/script/index.mjs";import h from"node:path";import"../../logger/index.mjs";import"../../common/object/index.mjs";import"../../shared/vite-plugin.DcExl6jd.mjs";const m=["script","iframe","object","embed","applet","form","input","textarea","select","button"],C=["onclick","ondblclick","onmouseover","onmouseout","onmousemove","onmousedown","onmouseup","onkeydown","onkeyup","onkeypress","onload","onerror","onfocus","onblur","onsubmit","onchange","oninput","oncontextmenu","ondrag","ondrop","onanimationend","ontransitionend"];function w(u){if(!u.rules||!Array.isArray(u.rules))throw new Error("rules \u5FC5\u987B\u662F\u975E\u7A7A\u6570\u7EC4");if(u.rules.length===0)throw new Error("rules \u4E0D\u80FD\u4E3A\u7A7A\u6570\u7EC4");for(let e=0;e<u.rules.length;e++)y(u.rules[e],e)}function y(u,e){if(!u.content||typeof u.content!="string")throw new Error(`rules[${e}].content \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);if(!u.position||typeof u.position!="string")throw new Error(`rules[${e}].position \u5FC5\u987B\u662F\u6709\u6548\u7684\u6CE8\u5165\u4F4D\u7F6E`);const t=["head-start","head-end","body-start","body-end","before-selector","after-selector","replace-selector"];if(!t.includes(u.position))throw new Error(`rules[${e}].position \u5FC5\u987B\u662F ${t.join(", ")} \u4E4B\u4E00`);if(u.position.includes("selector")&&!u.selector)throw new Error(`rules[${e}].position \u4E3A "${u.position}" \u65F6\uFF0Cselector \u4E3A\u5FC5\u586B\u9879`);if(u.priority!==void 0&&(typeof u.priority!="number"||u.priority<0))throw new Error(`rules[${e}].priority \u5FC5\u987B\u662F\u975E\u8D1F\u6570`);u.condition&&j(u.condition,e)}function j(u,e){if(!u)return;const t=["env","file-contains","custom"];if(!t.includes(u.type))throw new Error(`rules[${e}].condition.type \u5FC5\u987B\u662F ${t.join(", ")} \u4E4B\u4E00`);if(u.type==="custom"&&typeof u.value!="function")throw new Error(`rules[${e}].condition.type \u4E3A "custom" \u65F6\uFF0Cvalue \u5FC5\u987B\u662F\u51FD\u6570`);if(u.type!=="custom"&&typeof u.value!="string")throw new Error(`rules[${e}].condition.type \u4E3A "${u.type}" \u65F6\uFF0Cvalue \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`)}function $(u){if(u){if(u.blockedTags&&!Array.isArray(u.blockedTags))throw new Error("security.blockedTags \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4");if(u.allowedTags&&!Array.isArray(u.allowedTags))throw new Error("security.allowedTags \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4");if(u.blockedAttributes&&!Array.isArray(u.blockedAttributes))throw new Error("security.blockedAttributes \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4")}}function b(u){w(u),$(u.security)}function A(u,e,t,r){const i=t?.blockDangerousTags!==!1,n=t?.blockDangerousAttributes!==!1,o=t?.blockedTags||m,a=t?.allowedTags,l=t?.blockedAttributes||C;let s=u;if(i){const d=a?o.filter(c=>!a.includes(c)):o;if(B(u))if(e.allowScriptInjection)r?.warn(`[\u5B89\u5168\u8B66\u544A] \u89C4\u5219 "${e.id||"unnamed"}" \u5DF2\u542F\u7528\u811A\u672C\u6CE8\u5165(allowScriptInjection=true)\uFF0C\u8BF7\u786E\u4FDD\u6CE8\u5165\u5185\u5BB9\u6765\u6E90\u53EF\u4FE1\u3002\u6CE8\u5165\u811A\u672C\u53EF\u80FD\u5E26\u6765 XSS \u653B\u51FB\u98CE\u9669\u3002`);else throw new Error(`\u89C4\u5219 "${e.id||"unnamed"}" \u7684\u5185\u5BB9\u5305\u542B <script> \u6807\u7B7E\uFF0C\u9ED8\u8BA4\u88AB\u963B\u6B62\u3002\u5982\u9700\u6CE8\u5165\u811A\u672C\uFF0C\u8BF7\u8BBE\u7F6E allowScriptInjection: true`);for(const c of d){if(c==="script")continue;const f=new RegExp(`<${c}\\b[^>]*>[\\s\\S]*?<\\/${c}>`,"gi"),F=new RegExp(`<${c}\\b[^>]*/?>`,"gi");if(f.test(s)||F.test(s))if(e.allowScriptInjection){r?.warn(`[\u5B89\u5168\u8B66\u544A] \u89C4\u5219 "${e.id||"unnamed"}" \u5305\u542B\u88AB\u963B\u6B62\u7684\u6807\u7B7E <${c}>\uFF0C\u5DF2\u901A\u8FC7 allowScriptInjection \u8DF3\u8FC7\u5B89\u5168\u68C0\u67E5\uFF0C\u8BF7\u786E\u4FDD\u5185\u5BB9\u53EF\u4FE1\u3002`);continue}else throw new Error(`\u89C4\u5219 "${e.id||"unnamed"}" \u7684\u5185\u5BB9\u5305\u542B\u88AB\u963B\u6B62\u7684\u6807\u7B7E <${c}>\u3002\u5982\u9700\u6CE8\u5165\u6B64\u6807\u7B7E\uFF0C\u8BF7\u8BBE\u7F6E allowScriptInjection: true \u6216\u5728 security.allowedTags \u4E2D\u6DFB\u52A0 "${c}"`);s=s.replace(f,""),s=s.replace(F,"")}}if(n)for(const d of l){const c=new RegExp(`\\s${d}\\s*=\\s*["'][^"']*["']`,"gi");if(c.test(s))if(e.allowScriptInjection){r?.warn(`[\u5B89\u5168\u8B66\u544A] \u89C4\u5219 "${e.id||"unnamed"}" \u5305\u542B\u5371\u9669\u5C5E\u6027 ${d}\uFF0C\u5DF2\u901A\u8FC7 allowScriptInjection \u8DF3\u8FC7\u5B89\u5168\u68C0\u67E5\uFF0C\u8BF7\u786E\u4FDD\u5185\u5BB9\u53EF\u4FE1\u3002`);continue}else throw new Error(`\u89C4\u5219 "${e.id||"unnamed"}" \u7684\u5185\u5BB9\u5305\u542B\u5371\u9669\u5C5E\u6027 ${d}\u3002\u5982\u9700\u6CE8\u5165\u6B64\u5C5E\u6027\uFF0C\u8BF7\u8BBE\u7F6E allowScriptInjection: true`);s=s.replace(c,"")}return s}function E(u,e,t){if(t==="regex"){try{const i=new RegExp(e),n=u.match(i);if(n&&n.index!==void 0)return{index:n.index,length:n[0].length}}catch{return null}return null}const r=u.indexOf(e);return r===-1?null:{index:r,length:e.length}}function D(u,e,t){let r=u;const i={...t,...e};for(const[n,o]of Object.entries(i)){const a=n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),l=o.replace(/\$/g,"$$$$");r=r.replace(new RegExp(`\\{\\{${a}\\}\\}`,"g"),l)}return r}function x(u,e){let t=!1;switch(u.type){case"env":{const r=u.value,i=process.env[r];t=!!i&&i!=="false"&&i!=="0";break}case"file-contains":{const r=u.value;t=e.includes(r);break}case"custom":{const r=u.value;try{t=!!r()}catch{t=!1}break}}return u.negate?!t:t}function k(u){return[...u].sort((e,t)=>(e.priority??100)-(t.priority??100))}function v(u,e,t,r,i){switch(t){case"head-start":{const n=u.match(/<head\b[^>]*>/i);if(!n)return{html:u,injected:!1,reason:"\u672A\u627E\u5230 <head> \u6807\u7B7E"};const o=(n.index??0)+n[0].length;return{html:u.slice(0,o)+`
2
+ `+e+u.slice(o),injected:!0}}case"head-end":{const n=u.match(/<\/head\s*>/i);if(!n)return{html:u,injected:!1,reason:"\u672A\u627E\u5230 </head> \u6807\u7B7E"};const o=n.index;return{html:u.slice(0,o)+e+`
3
+ `+u.slice(o),injected:!0}}case"body-start":{const n=u.match(/<body\b[^>]*>/i);if(!n)return{html:u,injected:!1,reason:"\u672A\u627E\u5230 <body> \u6807\u7B7E"};const o=(n.index??0)+n[0].length;return{html:u.slice(0,o)+`
4
+ `+e+u.slice(o),injected:!0}}case"body-end":{const n=u.match(/<\/body\s*>/i);if(!n)return{html:u,injected:!1,reason:"\u672A\u627E\u5230 </body> \u6807\u7B7E"};const o=n.index;return{html:u.slice(0,o)+e+`
5
+ `+u.slice(o),injected:!0}}case"before-selector":{if(!r)return{html:u,injected:!1,reason:"before-selector \u9700\u8981 selector \u53C2\u6570"};const n=E(u,r,i);return n?{html:u.slice(0,n.index)+e+`
6
+ `+u.slice(n.index),injected:!0}:{html:u,injected:!1,reason:`\u672A\u627E\u5230\u9009\u62E9\u5668 "${r}"`}}case"after-selector":{if(!r)return{html:u,injected:!1,reason:"after-selector \u9700\u8981 selector \u53C2\u6570"};const n=E(u,r,i);if(!n)return{html:u,injected:!1,reason:`\u672A\u627E\u5230\u9009\u62E9\u5668 "${r}"`};const o=n.index+n.length;return{html:u.slice(0,o)+`
7
+ `+e+u.slice(o),injected:!0}}case"replace-selector":{if(!r)return{html:u,injected:!1,reason:"replace-selector \u9700\u8981 selector \u53C2\u6570"};const n=E(u,r,i);if(!n)return{html:u,injected:!1,reason:`\u672A\u627E\u5230\u9009\u62E9\u5668 "${r}"`};const o=n.index+n.length;return{html:u.slice(0,n.index)+e+u.slice(o),injected:!0}}default:return{html:u,injected:!1,reason:`\u4E0D\u652F\u6301\u7684\u6CE8\u5165\u4F4D\u7F6E: ${t}`}}}function I(u,e,t,r,i){let n=u;const o=[],a=k(e);for(const l of a){const s={ruleId:l.id||"unnamed",position:l.position,selector:l.selector,injected:!1,timestamp:Date.now()};if(l.condition&&!x(l.condition,n)){s.injected=!1,s.reason="\u6761\u4EF6\u4E0D\u6EE1\u8DB3\uFF0C\u8DF3\u8FC7\u6CE8\u5165",o.push(s);continue}let d=D(l.content,l.templateVars,t);try{d=A(d,l,r,i)}catch(f){s.injected=!1,s.reason=f.message,o.push(s),i?.warn(`\u89C4\u5219 "${l.id||"unnamed"}" \u5B89\u5168\u68C0\u67E5\u5931\u8D25: ${f.message}`);continue}const c=v(n,d,l.position,l.selector,l.selectorMatch);n=c.html,s.injected=c.injected,s.reason=c.reason,o.push(s)}return{html:n,logs:o}}class T extends g{injectionLogs=[];getDefaultOptions(){return{targetFile:"index.html",logInjection:!0,security:{blockDangerousTags:!0,blockDangerousAttributes:!0}}}validateOptions(){this.validator.field("targetFile").string().field("rules").required().field("logInjection").boolean().validate(),b(this.options)}getPluginName(){return"html-inject"}isTargetFile(e,t){if(t==="index.html")return e.endsWith("index.html")||e.endsWith("index.htm");const r=t.replace(/\\/g,"/"),i=e.replace(/\\/g,"/");return i.endsWith(r)?!0:h.basename(i)===h.basename(r)}addPluginHooks(e){e.transformIndexHtml={order:"post",handler:(t,r)=>{const i=r.filename||"",n=this.options.targetFile||"index.html";if(!this.isTargetFile(i,n))return t;const o={warn:l=>this.logger.warn(l)},a=I(t,this.options.rules,this.options.templateVars,this.options.security,o);return this.injectionLogs=a.logs,this.options.logInjection&&this.logInjectionResults(a.logs),a.html}},e.buildEnd=()=>{this.options.logInjection&&this.injectionLogs.length>0&&this.logger.info(`\u6CE8\u5165\u5B8C\u6210\uFF0C\u5171\u5904\u7406 ${this.injectionLogs.length} \u6761\u89C4\u5219`)}}logInjectionResults(e){for(const t of e)t.injected?this.logger.success(`\u89C4\u5219 "${t.ruleId}" \u6CE8\u5165\u6210\u529F (\u4F4D\u7F6E: ${t.position}${t.selector?`, \u9009\u62E9\u5668: ${t.selector}`:""})`):this.logger.warn(`\u89C4\u5219 "${t.ruleId}" \u6CE8\u5165\u5931\u8D25: ${t.reason||"\u672A\u77E5\u539F\u56E0"}`)}getInjectionLogs(){return[...this.injectionLogs]}}const S=p(T);export{S as htmlInject};
@@ -1 +1 @@
1
- "use strict";const index=require("../shared/vite-plugin.D8L9KzuW.cjs");require("../shared/vite-plugin.CawoITTT.cjs"),require("../logger/index.cjs"),require("fs"),require("path"),require("crypto"),require("../shared/vite-plugin.IGZeStMa.cjs"),require("../shared/vite-plugin.Tab4qcIM.cjs"),exports.buildProgress=index.buildProgress,exports.copyFile=index.copyFile,exports.faviconManager=index.faviconManager,exports.generateRouter=index.generateRouter,exports.generateVersion=index.generateVersion,exports.loadingManager=index.loadingManager,exports.versionUpdateChecker=index.versionUpdateChecker;
1
+ "use strict";const plugins_buildProgress_index=require("./buildProgress/index.cjs"),plugins_compressAssets_index=require("./compressAssets/index.cjs"),plugins_copyFile_index=require("./copyFile/index.cjs"),plugins_faviconManager_index=require("./faviconManager/index.cjs"),plugins_generateRouter_index=require("./generateRouter/index.cjs"),plugins_generateVersion_index=require("./generateVersion/index.cjs"),plugins_htmlInject_index=require("./htmlInject/index.cjs"),plugins_loadingManager_index=require("./loadingManager/index.cjs"),plugins_versionUpdateChecker_index=require("./versionUpdateChecker/index.cjs");require("../factory/index.cjs"),require("../logger/index.cjs"),require("../common/object/index.cjs"),require("../shared/vite-plugin.Bcg6RW2N.cjs"),require("node:zlib"),require("node:fs"),require("node:stream/promises"),require("node:path"),require("../common/fs/index.cjs"),require("fs"),require("path"),require("../common/html/index.cjs"),require("../common/format/index.cjs"),require("crypto"),require("../common/script/index.cjs"),require("../common/validation/index.cjs"),exports.buildProgress=plugins_buildProgress_index.buildProgress,exports.compressAssets=plugins_compressAssets_index.compressAssets,exports.copyFile=plugins_copyFile_index.copyFile,exports.faviconManager=plugins_faviconManager_index.faviconManager,exports.generateRouter=plugins_generateRouter_index.generateRouter,exports.generateVersion=plugins_generateVersion_index.generateVersion,exports.htmlInject=plugins_htmlInject_index.htmlInject,exports.loadingManager=plugins_loadingManager_index.loadingManager,exports.versionUpdateChecker=plugins_versionUpdateChecker_index.versionUpdateChecker;