@meng-xi/vite-plugin 0.1.3 → 0.1.5
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 +49 -775
- package/README.md +46 -770
- package/dist/common/format/index.cjs +1 -1
- package/dist/common/format/index.d.cts +1 -130
- package/dist/common/format/index.d.mts +1 -130
- package/dist/common/format/index.d.ts +1 -130
- package/dist/common/format/index.mjs +1 -1
- package/dist/common/fs/index.cjs +1 -1
- package/dist/common/fs/index.d.cts +1 -89
- package/dist/common/fs/index.d.mts +1 -89
- package/dist/common/fs/index.d.ts +1 -89
- package/dist/common/fs/index.mjs +1 -1
- package/dist/common/html/index.cjs +2 -2
- package/dist/common/html/index.d.cts +19 -81
- package/dist/common/html/index.d.mts +19 -81
- package/dist/common/html/index.d.ts +19 -81
- package/dist/common/html/index.mjs +2 -2
- package/dist/common/index.cjs +1 -1
- package/dist/common/index.d.cts +7 -8
- package/dist/common/index.d.mts +7 -8
- package/dist/common/index.d.ts +7 -8
- package/dist/common/index.mjs +1 -1
- package/dist/common/script/index.cjs +1 -1
- package/dist/common/script/index.d.cts +1 -44
- package/dist/common/script/index.d.mts +1 -44
- package/dist/common/script/index.d.ts +1 -44
- package/dist/common/script/index.mjs +1 -1
- package/dist/common/ui/index.cjs +1 -0
- package/dist/common/ui/index.d.cts +22 -0
- package/dist/common/ui/index.d.mts +22 -0
- package/dist/common/ui/index.d.ts +22 -0
- package/dist/common/ui/index.mjs +1 -0
- package/dist/common/validation/index.cjs +1 -1
- package/dist/common/validation/index.d.cts +2 -79
- package/dist/common/validation/index.d.mts +2 -79
- package/dist/common/validation/index.d.ts +2 -79
- package/dist/common/validation/index.mjs +1 -1
- package/dist/factory/index.cjs +1 -1
- package/dist/factory/index.d.cts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.d.ts +1 -1
- package/dist/factory/index.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +12 -10
- package/dist/index.d.mts +12 -10
- package/dist/index.d.ts +12 -10
- package/dist/index.mjs +1 -1
- package/dist/logger/index.d.cts +92 -1
- package/dist/logger/index.d.mts +92 -1
- package/dist/logger/index.d.ts +92 -1
- package/dist/plugins/autoImport/index.cjs +17 -0
- package/dist/plugins/autoImport/index.d.cts +291 -0
- package/dist/plugins/autoImport/index.d.mts +291 -0
- package/dist/plugins/autoImport/index.d.ts +291 -0
- package/dist/plugins/autoImport/index.mjs +17 -0
- package/dist/plugins/buildProgress/index.cjs +2 -2
- package/dist/plugins/buildProgress/index.d.cts +1 -1
- package/dist/plugins/buildProgress/index.d.mts +1 -1
- package/dist/plugins/buildProgress/index.d.ts +1 -1
- package/dist/plugins/buildProgress/index.mjs +2 -2
- package/dist/plugins/bundleAnalyzer/index.cjs +11 -11
- package/dist/plugins/bundleAnalyzer/index.d.cts +1 -1
- package/dist/plugins/bundleAnalyzer/index.d.mts +1 -1
- package/dist/plugins/bundleAnalyzer/index.d.ts +1 -1
- package/dist/plugins/bundleAnalyzer/index.mjs +18 -18
- package/dist/plugins/compressAssets/index.cjs +1 -1
- package/dist/plugins/compressAssets/index.d.cts +1 -1
- package/dist/plugins/compressAssets/index.d.mts +1 -1
- package/dist/plugins/compressAssets/index.d.ts +1 -1
- package/dist/plugins/compressAssets/index.mjs +1 -1
- package/dist/plugins/copyFile/index.cjs +1 -1
- package/dist/plugins/copyFile/index.d.cts +21 -3
- package/dist/plugins/copyFile/index.d.mts +21 -3
- package/dist/plugins/copyFile/index.d.ts +21 -3
- package/dist/plugins/copyFile/index.mjs +1 -1
- package/dist/plugins/envGuard/index.cjs +67 -0
- package/dist/plugins/envGuard/index.d.cts +255 -0
- package/dist/plugins/envGuard/index.d.mts +255 -0
- package/dist/plugins/envGuard/index.d.ts +255 -0
- package/dist/plugins/envGuard/index.mjs +67 -0
- package/dist/plugins/faviconManager/index.cjs +1 -1
- package/dist/plugins/faviconManager/index.d.cts +44 -6
- package/dist/plugins/faviconManager/index.d.mts +44 -6
- package/dist/plugins/faviconManager/index.d.ts +44 -6
- package/dist/plugins/faviconManager/index.mjs +1 -1
- package/dist/plugins/generateRouter/index.cjs +4 -4
- package/dist/plugins/generateRouter/index.d.cts +62 -15
- package/dist/plugins/generateRouter/index.d.mts +62 -15
- package/dist/plugins/generateRouter/index.d.ts +62 -15
- package/dist/plugins/generateRouter/index.mjs +4 -4
- package/dist/plugins/generateVersion/index.cjs +1 -1
- package/dist/plugins/generateVersion/index.d.cts +13 -1
- package/dist/plugins/generateVersion/index.d.mts +13 -1
- package/dist/plugins/generateVersion/index.d.ts +13 -1
- package/dist/plugins/generateVersion/index.mjs +1 -1
- package/dist/plugins/htmlInject/index.cjs +7 -7
- package/dist/plugins/htmlInject/index.d.cts +50 -195
- package/dist/plugins/htmlInject/index.d.mts +50 -195
- package/dist/plugins/htmlInject/index.d.ts +50 -195
- package/dist/plugins/htmlInject/index.mjs +7 -7
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.d.cts +5 -2
- package/dist/plugins/index.d.mts +5 -2
- package/dist/plugins/index.d.ts +5 -2
- package/dist/plugins/index.mjs +1 -1
- package/dist/plugins/loadingManager/index.cjs +26 -26
- package/dist/plugins/loadingManager/index.d.cts +1 -1
- package/dist/plugins/loadingManager/index.d.mts +1 -1
- package/dist/plugins/loadingManager/index.d.ts +1 -1
- package/dist/plugins/loadingManager/index.mjs +11 -11
- package/dist/plugins/versionUpdateChecker/index.cjs +1 -1
- package/dist/plugins/versionUpdateChecker/index.d.cts +1 -1
- package/dist/plugins/versionUpdateChecker/index.d.mts +1 -1
- package/dist/plugins/versionUpdateChecker/index.d.ts +1 -1
- package/dist/plugins/versionUpdateChecker/index.mjs +1 -1
- package/dist/shared/vite-plugin.B8FuZce1.d.cts +45 -0
- package/dist/shared/vite-plugin.B8FuZce1.d.mts +45 -0
- package/dist/shared/vite-plugin.B8FuZce1.d.ts +45 -0
- package/dist/shared/vite-plugin.BI9taN75.d.cts +122 -0
- package/dist/shared/vite-plugin.BI9taN75.d.mts +122 -0
- package/dist/shared/vite-plugin.BI9taN75.d.ts +122 -0
- package/dist/shared/vite-plugin.BPFqtmWa.mjs +1 -0
- package/dist/shared/vite-plugin.CnOy46d3.cjs +1 -0
- package/package.json +16 -16
- package/dist/common/compress/index.cjs +0 -1
- package/dist/common/compress/index.d.cts +0 -23
- package/dist/common/compress/index.d.mts +0 -23
- package/dist/common/compress/index.d.ts +0 -23
- package/dist/common/compress/index.mjs +0 -1
- package/dist/common/object/index.cjs +0 -1
- package/dist/common/object/index.d.cts +0 -30
- package/dist/common/object/index.d.mts +0 -30
- package/dist/common/object/index.d.ts +0 -30
- package/dist/common/object/index.mjs +0 -1
- package/dist/common/path/index.cjs +0 -1
- package/dist/common/path/index.d.cts +0 -22
- package/dist/common/path/index.d.mts +0 -22
- package/dist/common/path/index.d.ts +0 -22
- package/dist/common/path/index.mjs +0 -1
- package/dist/shared/vite-plugin.CLr0ttuO.d.cts +0 -135
- package/dist/shared/vite-plugin.CLr0ttuO.d.mts +0 -135
- package/dist/shared/vite-plugin.CLr0ttuO.d.ts +0 -135
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { BasePluginOptions, PluginFactory } from '../../factory/index.js';
|
|
2
|
+
import 'vite';
|
|
3
|
+
import '../../shared/vite-plugin.B8FuZce1.js';
|
|
4
|
+
import '../../shared/vite-plugin.DRRlWY8P.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 环境变量值类型
|
|
8
|
+
*
|
|
9
|
+
* @description 定义环境变量支持的所有值类型:
|
|
10
|
+
* - `string`:普通字符串(默认类型)
|
|
11
|
+
* - `number`:数字类型
|
|
12
|
+
* - `url`:URL 地址
|
|
13
|
+
* - `boolean`:布尔值
|
|
14
|
+
* - `enum`:枚举值
|
|
15
|
+
* - `json`:JSON 字符串
|
|
16
|
+
* - `semver`:语义化版本号
|
|
17
|
+
* - `path`:文件路径
|
|
18
|
+
*/
|
|
19
|
+
type EnvType = 'string' | 'number' | 'url' | 'boolean' | 'enum' | 'json' | 'semver' | 'path';
|
|
20
|
+
/**
|
|
21
|
+
* 环境变量字段校验规则
|
|
22
|
+
*
|
|
23
|
+
* @description 定义单个环境变量的校验规则,包括类型约束、范围限制、
|
|
24
|
+
* 自定义验证函数和元数据信息等。
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* // 基本字符串字段
|
|
29
|
+
* const rule: EnvFieldRule = { type: 'string', required: true }
|
|
30
|
+
*
|
|
31
|
+
* // 带范围的数字字段
|
|
32
|
+
* const portRule: EnvFieldRule = { type: 'number', required: true, minValue: 1, maxValue: 65535 }
|
|
33
|
+
*
|
|
34
|
+
* // 枚举字段
|
|
35
|
+
* const envRule: EnvFieldRule = { type: 'enum', required: true, enumValues: ['development', 'staging', 'production'] }
|
|
36
|
+
*
|
|
37
|
+
* // 自定义验证
|
|
38
|
+
* const customRule: EnvFieldRule = {
|
|
39
|
+
* type: 'string',
|
|
40
|
+
* required: true,
|
|
41
|
+
* validator: (v) => v.startsWith('https://') || '必须使用 HTTPS'
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
interface EnvFieldRule {
|
|
46
|
+
/** 值类型,默认为 `'string'` */
|
|
47
|
+
type?: EnvType;
|
|
48
|
+
/** 是否为必需字段,默认为 `true` */
|
|
49
|
+
required?: boolean;
|
|
50
|
+
/** 正则表达式,值必须匹配此模式 */
|
|
51
|
+
pattern?: RegExp;
|
|
52
|
+
/**
|
|
53
|
+
* 自定义验证函数
|
|
54
|
+
*
|
|
55
|
+
* @description 返回 `true` 表示验证通过,返回字符串表示验证失败且字符串为错误消息
|
|
56
|
+
*/
|
|
57
|
+
validator?: (value: string) => boolean | string;
|
|
58
|
+
/** 自定义错误消息,覆盖默认的错误提示 */
|
|
59
|
+
message?: string;
|
|
60
|
+
/** 当值为空时使用的默认值 */
|
|
61
|
+
default?: string;
|
|
62
|
+
/** 枚举值列表(仅 `enum` 类型需要) */
|
|
63
|
+
enumValues?: string[];
|
|
64
|
+
/** 数值最小值(仅 `number` 类型) */
|
|
65
|
+
minValue?: number;
|
|
66
|
+
/** 数值最大值(仅 `number` 类型) */
|
|
67
|
+
maxValue?: number;
|
|
68
|
+
/** 字符串最小长度(仅字符串类类型) */
|
|
69
|
+
minLength?: number;
|
|
70
|
+
/** 字符串最大长度(仅字符串类类型) */
|
|
71
|
+
maxLength?: number;
|
|
72
|
+
/** 变量分组名称,用于模板生成时的分组显示 */
|
|
73
|
+
group?: string;
|
|
74
|
+
/** 变量描述信息,用于模板生成时的说明文本 */
|
|
75
|
+
description?: string;
|
|
76
|
+
/** 是否为敏感变量,模板中会隐藏实际值 */
|
|
77
|
+
sensitive?: boolean;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 环境变量验证结果
|
|
81
|
+
*
|
|
82
|
+
* @description 表示单个环境变量的验证结果,包含验证状态、错误消息和有效值。
|
|
83
|
+
*/
|
|
84
|
+
interface EnvValidationResult {
|
|
85
|
+
/** 环境变量名 */
|
|
86
|
+
key: string;
|
|
87
|
+
/**
|
|
88
|
+
* 验证状态:
|
|
89
|
+
* - `pass`:验证通过
|
|
90
|
+
* - `missing`:必需变量缺失
|
|
91
|
+
* - `type_error`:类型不匹配
|
|
92
|
+
* - `custom_error`:自定义验证失败或正则不匹配
|
|
93
|
+
* - `enum_mismatch`:枚举值不匹配
|
|
94
|
+
* - `range_error`:数值超出范围
|
|
95
|
+
* - `length_error`:字符串长度不符合要求
|
|
96
|
+
*/
|
|
97
|
+
status: 'pass' | 'missing' | 'type_error' | 'custom_error' | 'enum_mismatch' | 'range_error' | 'length_error';
|
|
98
|
+
/** 验证消息(验证通过时为空字符串,失败时为错误描述) */
|
|
99
|
+
message: string;
|
|
100
|
+
/** 环境变量的有效值(缺失时可能为 `undefined` 或默认值) */
|
|
101
|
+
value: string | undefined;
|
|
102
|
+
/** 应用的校验规则(含默认值填充后的完整规则) */
|
|
103
|
+
rule: EnvFieldRule;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 环境变量校验失败时的处理动作
|
|
108
|
+
*
|
|
109
|
+
* @description 定义当环境变量校验未通过时的处理策略:
|
|
110
|
+
* - `error`: 抛出错误,中断构建流程
|
|
111
|
+
* - `warn`: 输出警告日志,继续构建
|
|
112
|
+
* - `ignore`: 静默忽略,不输出任何信息
|
|
113
|
+
*/
|
|
114
|
+
type EnvFailAction = 'error' | 'warn' | 'ignore';
|
|
115
|
+
/**
|
|
116
|
+
* 运行时守卫的行为模式
|
|
117
|
+
*
|
|
118
|
+
* @description 定义注入到 HTML 中的运行时守卫代码在检测到
|
|
119
|
+
* 环境变量缺失或无效时的行为方式:
|
|
120
|
+
* - `console`: 在浏览器控制台输出警告信息
|
|
121
|
+
* - `throw`: 抛出运行时错误,阻止应用启动
|
|
122
|
+
* - `overlay`: 在页面顶部显示警告横幅
|
|
123
|
+
*/
|
|
124
|
+
type RuntimeGuardMode = 'console' | 'throw' | 'overlay';
|
|
125
|
+
/**
|
|
126
|
+
* 环境变量校验结果汇总
|
|
127
|
+
*
|
|
128
|
+
* @interface EnvGuardResult
|
|
129
|
+
* @description 包含所有环境变量的校验统计信息和详细结果列表,
|
|
130
|
+
* 用于报告生成和日志输出。
|
|
131
|
+
*/
|
|
132
|
+
interface EnvGuardResult {
|
|
133
|
+
/** 校验时间戳(ISO 格式) */
|
|
134
|
+
timestamp: string;
|
|
135
|
+
/** 校验的环境变量总数 */
|
|
136
|
+
total: number;
|
|
137
|
+
/** 校验通过的变量数量 */
|
|
138
|
+
passed: number;
|
|
139
|
+
/** 缺失的必需变量数量 */
|
|
140
|
+
missing: number;
|
|
141
|
+
/** 校验失败的变量数量(类型不匹配、范围越界等) */
|
|
142
|
+
invalid: number;
|
|
143
|
+
/** 所有变量的详细校验结果列表 */
|
|
144
|
+
results: EnvValidationResult[];
|
|
145
|
+
/** 是否所有变量均校验通过 */
|
|
146
|
+
allPassed: boolean;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* 环境变量守卫插件的配置选项
|
|
150
|
+
*
|
|
151
|
+
* @interface EnvGuardOptions
|
|
152
|
+
* @extends {BasePluginOptions}
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* envGuard({
|
|
157
|
+
* required: {
|
|
158
|
+
* VITE_API_URL: { type: 'url', required: true },
|
|
159
|
+
* VITE_APP_TITLE: { type: 'string', minLength: 1, maxLength: 50 }
|
|
160
|
+
* },
|
|
161
|
+
* failAction: 'error',
|
|
162
|
+
* generateTemplate: true,
|
|
163
|
+
* runtimeGuard: true,
|
|
164
|
+
* runtimeGuardMode: 'console'
|
|
165
|
+
* })
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
interface EnvGuardOptions extends BasePluginOptions {
|
|
169
|
+
/** 环境变量校验规则映射,键为变量名,值为校验规则 */
|
|
170
|
+
required?: Record<string, EnvFieldRule>;
|
|
171
|
+
/** 校验失败时的处理动作 */
|
|
172
|
+
failAction?: EnvFailAction;
|
|
173
|
+
/** 是否自动生成 .env 模板文件 */
|
|
174
|
+
generateTemplate?: boolean;
|
|
175
|
+
/** .env 模板文件的输出路径 */
|
|
176
|
+
templateOutput?: string;
|
|
177
|
+
/** 是否注入运行时环境变量守卫代码到 HTML */
|
|
178
|
+
runtimeGuard?: boolean;
|
|
179
|
+
/** 运行时守卫的全局变量名 */
|
|
180
|
+
runtimeGlobalName?: string;
|
|
181
|
+
/** 运行时守卫的行为模式 */
|
|
182
|
+
runtimeGuardMode?: RuntimeGuardMode;
|
|
183
|
+
/** 需要加载的 .env 文件路径列表 */
|
|
184
|
+
envFiles?: string[];
|
|
185
|
+
/** 是否自动加载 .env 文件中的变量到 process.env */
|
|
186
|
+
autoLoadEnv?: boolean;
|
|
187
|
+
/** 校验报告输出路径,设为 false 则不生成报告 */
|
|
188
|
+
reportOutput?: string | false;
|
|
189
|
+
/** 是否在构建前执行校验 */
|
|
190
|
+
validateBeforeBuild?: boolean;
|
|
191
|
+
/** 是否输出校验摘要日志 */
|
|
192
|
+
showSummary?: boolean;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 创建环境变量守卫插件
|
|
197
|
+
*
|
|
198
|
+
* @function envGuard
|
|
199
|
+
* @param {Partial<EnvGuardOptions>} [options] - 插件配置选项
|
|
200
|
+
* @returns {Plugin} Vite 插件实例
|
|
201
|
+
*
|
|
202
|
+
* @description 在 Vite 构建前校验环境变量的存在性和合法性,
|
|
203
|
+
* 支持多种值类型校验、正则匹配、自定义校验函数等,
|
|
204
|
+
* 可选生成 .env 模板文件和注入运行时守卫代码。
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* // vite.config.ts
|
|
209
|
+
* import { envGuard } from '@meng-xi/vite-plugin'
|
|
210
|
+
*
|
|
211
|
+
* export default defineConfig({
|
|
212
|
+
* plugins: [
|
|
213
|
+
* envGuard({
|
|
214
|
+
* required: {
|
|
215
|
+
* VITE_API_BASE_URL: {
|
|
216
|
+
* type: 'url',
|
|
217
|
+
* required: true,
|
|
218
|
+
* message: 'API 基础地址必须为合法 URL'
|
|
219
|
+
* },
|
|
220
|
+
* VITE_APP_TITLE: {
|
|
221
|
+
* type: 'string',
|
|
222
|
+
* required: true,
|
|
223
|
+
* minLength: 1,
|
|
224
|
+
* maxLength: 50
|
|
225
|
+
* },
|
|
226
|
+
* VITE_ENABLE_ANALYTICS: {
|
|
227
|
+
* type: 'boolean',
|
|
228
|
+
* required: false,
|
|
229
|
+
* default: 'false'
|
|
230
|
+
* },
|
|
231
|
+
* VITE_API_TIMEOUT: {
|
|
232
|
+
* type: 'number',
|
|
233
|
+
* minValue: 1000,
|
|
234
|
+
* maxValue: 60000,
|
|
235
|
+
* message: 'API 超时时间必须在 1000-60000ms 之间'
|
|
236
|
+
* },
|
|
237
|
+
* VITE_LOG_LEVEL: {
|
|
238
|
+
* type: 'enum',
|
|
239
|
+
* enumValues: ['debug', 'info', 'warn', 'error'],
|
|
240
|
+
* default: 'info'
|
|
241
|
+
* }
|
|
242
|
+
* },
|
|
243
|
+
* failAction: 'error',
|
|
244
|
+
* generateTemplate: true,
|
|
245
|
+
* runtimeGuard: true,
|
|
246
|
+
* runtimeGuardMode: 'console'
|
|
247
|
+
* })
|
|
248
|
+
* ]
|
|
249
|
+
* })
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
declare const envGuard: PluginFactory<EnvGuardOptions, EnvGuardOptions>;
|
|
253
|
+
|
|
254
|
+
export { envGuard };
|
|
255
|
+
export type { EnvFailAction, EnvGuardOptions, EnvGuardResult, RuntimeGuardMode };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import{createPluginFactory as v,BasePlugin as F}from"../../factory/index.mjs";import{injectBeforeTag as E}from"../../common/html/index.mjs";import{writeFileContent as g}from"../../common/fs/index.mjs";import{getDateFormatParams as A}from"../../common/format/index.mjs";import m from"node:path";import p from"node:fs";import"../../logger/index.mjs";import"../../shared/vite-plugin.DcExl6jd.mjs";import"../../shared/vite-plugin.BPFqtmWa.mjs";import"fs";import"path";const C=new Set(["string","url","path","enum","semver",void 0]);function D(t,u){switch(u.type){case"number":{if(isNaN(Number(t))||t.trim()==="")return{valid:!1,status:"type_error",message:`\u73AF\u5883\u53D8\u91CF\u503C "${t}" \u4E0D\u662F\u5408\u6CD5\u6570\u5B57`};break}case"url":{try{new URL(t)}catch{return{valid:!1,status:"type_error",message:`\u73AF\u5883\u53D8\u91CF\u503C "${t}" \u4E0D\u662F\u5408\u6CD5 URL`}}break}case"boolean":{const r=t.toLowerCase();if(!["true","false","1","0","yes","no"].includes(r))return{valid:!1,status:"type_error",message:`\u73AF\u5883\u53D8\u91CF\u503C "${t}" \u4E0D\u662F\u5408\u6CD5\u5E03\u5C14\u503C (true/false/1/0/yes/no)`};break}case"enum":{if(!u.enumValues||u.enumValues.length===0)return{valid:!1,status:"enum_mismatch",message:"enum \u7C7B\u578B\u5FC5\u987B\u6307\u5B9A enumValues"};if(!u.enumValues.includes(t))return{valid:!1,status:"enum_mismatch",message:`\u73AF\u5883\u53D8\u91CF\u503C "${t}" \u4E0D\u5728\u5141\u8BB8\u7684\u679A\u4E3E\u503C\u4E2D: ${u.enumValues.join(", ")}`};break}case"json":{try{JSON.parse(t)}catch{return{valid:!1,status:"type_error",message:"\u73AF\u5883\u53D8\u91CF\u503C\u4E0D\u662F\u5408\u6CD5 JSON"}}break}case"semver":{if(!/^\d+\.\d+\.\d+(-[\w.]+)?(\+[\w.]+)?$/.test(t))return{valid:!1,status:"type_error",message:`\u73AF\u5883\u53D8\u91CF\u503C "${t}" \u4E0D\u662F\u5408\u6CD5\u8BED\u4E49\u5316\u7248\u672C\u53F7 (x.y.z)`};break}case"path":{if(!/^(?:[./\\]|(?:[a-zA-Z]:))/.test(t))return{valid:!1,status:"type_error",message:`\u73AF\u5883\u53D8\u91CF\u503C "${t}" \u4E0D\u662F\u5408\u6CD5\u6587\u4EF6\u8DEF\u5F84`};break}}return{valid:!0,status:"pass",message:""}}function y(t,u){if(u.type!=="number")return{valid:!0,status:"pass",message:""};const r=Number(t);return u.minValue!==void 0&&r<u.minValue?{valid:!1,status:"range_error",message:`\u6570\u503C ${r} \u5C0F\u4E8E\u6700\u5C0F\u503C ${u.minValue}`}:u.maxValue!==void 0&&r>u.maxValue?{valid:!1,status:"range_error",message:`\u6570\u503C ${r} \u5927\u4E8E\u6700\u5927\u503C ${u.maxValue}`}:{valid:!0,status:"pass",message:""}}function $(t,u){return C.has(u.type)?u.minLength!==void 0&&t.length<u.minLength?{valid:!1,status:"length_error",message:`\u5B57\u7B26\u4E32\u957F\u5EA6 ${t.length} \u5C0F\u4E8E\u6700\u5C0F\u957F\u5EA6 ${u.minLength}`}:u.maxLength!==void 0&&t.length>u.maxLength?{valid:!1,status:"length_error",message:`\u5B57\u7B26\u4E32\u957F\u5EA6 ${t.length} \u5927\u4E8E\u6700\u5927\u957F\u5EA6 ${u.maxLength}`}:{valid:!0,status:"pass",message:""}:{valid:!0,status:"pass",message:""}}function R(t,u,r){const e={type:"string",required:!0,...r};if(u===void 0||u==="")return e.required!==!1?{key:t,status:"missing",message:e.message||`\u7F3A\u5C11\u5FC5\u9700\u7684\u73AF\u5883\u53D8\u91CF: ${t}`,value:u,rule:e}:{key:t,status:"pass",message:"",value:e.default??u,rule:e};const s=D(u,e);if(!s.valid)return{key:t,status:s.status,message:e.message||s.message,value:u,rule:e};const i=y(u,e);if(!i.valid)return{key:t,status:i.status,message:e.message||i.message,value:u,rule:e};const a=$(u,e);if(!a.valid)return{key:t,status:a.status,message:e.message||a.message,value:u,rule:e};if(e.pattern&&!e.pattern.test(u))return{key:t,status:"custom_error",message:e.message||`\u73AF\u5883\u53D8\u91CF ${t} \u4E0D\u5339\u914D\u6B63\u5219: ${e.pattern.source}`,value:u,rule:e};if(e.validator){const n=e.validator(u);if(n!==!0){const l=typeof n=="string"?n:"";return{key:t,status:"custom_error",message:e.message||l||`\u73AF\u5883\u53D8\u91CF ${t} \u81EA\u5B9A\u4E49\u6821\u9A8C\u5931\u8D25`,value:u,rule:e}}}return{key:t,status:"pass",message:"",value:u,rule:e}}function w(t,u){const r=[];for(const[e,s]of Object.entries(u)){const i=t[e];r.push(R(e,i,s))}return r}function _(t){const u=new Map,r=[];for(const[s,i]of Object.entries(t)){const a={type:"string",required:!0,...i};if(a.group){const n=u.get(a.group)||[];n.push({key:s,rule:a}),u.set(a.group,n)}else r.push({key:s,rule:a})}const e=[];e.push("# \u73AF\u5883\u53D8\u91CF\u6A21\u677F\u6587\u4EF6"),e.push(`# \u751F\u6210\u65F6\u95F4: ${new Date().toISOString()}`),e.push("# \u7531 @meng-xi/vite-plugin envGuard \u81EA\u52A8\u751F\u6210"),e.push(""),r.length>0&&h(e,"\u901A\u7528\u914D\u7F6E",r);for(const[s,i]of u)h(e,s,i);return e.join(`
|
|
2
|
+
`)}function h(t,u,r){t.push("# =============================="),t.push(`# ${u}`),t.push("# =============================="),t.push("");for(const{key:e,rule:s}of r){s.description&&t.push(`# ${s.description}`);const i=[];i.push(`\u7C7B\u578B: ${s.type||"string"}`),i.push(s.required!==!1?"\u5FC5\u9700":"\u53EF\u9009"),s.enumValues&&s.enumValues.length>0&&i.push(`\u679A\u4E3E\u503C: ${s.enumValues.join(" | ")}`),s.minValue!==void 0&&i.push(`\u6700\u5C0F\u503C: ${s.minValue}`),s.maxValue!==void 0&&i.push(`\u6700\u5927\u503C: ${s.maxValue}`),s.minLength!==void 0&&i.push(`\u6700\u5C0F\u957F\u5EA6: ${s.minLength}`),s.maxLength!==void 0&&i.push(`\u6700\u5927\u957F\u5EA6: ${s.maxLength}`),s.sensitive&&i.push("\u26A0\uFE0F \u654F\u611F\u4FE1\u606F"),t.push(`# [${i.join(" | ")}]`),s.default!==void 0?t.push(`${e}=${s.sensitive?"********":s.default}`):t.push(`${e}=`),t.push("")}}function b(t,u,r,e){const s=[];for(const[o,d]of Object.entries(t))d.required!==!1&&s.push({key:o,rule:{type:"string",required:!0,...d}});if(s.length===0)return"";const i=e.filter(o=>o.status!=="pass"),a=s.map(({key:o,rule:d})=>({key:o,type:d.type||"string",description:d.description||""})),n=JSON.stringify(a,null,2),l=i.map(o=>o.key),f=JSON.stringify(l),c=k(r);return`<script>
|
|
3
|
+
${`
|
|
4
|
+
(function() {
|
|
5
|
+
'use strict';
|
|
6
|
+
var GUARD_NAME = ${JSON.stringify(u)};
|
|
7
|
+
var GUARD_DATA = ${n};
|
|
8
|
+
var FAILED_KEYS = ${f};
|
|
9
|
+
var MODE = ${JSON.stringify(r)};
|
|
10
|
+
|
|
11
|
+
var missing = [];
|
|
12
|
+
var invalid = [];
|
|
13
|
+
|
|
14
|
+
for (var i = 0; i < GUARD_DATA.length; i++) {
|
|
15
|
+
var item = GUARD_DATA[i];
|
|
16
|
+
var el = document.querySelector('meta[name="env:' + item.key + '"]');
|
|
17
|
+
if (!el) {
|
|
18
|
+
var attr = document.querySelector('[' + item.key + ']');
|
|
19
|
+
if (!attr) {
|
|
20
|
+
missing.push(item.key);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
for (var j = 0; j < FAILED_KEYS.length; j++) {
|
|
26
|
+
if (invalid.indexOf(FAILED_KEYS[j]) === -1 && missing.indexOf(FAILED_KEYS[j]) === -1) {
|
|
27
|
+
invalid.push(FAILED_KEYS[j]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
var hasIssues = missing.length > 0 || invalid.length > 0;
|
|
32
|
+
|
|
33
|
+
var guard = {
|
|
34
|
+
missing: missing,
|
|
35
|
+
invalid: invalid,
|
|
36
|
+
allPassed: !hasIssues,
|
|
37
|
+
data: GUARD_DATA
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
if (typeof window !== 'undefined') {
|
|
41
|
+
window[GUARD_NAME] = guard;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (hasIssues) {
|
|
45
|
+
${c}
|
|
46
|
+
}
|
|
47
|
+
})();
|
|
48
|
+
`.trim()}
|
|
49
|
+
<\/script>`}function k(t){switch(t){case"console":return`
|
|
50
|
+
var msgs = [];
|
|
51
|
+
if (missing.length > 0) msgs.push('[EnvGuard] \u7F3A\u5C11\u73AF\u5883\u53D8\u91CF: ' + missing.join(', '));
|
|
52
|
+
if (invalid.length > 0) msgs.push('[EnvGuard] \u73AF\u5883\u53D8\u91CF\u6821\u9A8C\u5931\u8D25: ' + invalid.join(', '));
|
|
53
|
+
for (var k = 0; k < msgs.length; k++) console.warn(msgs[k]);`;case"throw":return`
|
|
54
|
+
var errMsg = '';
|
|
55
|
+
if (missing.length > 0) errMsg += '\u7F3A\u5C11\u73AF\u5883\u53D8\u91CF: ' + missing.join(', ') + '; ';
|
|
56
|
+
if (invalid.length > 0) errMsg += '\u73AF\u5883\u53D8\u91CF\u6821\u9A8C\u5931\u8D25: ' + invalid.join(', ');
|
|
57
|
+
throw new Error('[EnvGuard] ' + errMsg);`;case"overlay":return`
|
|
58
|
+
var overlay = document.createElement('div');
|
|
59
|
+
overlay.id = '__env_guard_overlay__';
|
|
60
|
+
overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:99999;background:#fff3cd;color:#856404;padding:12px 20px;font-size:14px;font-family:monospace;border-bottom:3px solid #ffc107;box-shadow:0 2px 8px rgba(0,0,0,0.15);';
|
|
61
|
+
var html = '<strong>\u26A0\uFE0F EnvGuard \u8B66\u544A</strong><br>';
|
|
62
|
+
if (missing.length > 0) html += '\u7F3A\u5C11: ' + missing.join(', ') + '<br>';
|
|
63
|
+
if (invalid.length > 0) html += '\u6821\u9A8C\u5931\u8D25: ' + invalid.join(', ');
|
|
64
|
+
overlay.innerHTML = html;
|
|
65
|
+
document.addEventListener('DOMContentLoaded', function() { document.body.appendChild(overlay); });`;default:return""}}function B(t,u){const r=A(t);let e=u;for(const[s,i]of Object.entries(r))e=e.replace(new RegExp(`\\{${s}\\}`,"g"),i);return e}class x extends F{validationResults=[];guardResult=null;getDefaultOptions(){return{required:{},failAction:"error",generateTemplate:!0,templateOutput:".env.template",runtimeGuard:!1,runtimeGlobalName:"__ENV_GUARD__",runtimeGuardMode:"console",envFiles:[".env",".env.local",".env.production",".env.development"],autoLoadEnv:!0,reportOutput:!1,validateBeforeBuild:!0,showSummary:!0}}validateOptions(){this.validator.field("failAction").enum(["error","warn","ignore"]).field("generateTemplate").boolean().field("runtimeGuard").boolean().field("runtimeGuardMode").enum(["console","throw","overlay"]).field("autoLoadEnv").boolean().field("reportOutput").custom(u=>u===!1||typeof u=="string","reportOutput \u5FC5\u987B\u4E3A false \u6216\u5B57\u7B26\u4E32\u8DEF\u5F84").field("validateBeforeBuild").boolean().field("showSummary").boolean().validate()}getPluginName(){return"env-guard"}addPluginHooks(u){this.options.validateBeforeBuild&&(u.configResolved=r=>{this.viteConfig=r,this.runValidation()}),this.options.runtimeGuard&&(u.transformIndexHtml={order:"post",handler:r=>this.safeExecuteSync(()=>this.injectRuntimeGuard(r),"\u6CE8\u5165\u8FD0\u884C\u65F6\u5B88\u536B")||r})}runValidation(){this.options.autoLoadEnv&&this.loadEnvFiles(),this.validationResults=w(process.env,this.options.required),this.guardResult=this.buildResult(),this.options.generateTemplate&&this.writeEnvTemplate(),this.options.reportOutput&&this.writeReport(),this.options.showSummary&&this.logSummary(),this.handleResults()}loadEnvFiles(){if(!this.viteConfig)return;const u=this.viteConfig.root||process.cwd();for(const r of this.options.envFiles){const e=m.resolve(u,r);if(p.existsSync(e))try{this.parseAndLoadEnvFile(e)}catch{this.logger.warn(`\u52A0\u8F7D .env \u6587\u4EF6\u5931\u8D25: ${e}`)}}}parseAndLoadEnvFile(u){const r=p.readFileSync(u,"utf-8").split(`
|
|
66
|
+
`);for(const e of r){const s=e.trim();if(!s||s.startsWith("#"))continue;const i=s.indexOf("=");if(i===-1)continue;const a=s.slice(0,i).trim();let n=s.slice(i+1).trim();(n.startsWith('"')&&n.endsWith('"')||n.startsWith("'")&&n.endsWith("'"))&&(n=n.slice(1,-1)),a.startsWith("VITE_")&&process.env[a]===void 0&&(process.env[a]=n)}}buildResult(){const u=this.validationResults.length,r=this.validationResults.filter(i=>i.status==="pass").length,e=this.validationResults.filter(i=>i.status==="missing").length,s=this.validationResults.filter(i=>i.status!=="pass"&&i.status!=="missing").length;return{timestamp:B(new Date,"{YYYY}-{MM}-{DD}T{HH}:{mm}:{ss}"),total:u,passed:r,missing:e,invalid:s,results:this.validationResults,allPassed:e===0&&s===0}}handleResults(){if(!this.guardResult||this.guardResult.allPassed)return;const u=this.validationResults.filter(i=>i.status==="missing").map(i=>i.key),r=this.validationResults.filter(i=>i.status!=="pass"&&i.status!=="missing"),e=[];u.length>0&&e.push(`\u7F3A\u5C11\u5FC5\u9700\u7684\u73AF\u5883\u53D8\u91CF: ${u.join(", ")}`);for(const i of r)e.push(`${i.key}: ${i.message}`);const s=e.join(`
|
|
67
|
+
`);switch(this.options.failAction){case"error":throw new Error(s);case"warn":this.logger.warn(s);break}}writeEnvTemplate(){const u=this.viteConfig?.root||process.cwd(),r=m.resolve(u,this.options.templateOutput),e=_(this.options.required);this.safeExecuteSync(()=>{g(r,e),this.logger.info(`\u73AF\u5883\u53D8\u91CF\u6A21\u677F\u5DF2\u751F\u6210: ${this.options.templateOutput}`)},"\u751F\u6210 .env \u6A21\u677F")}writeReport(){if(!this.guardResult||!this.options.reportOutput)return;const u=this.viteConfig?.build?.outDir||"dist",r=m.resolve(u,this.options.reportOutput);this.safeExecuteSync(()=>{const e=JSON.stringify(this.guardResult,(s,i)=>i instanceof RegExp?i.toString():typeof i=="function"?"[Function]":i,2);g(r,e),this.logger.info(`\u6821\u9A8C\u62A5\u544A\u5DF2\u751F\u6210: ${this.options.reportOutput}`)},"\u751F\u6210\u6821\u9A8C\u62A5\u544A")}logSummary(){if(!this.guardResult)return;const{total:u,passed:r,missing:e,invalid:s,allPassed:i}=this.guardResult;if(i){this.logger.success(`\u73AF\u5883\u53D8\u91CF\u6821\u9A8C\u901A\u8FC7: ${u} \u4E2A\u53D8\u91CF\u5168\u90E8\u5408\u6CD5`);return}this.logger.info(`\u73AF\u5883\u53D8\u91CF\u6821\u9A8C\u7ED3\u679C: \u603B\u8BA1 ${u} | \u901A\u8FC7 ${r} | \u7F3A\u5931 ${e} | \u5931\u8D25 ${s}`);const a=this.validationResults.filter(n=>n.status!=="pass");for(const n of a){const l=n.status==="missing"?"\u7F3A\u5931":"\u5931\u8D25";this.logger.warn(` [${l}] ${n.key}: ${n.message}`)}}injectRuntimeGuard(u){const r=b(this.options.required,this.options.runtimeGlobalName,this.options.runtimeGuardMode,this.validationResults);if(!r)return u;const e=E(u,"</head>",r);return e.injected?e.html:(this.logger.warn("\u672A\u627E\u5230 </head> \u6807\u7B7E\uFF0C\u8FD0\u884C\u65F6\u5B88\u536B\u4EE3\u7801\u672A\u80FD\u6CE8\u5165"),u)}getResult(){return this.guardResult}getValidationResults(){return[...this.validationResults]}}const O=v(x);export{O as envGuard};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const factory_index=require("../../factory/index.cjs"),common_fs_index=require("../../common/fs/index.cjs"),validator=require("../../shared/vite-plugin.Bcg6RW2N.cjs"),common_html_index=require("../../common/html/index.cjs");require("../../logger/index.cjs"),require("
|
|
1
|
+
"use strict";const factory_index=require("../../factory/index.cjs"),common_fs_index=require("../../common/fs/index.cjs"),validator=require("../../shared/vite-plugin.Bcg6RW2N.cjs"),common_html_index=require("../../common/html/index.cjs");require("../../logger/index.cjs"),require("fs"),require("path"),require("../../shared/vite-plugin.CnOy46d3.cjs");function generateIconTagDescriptors(u){const i=[];if(u.link)return[];if(u.icons&&u.icons.length>0)for(const e of u.icons){const t={rel:e.rel,href:e.href};e.sizes&&(t.sizes=e.sizes),e.type&&(t.type=e.type),i.push({tag:"link",attrs:t,injectTo:"head"})}else if(u.url)i.push({tag:"link",attrs:{rel:"icon",href:u.url},injectTo:"head"});else{const e=u.base||"/",t=e.endsWith("/")?`${e}favicon.ico`:`${e}/favicon.ico`;i.push({tag:"link",attrs:{rel:"icon",href:t},injectTo:"head"})}return i}class f extends factory_index.BasePlugin{getDefaultOptions(){return{base:"/"}}validateOptions(){this.validator.field("base").string().field("url").string().field("link").string().field("icons").array(),this.options?.copyOptions&&(this.validator.field("copyOptions").object(),new validator.Validator(this.options.copyOptions).field("sourceDir").required().string().field("targetDir").required().string().field("overwrite").boolean().field("recursive").boolean().validate()),this.validator.validate()}getPluginName(){return"favicon-manager"}getIconTagDescriptors(){if(!this.options.enabled)return this.logger.info("\u63D2\u4EF6\u5DF2\u7981\u7528\uFF0C\u8DF3\u8FC7\u56FE\u6807\u6CE8\u5165"),[];const i=generateIconTagDescriptors(this.options);return i.length>0&&this.logger.success(`\u6210\u529F\u6CE8\u5165 ${i.length} \u4E2A\u56FE\u6807\u6807\u7B7E\u5230 HTML \u6587\u4EF6`),i}injectCustomLinkTag(i){if(!this.options.enabled||!this.options.link)return i;const e=this.options.link,t=common_html_index.injectBeforeTag(i,"</head>",e);return t.injected?(this.logger.success("\u6210\u529F\u6CE8\u5165\u81EA\u5B9A\u4E49\u56FE\u6807\u6807\u7B7E\u5230 HTML \u6587\u4EF6"),this.logger.info(` - ${e}`),t.html):(this.logger.warn("\u672A\u627E\u5230 </head> \u6807\u7B7E\uFF0C\u8DF3\u8FC7\u56FE\u6807\u6CE8\u5165"),i)}async copyFiles(){if(!this.options.enabled){this.logger.info("\u63D2\u4EF6\u5DF2\u7981\u7528\uFF0C\u8DF3\u8FC7\u6587\u4EF6\u590D\u5236");return}const{copyOptions:i}=this.options;if(!i)return;const{sourceDir:e,targetDir:t,overwrite:r=!0,recursive:n=!0}=i;await common_fs_index.checkSourceExists(e);const s=await common_fs_index.copySourceToTarget(e,t,{recursive:n,overwrite:r,incremental:!0});this.logger.success(`\u56FE\u6807\u6587\u4EF6\u590D\u5236\u6210\u529F\uFF1A\u4ECE ${e} \u5230 ${t}`,`\u590D\u5236\u4E86 ${s.copiedFiles} \u4E2A\u6587\u4EF6\uFF0C\u8DF3\u8FC7\u4E86 ${s.skippedFiles} \u4E2A\u6587\u4EF6\uFF0C\u8017\u65F6 ${s.executionTime}ms`)}addPluginHooks(i){i.transformIndexHtml={order:"pre",handler:e=>{if(this.options.link)return this.injectCustomLinkTag(e);const t=this.getIconTagDescriptors();return t.length>0?{html:e,tags:t}:e}},i.writeBundle=async()=>{await this.safeExecute(()=>this.copyFiles(),"\u56FE\u6807\u6587\u4EF6\u590D\u5236")}}}const faviconManager=factory_index.createPluginFactory(f,u=>typeof u=="string"?{base:u}:u||{});exports.faviconManager=faviconManager;
|
|
@@ -1,28 +1,42 @@
|
|
|
1
1
|
import { BasePluginOptions, PluginFactory } from '../../factory/index.cjs';
|
|
2
2
|
import 'vite';
|
|
3
|
-
import '../../shared/vite-plugin.
|
|
3
|
+
import '../../shared/vite-plugin.B8FuZce1.cjs';
|
|
4
4
|
import '../../shared/vite-plugin.DRRlWY8P.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* 图标配置项接口
|
|
8
8
|
*
|
|
9
9
|
* @interface Icon
|
|
10
|
+
* @description 定义单个网站图标的属性,对应 HTML `<link>` 标签的各个属性。
|
|
10
11
|
*/
|
|
11
12
|
interface Icon {
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
+
* 图标关系类型,对应 `<link>` 标签的 `rel` 属性
|
|
15
|
+
*
|
|
16
|
+
* @example 'icon'
|
|
17
|
+
* @example 'apple-touch-icon'
|
|
18
|
+
* @example 'manifest'
|
|
14
19
|
*/
|
|
15
20
|
rel: string;
|
|
16
21
|
/**
|
|
17
|
-
* 图标 URL
|
|
22
|
+
* 图标 URL,对应 `<link>` 标签的 `href` 属性
|
|
23
|
+
*
|
|
24
|
+
* @example '/favicon.ico'
|
|
25
|
+
* @example '/apple-touch-icon.png'
|
|
18
26
|
*/
|
|
19
27
|
href: string;
|
|
20
28
|
/**
|
|
21
|
-
*
|
|
29
|
+
* 图标尺寸,对应 `<link>` 标签的 `sizes` 属性
|
|
30
|
+
*
|
|
31
|
+
* @example '32x32'
|
|
32
|
+
* @example '180x180'
|
|
22
33
|
*/
|
|
23
34
|
sizes?: string;
|
|
24
35
|
/**
|
|
25
|
-
* 图标 MIME
|
|
36
|
+
* 图标 MIME 类型,对应 `<link>` 标签的 `type` 属性
|
|
37
|
+
*
|
|
38
|
+
* @example 'image/png'
|
|
39
|
+
* @example 'image/svg+xml'
|
|
26
40
|
*/
|
|
27
41
|
type?: string;
|
|
28
42
|
}
|
|
@@ -30,6 +44,8 @@ interface Icon {
|
|
|
30
44
|
* 图标文件复制配置选项接口
|
|
31
45
|
*
|
|
32
46
|
* @interface CopyOptions
|
|
47
|
+
* @description 配置图标文件从源目录到构建输出目录的复制行为,
|
|
48
|
+
* 仅当此对象存在时才开启图标文件复制功能。
|
|
33
49
|
*/
|
|
34
50
|
interface CopyOptions {
|
|
35
51
|
/**
|
|
@@ -51,7 +67,7 @@ interface CopyOptions {
|
|
|
51
67
|
*/
|
|
52
68
|
overwrite?: boolean;
|
|
53
69
|
/**
|
|
54
|
-
*
|
|
70
|
+
* 是否支持递归复制子目录
|
|
55
71
|
*
|
|
56
72
|
* @default true
|
|
57
73
|
*/
|
|
@@ -61,6 +77,28 @@ interface CopyOptions {
|
|
|
61
77
|
* 网站图标管理插件的配置选项接口
|
|
62
78
|
*
|
|
63
79
|
* @interface FaviconManagerOptions
|
|
80
|
+
* @extends {BasePluginOptions}
|
|
81
|
+
*
|
|
82
|
+
* @description 支持三种图标配置方式(优先级从高到低):
|
|
83
|
+
* 1. `link` - 自定义完整的 `<link>` 标签 HTML
|
|
84
|
+
* 2. `url` - 完整的图标 URL
|
|
85
|
+
* 3. `base` + 默认 favicon.ico - 基础路径拼接
|
|
86
|
+
* 此外还支持通过 `icons` 数组配置多个图标,以及通过 `copyOptions` 复制图标文件。
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* faviconManager({
|
|
91
|
+
* base: '/assets',
|
|
92
|
+
* icons: [
|
|
93
|
+
* { rel: 'icon', href: '/favicon.svg', type: 'image/svg+xml' },
|
|
94
|
+
* { rel: 'icon', href: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' }
|
|
95
|
+
* ],
|
|
96
|
+
* copyOptions: {
|
|
97
|
+
* sourceDir: 'src/assets/icons',
|
|
98
|
+
* targetDir: 'dist/assets/icons'
|
|
99
|
+
* }
|
|
100
|
+
* })
|
|
101
|
+
* ```
|
|
64
102
|
*/
|
|
65
103
|
interface FaviconManagerOptions extends BasePluginOptions {
|
|
66
104
|
/**
|
|
@@ -1,28 +1,42 @@
|
|
|
1
1
|
import { BasePluginOptions, PluginFactory } from '../../factory/index.mjs';
|
|
2
2
|
import 'vite';
|
|
3
|
-
import '../../shared/vite-plugin.
|
|
3
|
+
import '../../shared/vite-plugin.B8FuZce1.mjs';
|
|
4
4
|
import '../../shared/vite-plugin.DRRlWY8P.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* 图标配置项接口
|
|
8
8
|
*
|
|
9
9
|
* @interface Icon
|
|
10
|
+
* @description 定义单个网站图标的属性,对应 HTML `<link>` 标签的各个属性。
|
|
10
11
|
*/
|
|
11
12
|
interface Icon {
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
+
* 图标关系类型,对应 `<link>` 标签的 `rel` 属性
|
|
15
|
+
*
|
|
16
|
+
* @example 'icon'
|
|
17
|
+
* @example 'apple-touch-icon'
|
|
18
|
+
* @example 'manifest'
|
|
14
19
|
*/
|
|
15
20
|
rel: string;
|
|
16
21
|
/**
|
|
17
|
-
* 图标 URL
|
|
22
|
+
* 图标 URL,对应 `<link>` 标签的 `href` 属性
|
|
23
|
+
*
|
|
24
|
+
* @example '/favicon.ico'
|
|
25
|
+
* @example '/apple-touch-icon.png'
|
|
18
26
|
*/
|
|
19
27
|
href: string;
|
|
20
28
|
/**
|
|
21
|
-
*
|
|
29
|
+
* 图标尺寸,对应 `<link>` 标签的 `sizes` 属性
|
|
30
|
+
*
|
|
31
|
+
* @example '32x32'
|
|
32
|
+
* @example '180x180'
|
|
22
33
|
*/
|
|
23
34
|
sizes?: string;
|
|
24
35
|
/**
|
|
25
|
-
* 图标 MIME
|
|
36
|
+
* 图标 MIME 类型,对应 `<link>` 标签的 `type` 属性
|
|
37
|
+
*
|
|
38
|
+
* @example 'image/png'
|
|
39
|
+
* @example 'image/svg+xml'
|
|
26
40
|
*/
|
|
27
41
|
type?: string;
|
|
28
42
|
}
|
|
@@ -30,6 +44,8 @@ interface Icon {
|
|
|
30
44
|
* 图标文件复制配置选项接口
|
|
31
45
|
*
|
|
32
46
|
* @interface CopyOptions
|
|
47
|
+
* @description 配置图标文件从源目录到构建输出目录的复制行为,
|
|
48
|
+
* 仅当此对象存在时才开启图标文件复制功能。
|
|
33
49
|
*/
|
|
34
50
|
interface CopyOptions {
|
|
35
51
|
/**
|
|
@@ -51,7 +67,7 @@ interface CopyOptions {
|
|
|
51
67
|
*/
|
|
52
68
|
overwrite?: boolean;
|
|
53
69
|
/**
|
|
54
|
-
*
|
|
70
|
+
* 是否支持递归复制子目录
|
|
55
71
|
*
|
|
56
72
|
* @default true
|
|
57
73
|
*/
|
|
@@ -61,6 +77,28 @@ interface CopyOptions {
|
|
|
61
77
|
* 网站图标管理插件的配置选项接口
|
|
62
78
|
*
|
|
63
79
|
* @interface FaviconManagerOptions
|
|
80
|
+
* @extends {BasePluginOptions}
|
|
81
|
+
*
|
|
82
|
+
* @description 支持三种图标配置方式(优先级从高到低):
|
|
83
|
+
* 1. `link` - 自定义完整的 `<link>` 标签 HTML
|
|
84
|
+
* 2. `url` - 完整的图标 URL
|
|
85
|
+
* 3. `base` + 默认 favicon.ico - 基础路径拼接
|
|
86
|
+
* 此外还支持通过 `icons` 数组配置多个图标,以及通过 `copyOptions` 复制图标文件。
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* faviconManager({
|
|
91
|
+
* base: '/assets',
|
|
92
|
+
* icons: [
|
|
93
|
+
* { rel: 'icon', href: '/favicon.svg', type: 'image/svg+xml' },
|
|
94
|
+
* { rel: 'icon', href: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' }
|
|
95
|
+
* ],
|
|
96
|
+
* copyOptions: {
|
|
97
|
+
* sourceDir: 'src/assets/icons',
|
|
98
|
+
* targetDir: 'dist/assets/icons'
|
|
99
|
+
* }
|
|
100
|
+
* })
|
|
101
|
+
* ```
|
|
64
102
|
*/
|
|
65
103
|
interface FaviconManagerOptions extends BasePluginOptions {
|
|
66
104
|
/**
|
|
@@ -1,28 +1,42 @@
|
|
|
1
1
|
import { BasePluginOptions, PluginFactory } from '../../factory/index.js';
|
|
2
2
|
import 'vite';
|
|
3
|
-
import '../../shared/vite-plugin.
|
|
3
|
+
import '../../shared/vite-plugin.B8FuZce1.js';
|
|
4
4
|
import '../../shared/vite-plugin.DRRlWY8P.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* 图标配置项接口
|
|
8
8
|
*
|
|
9
9
|
* @interface Icon
|
|
10
|
+
* @description 定义单个网站图标的属性,对应 HTML `<link>` 标签的各个属性。
|
|
10
11
|
*/
|
|
11
12
|
interface Icon {
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
+
* 图标关系类型,对应 `<link>` 标签的 `rel` 属性
|
|
15
|
+
*
|
|
16
|
+
* @example 'icon'
|
|
17
|
+
* @example 'apple-touch-icon'
|
|
18
|
+
* @example 'manifest'
|
|
14
19
|
*/
|
|
15
20
|
rel: string;
|
|
16
21
|
/**
|
|
17
|
-
* 图标 URL
|
|
22
|
+
* 图标 URL,对应 `<link>` 标签的 `href` 属性
|
|
23
|
+
*
|
|
24
|
+
* @example '/favicon.ico'
|
|
25
|
+
* @example '/apple-touch-icon.png'
|
|
18
26
|
*/
|
|
19
27
|
href: string;
|
|
20
28
|
/**
|
|
21
|
-
*
|
|
29
|
+
* 图标尺寸,对应 `<link>` 标签的 `sizes` 属性
|
|
30
|
+
*
|
|
31
|
+
* @example '32x32'
|
|
32
|
+
* @example '180x180'
|
|
22
33
|
*/
|
|
23
34
|
sizes?: string;
|
|
24
35
|
/**
|
|
25
|
-
* 图标 MIME
|
|
36
|
+
* 图标 MIME 类型,对应 `<link>` 标签的 `type` 属性
|
|
37
|
+
*
|
|
38
|
+
* @example 'image/png'
|
|
39
|
+
* @example 'image/svg+xml'
|
|
26
40
|
*/
|
|
27
41
|
type?: string;
|
|
28
42
|
}
|
|
@@ -30,6 +44,8 @@ interface Icon {
|
|
|
30
44
|
* 图标文件复制配置选项接口
|
|
31
45
|
*
|
|
32
46
|
* @interface CopyOptions
|
|
47
|
+
* @description 配置图标文件从源目录到构建输出目录的复制行为,
|
|
48
|
+
* 仅当此对象存在时才开启图标文件复制功能。
|
|
33
49
|
*/
|
|
34
50
|
interface CopyOptions {
|
|
35
51
|
/**
|
|
@@ -51,7 +67,7 @@ interface CopyOptions {
|
|
|
51
67
|
*/
|
|
52
68
|
overwrite?: boolean;
|
|
53
69
|
/**
|
|
54
|
-
*
|
|
70
|
+
* 是否支持递归复制子目录
|
|
55
71
|
*
|
|
56
72
|
* @default true
|
|
57
73
|
*/
|
|
@@ -61,6 +77,28 @@ interface CopyOptions {
|
|
|
61
77
|
* 网站图标管理插件的配置选项接口
|
|
62
78
|
*
|
|
63
79
|
* @interface FaviconManagerOptions
|
|
80
|
+
* @extends {BasePluginOptions}
|
|
81
|
+
*
|
|
82
|
+
* @description 支持三种图标配置方式(优先级从高到低):
|
|
83
|
+
* 1. `link` - 自定义完整的 `<link>` 标签 HTML
|
|
84
|
+
* 2. `url` - 完整的图标 URL
|
|
85
|
+
* 3. `base` + 默认 favicon.ico - 基础路径拼接
|
|
86
|
+
* 此外还支持通过 `icons` 数组配置多个图标,以及通过 `copyOptions` 复制图标文件。
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* faviconManager({
|
|
91
|
+
* base: '/assets',
|
|
92
|
+
* icons: [
|
|
93
|
+
* { rel: 'icon', href: '/favicon.svg', type: 'image/svg+xml' },
|
|
94
|
+
* { rel: 'icon', href: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' }
|
|
95
|
+
* ],
|
|
96
|
+
* copyOptions: {
|
|
97
|
+
* sourceDir: 'src/assets/icons',
|
|
98
|
+
* targetDir: 'dist/assets/icons'
|
|
99
|
+
* }
|
|
100
|
+
* })
|
|
101
|
+
* ```
|
|
64
102
|
*/
|
|
65
103
|
interface FaviconManagerOptions extends BasePluginOptions {
|
|
66
104
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createPluginFactory as n,BasePlugin as a}from"../../factory/index.mjs";import{checkSourceExists as c,copySourceToTarget as l}from"../../common/fs/index.mjs";import{V as g}from"../../shared/vite-plugin.DcExl6jd.mjs";import{injectBeforeTag as p}from"../../common/html/index.mjs";import"../../logger/index.mjs";import"
|
|
1
|
+
import{createPluginFactory as n,BasePlugin as a}from"../../factory/index.mjs";import{checkSourceExists as c,copySourceToTarget as l}from"../../common/fs/index.mjs";import{V as g}from"../../shared/vite-plugin.DcExl6jd.mjs";import{injectBeforeTag as p}from"../../common/html/index.mjs";import"../../logger/index.mjs";import"fs";import"path";import"../../shared/vite-plugin.BPFqtmWa.mjs";function F(u){const i=[];if(u.link)return[];if(u.icons&&u.icons.length>0)for(const e of u.icons){const t={rel:e.rel,href:e.href};e.sizes&&(t.sizes=e.sizes),e.type&&(t.type=e.type),i.push({tag:"link",attrs:t,injectTo:"head"})}else if(u.url)i.push({tag:"link",attrs:{rel:"icon",href:u.url},injectTo:"head"});else{const e=u.base||"/",t=e.endsWith("/")?`${e}favicon.ico`:`${e}/favicon.ico`;i.push({tag:"link",attrs:{rel:"icon",href:t},injectTo:"head"})}return i}class h extends a{getDefaultOptions(){return{base:"/"}}validateOptions(){this.validator.field("base").string().field("url").string().field("link").string().field("icons").array(),this.options?.copyOptions&&(this.validator.field("copyOptions").object(),new g(this.options.copyOptions).field("sourceDir").required().string().field("targetDir").required().string().field("overwrite").boolean().field("recursive").boolean().validate()),this.validator.validate()}getPluginName(){return"favicon-manager"}getIconTagDescriptors(){if(!this.options.enabled)return this.logger.info("\u63D2\u4EF6\u5DF2\u7981\u7528\uFF0C\u8DF3\u8FC7\u56FE\u6807\u6CE8\u5165"),[];const i=F(this.options);return i.length>0&&this.logger.success(`\u6210\u529F\u6CE8\u5165 ${i.length} \u4E2A\u56FE\u6807\u6807\u7B7E\u5230 HTML \u6587\u4EF6`),i}injectCustomLinkTag(i){if(!this.options.enabled||!this.options.link)return i;const e=this.options.link,t=p(i,"</head>",e);return t.injected?(this.logger.success("\u6210\u529F\u6CE8\u5165\u81EA\u5B9A\u4E49\u56FE\u6807\u6807\u7B7E\u5230 HTML \u6587\u4EF6"),this.logger.info(` - ${e}`),t.html):(this.logger.warn("\u672A\u627E\u5230 </head> \u6807\u7B7E\uFF0C\u8DF3\u8FC7\u56FE\u6807\u6CE8\u5165"),i)}async copyFiles(){if(!this.options.enabled){this.logger.info("\u63D2\u4EF6\u5DF2\u7981\u7528\uFF0C\u8DF3\u8FC7\u6587\u4EF6\u590D\u5236");return}const{copyOptions:i}=this.options;if(!i)return;const{sourceDir:e,targetDir:t,overwrite:s=!0,recursive:o=!0}=i;await c(e);const r=await l(e,t,{recursive:o,overwrite:s,incremental:!0});this.logger.success(`\u56FE\u6807\u6587\u4EF6\u590D\u5236\u6210\u529F\uFF1A\u4ECE ${e} \u5230 ${t}`,`\u590D\u5236\u4E86 ${r.copiedFiles} \u4E2A\u6587\u4EF6\uFF0C\u8DF3\u8FC7\u4E86 ${r.skippedFiles} \u4E2A\u6587\u4EF6\uFF0C\u8017\u65F6 ${r.executionTime}ms`)}addPluginHooks(i){i.transformIndexHtml={order:"pre",handler:e=>{if(this.options.link)return this.injectCustomLinkTag(e);const t=this.getIconTagDescriptors();return t.length>0?{html:e,tags:t}:e}},i.writeBundle=async()=>{await this.safeExecute(()=>this.copyFiles(),"\u56FE\u6807\u6587\u4EF6\u590D\u5236")}}}const f=n(h,u=>typeof u=="string"?{base:u}:u||{});export{f as faviconManager};
|