@meng-xi/vite-plugin 0.1.3 → 0.1.4
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 +48 -774
- package/README.md +45 -769
- package/dist/common/html/index.cjs +2 -2
- package/dist/common/html/index.d.cts +268 -19
- package/dist/common/html/index.d.mts +268 -19
- package/dist/common/html/index.d.ts +268 -19
- package/dist/common/html/index.mjs +2 -2
- package/dist/common/index.cjs +1 -1
- package/dist/common/index.d.cts +4 -1
- package/dist/common/index.d.mts +4 -1
- package/dist/common/index.d.ts +4 -1
- package/dist/common/index.mjs +1 -1
- package/dist/common/ui/index.cjs +1 -0
- package/dist/common/ui/index.d.cts +132 -0
- package/dist/common/ui/index.d.mts +132 -0
- package/dist/common/ui/index.d.ts +132 -0
- package/dist/common/ui/index.mjs +1 -0
- package/dist/common/validation/index.cjs +1 -1
- package/dist/common/validation/index.d.cts +1 -0
- package/dist/common/validation/index.d.mts +1 -0
- package/dist/common/validation/index.d.ts +1 -0
- package/dist/common/validation/index.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.mts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.mjs +1 -1
- package/dist/plugins/buildProgress/index.cjs +2 -2
- package/dist/plugins/buildProgress/index.mjs +2 -2
- package/dist/plugins/copyFile/index.d.cts +20 -2
- package/dist/plugins/copyFile/index.d.mts +20 -2
- package/dist/plugins/copyFile/index.d.ts +20 -2
- package/dist/plugins/envGuard/index.cjs +67 -0
- package/dist/plugins/envGuard/index.d.cts +156 -0
- package/dist/plugins/envGuard/index.d.mts +156 -0
- package/dist/plugins/envGuard/index.d.ts +156 -0
- package/dist/plugins/envGuard/index.mjs +67 -0
- package/dist/plugins/faviconManager/index.cjs +1 -1
- package/dist/plugins/faviconManager/index.d.cts +43 -5
- package/dist/plugins/faviconManager/index.d.mts +43 -5
- package/dist/plugins/faviconManager/index.d.ts +43 -5
- package/dist/plugins/faviconManager/index.mjs +1 -1
- package/dist/plugins/generateRouter/index.d.cts +61 -14
- package/dist/plugins/generateRouter/index.d.mts +61 -14
- package/dist/plugins/generateRouter/index.d.ts +61 -14
- package/dist/plugins/generateVersion/index.d.cts +12 -0
- package/dist/plugins/generateVersion/index.d.mts +12 -0
- package/dist/plugins/generateVersion/index.d.ts +12 -0
- package/dist/plugins/htmlInject/index.cjs +1 -7
- package/dist/plugins/htmlInject/index.d.cts +49 -194
- package/dist/plugins/htmlInject/index.d.mts +49 -194
- package/dist/plugins/htmlInject/index.d.ts +49 -194
- package/dist/plugins/htmlInject/index.mjs +1 -7
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.d.cts +4 -1
- package/dist/plugins/index.d.mts +4 -1
- package/dist/plugins/index.d.ts +4 -1
- package/dist/plugins/index.mjs +1 -1
- package/dist/plugins/loadingManager/index.cjs +2 -2
- package/dist/plugins/loadingManager/index.mjs +1 -1
- package/dist/plugins/versionUpdateChecker/index.cjs +2 -2
- package/dist/plugins/versionUpdateChecker/index.mjs +3 -3
- package/dist/shared/vite-plugin.BCuhU1au.mjs +7 -0
- package/dist/shared/vite-plugin.BrI73DHA.cjs +7 -0
- package/dist/shared/vite-plugin.CmtcnItg.d.cts +261 -0
- package/dist/shared/vite-plugin.CmtcnItg.d.mts +261 -0
- package/dist/shared/vite-plugin.CmtcnItg.d.ts +261 -0
- package/dist/shared/vite-plugin.DnFDPjNf.mjs +1 -0
- package/dist/shared/vite-plugin.Dumot0up.mjs +1 -0
- package/dist/shared/vite-plugin.FfJ-Wwfu.d.cts +143 -0
- package/dist/shared/vite-plugin.FfJ-Wwfu.d.mts +143 -0
- package/dist/shared/vite-plugin.FfJ-Wwfu.d.ts +143 -0
- package/dist/shared/vite-plugin.soT9a-KD.cjs +1 -0
- package/dist/shared/vite-plugin.vwox4bU0.cjs +1 -0
- package/package.json +11 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { BasePluginOptions, PluginFactory } from '../../factory/index.cjs';
|
|
2
|
+
import { E as EnvFieldRule, b as EnvValidationResult } from '../../shared/vite-plugin.CmtcnItg.cjs';
|
|
3
|
+
import 'vite';
|
|
4
|
+
import '../../shared/vite-plugin.CLr0ttuO.cjs';
|
|
5
|
+
import '../../shared/vite-plugin.DRRlWY8P.cjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 环境变量校验失败时的处理动作
|
|
9
|
+
*
|
|
10
|
+
* @description 定义当环境变量校验未通过时的处理策略:
|
|
11
|
+
* - `error`: 抛出错误,中断构建流程
|
|
12
|
+
* - `warn`: 输出警告日志,继续构建
|
|
13
|
+
* - `ignore`: 静默忽略,不输出任何信息
|
|
14
|
+
*/
|
|
15
|
+
type EnvFailAction = 'error' | 'warn' | 'ignore';
|
|
16
|
+
/**
|
|
17
|
+
* 运行时守卫的行为模式
|
|
18
|
+
*
|
|
19
|
+
* @description 定义注入到 HTML 中的运行时守卫代码在检测到
|
|
20
|
+
* 环境变量缺失或无效时的行为方式:
|
|
21
|
+
* - `console`: 在浏览器控制台输出警告信息
|
|
22
|
+
* - `throw`: 抛出运行时错误,阻止应用启动
|
|
23
|
+
* - `overlay`: 在页面顶部显示警告横幅
|
|
24
|
+
*/
|
|
25
|
+
type RuntimeGuardMode = 'console' | 'throw' | 'overlay';
|
|
26
|
+
/**
|
|
27
|
+
* 环境变量校验结果汇总
|
|
28
|
+
*
|
|
29
|
+
* @interface EnvGuardResult
|
|
30
|
+
* @description 包含所有环境变量的校验统计信息和详细结果列表,
|
|
31
|
+
* 用于报告生成和日志输出。
|
|
32
|
+
*/
|
|
33
|
+
interface EnvGuardResult {
|
|
34
|
+
/** 校验时间戳(ISO 格式) */
|
|
35
|
+
timestamp: string;
|
|
36
|
+
/** 校验的环境变量总数 */
|
|
37
|
+
total: number;
|
|
38
|
+
/** 校验通过的变量数量 */
|
|
39
|
+
passed: number;
|
|
40
|
+
/** 缺失的必需变量数量 */
|
|
41
|
+
missing: number;
|
|
42
|
+
/** 校验失败的变量数量(类型不匹配、范围越界等) */
|
|
43
|
+
invalid: number;
|
|
44
|
+
/** 所有变量的详细校验结果列表 */
|
|
45
|
+
results: EnvValidationResult[];
|
|
46
|
+
/** 是否所有变量均校验通过 */
|
|
47
|
+
allPassed: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 环境变量守卫插件的配置选项
|
|
51
|
+
*
|
|
52
|
+
* @interface EnvGuardOptions
|
|
53
|
+
* @extends {BasePluginOptions}
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* envGuard({
|
|
58
|
+
* required: {
|
|
59
|
+
* VITE_API_URL: { type: 'url', required: true },
|
|
60
|
+
* VITE_APP_TITLE: { type: 'string', minLength: 1, maxLength: 50 }
|
|
61
|
+
* },
|
|
62
|
+
* failAction: 'error',
|
|
63
|
+
* generateTemplate: true,
|
|
64
|
+
* runtimeGuard: true,
|
|
65
|
+
* runtimeGuardMode: 'console'
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
interface EnvGuardOptions extends BasePluginOptions {
|
|
70
|
+
/** 环境变量校验规则映射,键为变量名,值为校验规则 */
|
|
71
|
+
required?: Record<string, EnvFieldRule>;
|
|
72
|
+
/** 校验失败时的处理动作 */
|
|
73
|
+
failAction?: EnvFailAction;
|
|
74
|
+
/** 是否自动生成 .env 模板文件 */
|
|
75
|
+
generateTemplate?: boolean;
|
|
76
|
+
/** .env 模板文件的输出路径 */
|
|
77
|
+
templateOutput?: string;
|
|
78
|
+
/** 是否注入运行时环境变量守卫代码到 HTML */
|
|
79
|
+
runtimeGuard?: boolean;
|
|
80
|
+
/** 运行时守卫的全局变量名 */
|
|
81
|
+
runtimeGlobalName?: string;
|
|
82
|
+
/** 运行时守卫的行为模式 */
|
|
83
|
+
runtimeGuardMode?: RuntimeGuardMode;
|
|
84
|
+
/** 需要加载的 .env 文件路径列表 */
|
|
85
|
+
envFiles?: string[];
|
|
86
|
+
/** 是否自动加载 .env 文件中的变量到 process.env */
|
|
87
|
+
autoLoadEnv?: boolean;
|
|
88
|
+
/** 校验报告输出路径,设为 false 则不生成报告 */
|
|
89
|
+
reportOutput?: string | false;
|
|
90
|
+
/** 是否在构建前执行校验 */
|
|
91
|
+
validateBeforeBuild?: boolean;
|
|
92
|
+
/** 是否输出校验摘要日志 */
|
|
93
|
+
showSummary?: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 创建环境变量守卫插件
|
|
98
|
+
*
|
|
99
|
+
* @function envGuard
|
|
100
|
+
* @param {Partial<EnvGuardOptions>} [options] - 插件配置选项
|
|
101
|
+
* @returns {Plugin} Vite 插件实例
|
|
102
|
+
*
|
|
103
|
+
* @description 在 Vite 构建前校验环境变量的存在性和合法性,
|
|
104
|
+
* 支持多种值类型校验、正则匹配、自定义校验函数等,
|
|
105
|
+
* 可选生成 .env 模板文件和注入运行时守卫代码。
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* // vite.config.ts
|
|
110
|
+
* import { envGuard } from '@meng-xi/vite-plugin'
|
|
111
|
+
*
|
|
112
|
+
* export default defineConfig({
|
|
113
|
+
* plugins: [
|
|
114
|
+
* envGuard({
|
|
115
|
+
* required: {
|
|
116
|
+
* VITE_API_BASE_URL: {
|
|
117
|
+
* type: 'url',
|
|
118
|
+
* required: true,
|
|
119
|
+
* message: 'API 基础地址必须为合法 URL'
|
|
120
|
+
* },
|
|
121
|
+
* VITE_APP_TITLE: {
|
|
122
|
+
* type: 'string',
|
|
123
|
+
* required: true,
|
|
124
|
+
* minLength: 1,
|
|
125
|
+
* maxLength: 50
|
|
126
|
+
* },
|
|
127
|
+
* VITE_ENABLE_ANALYTICS: {
|
|
128
|
+
* type: 'boolean',
|
|
129
|
+
* required: false,
|
|
130
|
+
* default: 'false'
|
|
131
|
+
* },
|
|
132
|
+
* VITE_API_TIMEOUT: {
|
|
133
|
+
* type: 'number',
|
|
134
|
+
* minValue: 1000,
|
|
135
|
+
* maxValue: 60000,
|
|
136
|
+
* message: 'API 超时时间必须在 1000-60000ms 之间'
|
|
137
|
+
* },
|
|
138
|
+
* VITE_LOG_LEVEL: {
|
|
139
|
+
* type: 'enum',
|
|
140
|
+
* enumValues: ['debug', 'info', 'warn', 'error'],
|
|
141
|
+
* default: 'info'
|
|
142
|
+
* }
|
|
143
|
+
* },
|
|
144
|
+
* failAction: 'error',
|
|
145
|
+
* generateTemplate: true,
|
|
146
|
+
* runtimeGuard: true,
|
|
147
|
+
* runtimeGuardMode: 'console'
|
|
148
|
+
* })
|
|
149
|
+
* ]
|
|
150
|
+
* })
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
declare const envGuard: PluginFactory<EnvGuardOptions, EnvGuardOptions>;
|
|
154
|
+
|
|
155
|
+
export { envGuard };
|
|
156
|
+
export type { EnvFailAction, EnvGuardOptions, EnvGuardResult, RuntimeGuardMode };
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { BasePluginOptions, PluginFactory } from '../../factory/index.mjs';
|
|
2
|
+
import { E as EnvFieldRule, b as EnvValidationResult } from '../../shared/vite-plugin.CmtcnItg.mjs';
|
|
3
|
+
import 'vite';
|
|
4
|
+
import '../../shared/vite-plugin.CLr0ttuO.mjs';
|
|
5
|
+
import '../../shared/vite-plugin.DRRlWY8P.mjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 环境变量校验失败时的处理动作
|
|
9
|
+
*
|
|
10
|
+
* @description 定义当环境变量校验未通过时的处理策略:
|
|
11
|
+
* - `error`: 抛出错误,中断构建流程
|
|
12
|
+
* - `warn`: 输出警告日志,继续构建
|
|
13
|
+
* - `ignore`: 静默忽略,不输出任何信息
|
|
14
|
+
*/
|
|
15
|
+
type EnvFailAction = 'error' | 'warn' | 'ignore';
|
|
16
|
+
/**
|
|
17
|
+
* 运行时守卫的行为模式
|
|
18
|
+
*
|
|
19
|
+
* @description 定义注入到 HTML 中的运行时守卫代码在检测到
|
|
20
|
+
* 环境变量缺失或无效时的行为方式:
|
|
21
|
+
* - `console`: 在浏览器控制台输出警告信息
|
|
22
|
+
* - `throw`: 抛出运行时错误,阻止应用启动
|
|
23
|
+
* - `overlay`: 在页面顶部显示警告横幅
|
|
24
|
+
*/
|
|
25
|
+
type RuntimeGuardMode = 'console' | 'throw' | 'overlay';
|
|
26
|
+
/**
|
|
27
|
+
* 环境变量校验结果汇总
|
|
28
|
+
*
|
|
29
|
+
* @interface EnvGuardResult
|
|
30
|
+
* @description 包含所有环境变量的校验统计信息和详细结果列表,
|
|
31
|
+
* 用于报告生成和日志输出。
|
|
32
|
+
*/
|
|
33
|
+
interface EnvGuardResult {
|
|
34
|
+
/** 校验时间戳(ISO 格式) */
|
|
35
|
+
timestamp: string;
|
|
36
|
+
/** 校验的环境变量总数 */
|
|
37
|
+
total: number;
|
|
38
|
+
/** 校验通过的变量数量 */
|
|
39
|
+
passed: number;
|
|
40
|
+
/** 缺失的必需变量数量 */
|
|
41
|
+
missing: number;
|
|
42
|
+
/** 校验失败的变量数量(类型不匹配、范围越界等) */
|
|
43
|
+
invalid: number;
|
|
44
|
+
/** 所有变量的详细校验结果列表 */
|
|
45
|
+
results: EnvValidationResult[];
|
|
46
|
+
/** 是否所有变量均校验通过 */
|
|
47
|
+
allPassed: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 环境变量守卫插件的配置选项
|
|
51
|
+
*
|
|
52
|
+
* @interface EnvGuardOptions
|
|
53
|
+
* @extends {BasePluginOptions}
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* envGuard({
|
|
58
|
+
* required: {
|
|
59
|
+
* VITE_API_URL: { type: 'url', required: true },
|
|
60
|
+
* VITE_APP_TITLE: { type: 'string', minLength: 1, maxLength: 50 }
|
|
61
|
+
* },
|
|
62
|
+
* failAction: 'error',
|
|
63
|
+
* generateTemplate: true,
|
|
64
|
+
* runtimeGuard: true,
|
|
65
|
+
* runtimeGuardMode: 'console'
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
interface EnvGuardOptions extends BasePluginOptions {
|
|
70
|
+
/** 环境变量校验规则映射,键为变量名,值为校验规则 */
|
|
71
|
+
required?: Record<string, EnvFieldRule>;
|
|
72
|
+
/** 校验失败时的处理动作 */
|
|
73
|
+
failAction?: EnvFailAction;
|
|
74
|
+
/** 是否自动生成 .env 模板文件 */
|
|
75
|
+
generateTemplate?: boolean;
|
|
76
|
+
/** .env 模板文件的输出路径 */
|
|
77
|
+
templateOutput?: string;
|
|
78
|
+
/** 是否注入运行时环境变量守卫代码到 HTML */
|
|
79
|
+
runtimeGuard?: boolean;
|
|
80
|
+
/** 运行时守卫的全局变量名 */
|
|
81
|
+
runtimeGlobalName?: string;
|
|
82
|
+
/** 运行时守卫的行为模式 */
|
|
83
|
+
runtimeGuardMode?: RuntimeGuardMode;
|
|
84
|
+
/** 需要加载的 .env 文件路径列表 */
|
|
85
|
+
envFiles?: string[];
|
|
86
|
+
/** 是否自动加载 .env 文件中的变量到 process.env */
|
|
87
|
+
autoLoadEnv?: boolean;
|
|
88
|
+
/** 校验报告输出路径,设为 false 则不生成报告 */
|
|
89
|
+
reportOutput?: string | false;
|
|
90
|
+
/** 是否在构建前执行校验 */
|
|
91
|
+
validateBeforeBuild?: boolean;
|
|
92
|
+
/** 是否输出校验摘要日志 */
|
|
93
|
+
showSummary?: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 创建环境变量守卫插件
|
|
98
|
+
*
|
|
99
|
+
* @function envGuard
|
|
100
|
+
* @param {Partial<EnvGuardOptions>} [options] - 插件配置选项
|
|
101
|
+
* @returns {Plugin} Vite 插件实例
|
|
102
|
+
*
|
|
103
|
+
* @description 在 Vite 构建前校验环境变量的存在性和合法性,
|
|
104
|
+
* 支持多种值类型校验、正则匹配、自定义校验函数等,
|
|
105
|
+
* 可选生成 .env 模板文件和注入运行时守卫代码。
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* // vite.config.ts
|
|
110
|
+
* import { envGuard } from '@meng-xi/vite-plugin'
|
|
111
|
+
*
|
|
112
|
+
* export default defineConfig({
|
|
113
|
+
* plugins: [
|
|
114
|
+
* envGuard({
|
|
115
|
+
* required: {
|
|
116
|
+
* VITE_API_BASE_URL: {
|
|
117
|
+
* type: 'url',
|
|
118
|
+
* required: true,
|
|
119
|
+
* message: 'API 基础地址必须为合法 URL'
|
|
120
|
+
* },
|
|
121
|
+
* VITE_APP_TITLE: {
|
|
122
|
+
* type: 'string',
|
|
123
|
+
* required: true,
|
|
124
|
+
* minLength: 1,
|
|
125
|
+
* maxLength: 50
|
|
126
|
+
* },
|
|
127
|
+
* VITE_ENABLE_ANALYTICS: {
|
|
128
|
+
* type: 'boolean',
|
|
129
|
+
* required: false,
|
|
130
|
+
* default: 'false'
|
|
131
|
+
* },
|
|
132
|
+
* VITE_API_TIMEOUT: {
|
|
133
|
+
* type: 'number',
|
|
134
|
+
* minValue: 1000,
|
|
135
|
+
* maxValue: 60000,
|
|
136
|
+
* message: 'API 超时时间必须在 1000-60000ms 之间'
|
|
137
|
+
* },
|
|
138
|
+
* VITE_LOG_LEVEL: {
|
|
139
|
+
* type: 'enum',
|
|
140
|
+
* enumValues: ['debug', 'info', 'warn', 'error'],
|
|
141
|
+
* default: 'info'
|
|
142
|
+
* }
|
|
143
|
+
* },
|
|
144
|
+
* failAction: 'error',
|
|
145
|
+
* generateTemplate: true,
|
|
146
|
+
* runtimeGuard: true,
|
|
147
|
+
* runtimeGuardMode: 'console'
|
|
148
|
+
* })
|
|
149
|
+
* ]
|
|
150
|
+
* })
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
declare const envGuard: PluginFactory<EnvGuardOptions, EnvGuardOptions>;
|
|
154
|
+
|
|
155
|
+
export { envGuard };
|
|
156
|
+
export type { EnvFailAction, EnvGuardOptions, EnvGuardResult, RuntimeGuardMode };
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { BasePluginOptions, PluginFactory } from '../../factory/index.js';
|
|
2
|
+
import { E as EnvFieldRule, b as EnvValidationResult } from '../../shared/vite-plugin.CmtcnItg.js';
|
|
3
|
+
import 'vite';
|
|
4
|
+
import '../../shared/vite-plugin.CLr0ttuO.js';
|
|
5
|
+
import '../../shared/vite-plugin.DRRlWY8P.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 环境变量校验失败时的处理动作
|
|
9
|
+
*
|
|
10
|
+
* @description 定义当环境变量校验未通过时的处理策略:
|
|
11
|
+
* - `error`: 抛出错误,中断构建流程
|
|
12
|
+
* - `warn`: 输出警告日志,继续构建
|
|
13
|
+
* - `ignore`: 静默忽略,不输出任何信息
|
|
14
|
+
*/
|
|
15
|
+
type EnvFailAction = 'error' | 'warn' | 'ignore';
|
|
16
|
+
/**
|
|
17
|
+
* 运行时守卫的行为模式
|
|
18
|
+
*
|
|
19
|
+
* @description 定义注入到 HTML 中的运行时守卫代码在检测到
|
|
20
|
+
* 环境变量缺失或无效时的行为方式:
|
|
21
|
+
* - `console`: 在浏览器控制台输出警告信息
|
|
22
|
+
* - `throw`: 抛出运行时错误,阻止应用启动
|
|
23
|
+
* - `overlay`: 在页面顶部显示警告横幅
|
|
24
|
+
*/
|
|
25
|
+
type RuntimeGuardMode = 'console' | 'throw' | 'overlay';
|
|
26
|
+
/**
|
|
27
|
+
* 环境变量校验结果汇总
|
|
28
|
+
*
|
|
29
|
+
* @interface EnvGuardResult
|
|
30
|
+
* @description 包含所有环境变量的校验统计信息和详细结果列表,
|
|
31
|
+
* 用于报告生成和日志输出。
|
|
32
|
+
*/
|
|
33
|
+
interface EnvGuardResult {
|
|
34
|
+
/** 校验时间戳(ISO 格式) */
|
|
35
|
+
timestamp: string;
|
|
36
|
+
/** 校验的环境变量总数 */
|
|
37
|
+
total: number;
|
|
38
|
+
/** 校验通过的变量数量 */
|
|
39
|
+
passed: number;
|
|
40
|
+
/** 缺失的必需变量数量 */
|
|
41
|
+
missing: number;
|
|
42
|
+
/** 校验失败的变量数量(类型不匹配、范围越界等) */
|
|
43
|
+
invalid: number;
|
|
44
|
+
/** 所有变量的详细校验结果列表 */
|
|
45
|
+
results: EnvValidationResult[];
|
|
46
|
+
/** 是否所有变量均校验通过 */
|
|
47
|
+
allPassed: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 环境变量守卫插件的配置选项
|
|
51
|
+
*
|
|
52
|
+
* @interface EnvGuardOptions
|
|
53
|
+
* @extends {BasePluginOptions}
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* envGuard({
|
|
58
|
+
* required: {
|
|
59
|
+
* VITE_API_URL: { type: 'url', required: true },
|
|
60
|
+
* VITE_APP_TITLE: { type: 'string', minLength: 1, maxLength: 50 }
|
|
61
|
+
* },
|
|
62
|
+
* failAction: 'error',
|
|
63
|
+
* generateTemplate: true,
|
|
64
|
+
* runtimeGuard: true,
|
|
65
|
+
* runtimeGuardMode: 'console'
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
interface EnvGuardOptions extends BasePluginOptions {
|
|
70
|
+
/** 环境变量校验规则映射,键为变量名,值为校验规则 */
|
|
71
|
+
required?: Record<string, EnvFieldRule>;
|
|
72
|
+
/** 校验失败时的处理动作 */
|
|
73
|
+
failAction?: EnvFailAction;
|
|
74
|
+
/** 是否自动生成 .env 模板文件 */
|
|
75
|
+
generateTemplate?: boolean;
|
|
76
|
+
/** .env 模板文件的输出路径 */
|
|
77
|
+
templateOutput?: string;
|
|
78
|
+
/** 是否注入运行时环境变量守卫代码到 HTML */
|
|
79
|
+
runtimeGuard?: boolean;
|
|
80
|
+
/** 运行时守卫的全局变量名 */
|
|
81
|
+
runtimeGlobalName?: string;
|
|
82
|
+
/** 运行时守卫的行为模式 */
|
|
83
|
+
runtimeGuardMode?: RuntimeGuardMode;
|
|
84
|
+
/** 需要加载的 .env 文件路径列表 */
|
|
85
|
+
envFiles?: string[];
|
|
86
|
+
/** 是否自动加载 .env 文件中的变量到 process.env */
|
|
87
|
+
autoLoadEnv?: boolean;
|
|
88
|
+
/** 校验报告输出路径,设为 false 则不生成报告 */
|
|
89
|
+
reportOutput?: string | false;
|
|
90
|
+
/** 是否在构建前执行校验 */
|
|
91
|
+
validateBeforeBuild?: boolean;
|
|
92
|
+
/** 是否输出校验摘要日志 */
|
|
93
|
+
showSummary?: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 创建环境变量守卫插件
|
|
98
|
+
*
|
|
99
|
+
* @function envGuard
|
|
100
|
+
* @param {Partial<EnvGuardOptions>} [options] - 插件配置选项
|
|
101
|
+
* @returns {Plugin} Vite 插件实例
|
|
102
|
+
*
|
|
103
|
+
* @description 在 Vite 构建前校验环境变量的存在性和合法性,
|
|
104
|
+
* 支持多种值类型校验、正则匹配、自定义校验函数等,
|
|
105
|
+
* 可选生成 .env 模板文件和注入运行时守卫代码。
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* // vite.config.ts
|
|
110
|
+
* import { envGuard } from '@meng-xi/vite-plugin'
|
|
111
|
+
*
|
|
112
|
+
* export default defineConfig({
|
|
113
|
+
* plugins: [
|
|
114
|
+
* envGuard({
|
|
115
|
+
* required: {
|
|
116
|
+
* VITE_API_BASE_URL: {
|
|
117
|
+
* type: 'url',
|
|
118
|
+
* required: true,
|
|
119
|
+
* message: 'API 基础地址必须为合法 URL'
|
|
120
|
+
* },
|
|
121
|
+
* VITE_APP_TITLE: {
|
|
122
|
+
* type: 'string',
|
|
123
|
+
* required: true,
|
|
124
|
+
* minLength: 1,
|
|
125
|
+
* maxLength: 50
|
|
126
|
+
* },
|
|
127
|
+
* VITE_ENABLE_ANALYTICS: {
|
|
128
|
+
* type: 'boolean',
|
|
129
|
+
* required: false,
|
|
130
|
+
* default: 'false'
|
|
131
|
+
* },
|
|
132
|
+
* VITE_API_TIMEOUT: {
|
|
133
|
+
* type: 'number',
|
|
134
|
+
* minValue: 1000,
|
|
135
|
+
* maxValue: 60000,
|
|
136
|
+
* message: 'API 超时时间必须在 1000-60000ms 之间'
|
|
137
|
+
* },
|
|
138
|
+
* VITE_LOG_LEVEL: {
|
|
139
|
+
* type: 'enum',
|
|
140
|
+
* enumValues: ['debug', 'info', 'warn', 'error'],
|
|
141
|
+
* default: 'info'
|
|
142
|
+
* }
|
|
143
|
+
* },
|
|
144
|
+
* failAction: 'error',
|
|
145
|
+
* generateTemplate: true,
|
|
146
|
+
* runtimeGuard: true,
|
|
147
|
+
* runtimeGuardMode: 'console'
|
|
148
|
+
* })
|
|
149
|
+
* ]
|
|
150
|
+
* })
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
declare const envGuard: PluginFactory<EnvGuardOptions, EnvGuardOptions>;
|
|
154
|
+
|
|
155
|
+
export { envGuard };
|
|
156
|
+
export type { EnvFailAction, EnvGuardOptions, EnvGuardResult, RuntimeGuardMode };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import{createPluginFactory as v,BasePlugin as F}from"../../factory/index.mjs";import{v as A}from"../../shared/vite-plugin.DnFDPjNf.mjs";import{injectBeforeTag as E}from"../../common/html/index.mjs";import{writeFileContent as h}from"../../common/fs/index.mjs";import{formatDate as y}from"../../common/format/index.mjs";import p from"node:path";import m from"node:fs";import"../../logger/index.mjs";import"../../common/object/index.mjs";import"../../shared/vite-plugin.DcExl6jd.mjs";import"../../shared/vite-plugin.BCuhU1au.mjs";import"../../common/script/index.mjs";import"fs";import"path";import"crypto";function D(r){const i=new Map,s=[];for(const[t,e]of Object.entries(r)){const o={type:"string",required:!0,...e};if(o.group){const n=i.get(o.group)||[];n.push({key:t,rule:o}),i.set(o.group,n)}else s.push({key:t,rule:o})}const u=[];u.push("# \u73AF\u5883\u53D8\u91CF\u6A21\u677F\u6587\u4EF6"),u.push(`# \u751F\u6210\u65F6\u95F4: ${new Date().toISOString()}`),u.push("# \u7531 @meng-xi/vite-plugin envGuard \u81EA\u52A8\u751F\u6210"),u.push(""),s.length>0&&g(u,"\u901A\u7528\u914D\u7F6E",s);for(const[t,e]of i)g(u,t,e);return u.join(`
|
|
2
|
+
`)}function g(r,i,s){r.push("# =============================="),r.push(`# ${i}`),r.push("# =============================="),r.push("");for(const{key:u,rule:t}of s){t.description&&r.push(`# ${t.description}`);const e=[];e.push(`\u7C7B\u578B: ${t.type||"string"}`),e.push(t.required!==!1?"\u5FC5\u9700":"\u53EF\u9009"),t.enumValues&&t.enumValues.length>0&&e.push(`\u679A\u4E3E\u503C: ${t.enumValues.join(" | ")}`),t.minValue!==void 0&&e.push(`\u6700\u5C0F\u503C: ${t.minValue}`),t.maxValue!==void 0&&e.push(`\u6700\u5927\u503C: ${t.maxValue}`),t.minLength!==void 0&&e.push(`\u6700\u5C0F\u957F\u5EA6: ${t.minLength}`),t.maxLength!==void 0&&e.push(`\u6700\u5927\u957F\u5EA6: ${t.maxLength}`),t.sensitive&&e.push("\u26A0\uFE0F \u654F\u611F\u4FE1\u606F"),r.push(`# [${e.join(" | ")}]`),t.default!==void 0?r.push(`${u}=${t.sensitive?"********":t.default}`):r.push(`${u}=`),r.push("")}}function C(r,i,s,u){const t=[];for(const[a,l]of Object.entries(r))l.required!==!1&&t.push({key:a,rule:{type:"string",required:!0,...l}});if(t.length===0)return"";const e=u.filter(a=>a.status!=="pass"),o=t.map(({key:a,rule:l})=>({key:a,type:l.type||"string",description:l.description||""})),n=JSON.stringify(o,null,2),d=e.map(a=>a.key),f=JSON.stringify(d),c=R(s);return`<script>
|
|
3
|
+
${`
|
|
4
|
+
(function() {
|
|
5
|
+
'use strict';
|
|
6
|
+
var GUARD_NAME = ${JSON.stringify(i)};
|
|
7
|
+
var GUARD_DATA = ${n};
|
|
8
|
+
var FAILED_KEYS = ${f};
|
|
9
|
+
var MODE = ${JSON.stringify(s)};
|
|
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 R(r){switch(r){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""}}class $ 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(i=>i===!1||typeof i=="string","reportOutput \u5FC5\u987B\u4E3A false \u6216\u5B57\u7B26\u4E32\u8DEF\u5F84").field("validateBeforeBuild").boolean().field("showSummary").boolean().validate()}getPluginName(){return"env-guard"}addPluginHooks(i){this.options.validateBeforeBuild&&(i.configResolved=s=>{this.viteConfig=s,this.runValidation()}),this.options.runtimeGuard&&(i.transformIndexHtml={order:"post",handler:s=>this.safeExecuteSync(()=>this.injectRuntimeGuard(s),"\u6CE8\u5165\u8FD0\u884C\u65F6\u5B88\u536B")||s})}runValidation(){this.options.autoLoadEnv&&this.loadEnvFiles(),this.validationResults=A(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 i=this.viteConfig.root||process.cwd();for(const s of this.options.envFiles){const u=p.resolve(i,s);if(m.existsSync(u))try{this.parseAndLoadEnvFile(u)}catch{this.logger.warn(`\u52A0\u8F7D .env \u6587\u4EF6\u5931\u8D25: ${u}`)}}}parseAndLoadEnvFile(i){const s=m.readFileSync(i,"utf-8").split(`
|
|
66
|
+
`);for(const u of s){const t=u.trim();if(!t||t.startsWith("#"))continue;const e=t.indexOf("=");if(e===-1)continue;const o=t.slice(0,e).trim();let n=t.slice(e+1).trim();(n.startsWith('"')&&n.endsWith('"')||n.startsWith("'")&&n.endsWith("'"))&&(n=n.slice(1,-1)),o.startsWith("VITE_")&&process.env[o]===void 0&&(process.env[o]=n)}}buildResult(){const i=this.validationResults.length,s=this.validationResults.filter(e=>e.status==="pass").length,u=this.validationResults.filter(e=>e.status==="missing").length,t=this.validationResults.filter(e=>e.status!=="pass"&&e.status!=="missing").length;return{timestamp:y(new Date,"{YYYY}-{MM}-{DD}T{HH}:{mm}:{ss}"),total:i,passed:s,missing:u,invalid:t,results:this.validationResults,allPassed:u===0&&t===0}}handleResults(){if(!this.guardResult||this.guardResult.allPassed)return;const i=this.validationResults.filter(e=>e.status==="missing").map(e=>e.key),s=this.validationResults.filter(e=>e.status!=="pass"&&e.status!=="missing"),u=[];i.length>0&&u.push(`\u7F3A\u5C11\u5FC5\u9700\u7684\u73AF\u5883\u53D8\u91CF: ${i.join(", ")}`);for(const e of s)u.push(`${e.key}: ${e.message}`);const t=u.join(`
|
|
67
|
+
`);switch(this.options.failAction){case"error":throw new Error(t);case"warn":this.logger.warn(t);break}}writeEnvTemplate(){const i=this.viteConfig?.root||process.cwd(),s=p.resolve(i,this.options.templateOutput),u=D(this.options.required);this.safeExecuteSync(()=>{h(s,u),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 i=this.viteConfig?.build?.outDir||"dist",s=p.resolve(i,this.options.reportOutput);this.safeExecuteSync(()=>{const u=JSON.stringify(this.guardResult,(t,e)=>e instanceof RegExp?e.toString():typeof e=="function"?"[Function]":e,2);h(s,u),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:i,passed:s,missing:u,invalid:t,allPassed:e}=this.guardResult;if(e){this.logger.success(`\u73AF\u5883\u53D8\u91CF\u6821\u9A8C\u901A\u8FC7: ${i} \u4E2A\u53D8\u91CF\u5168\u90E8\u5408\u6CD5`);return}this.logger.info(`\u73AF\u5883\u53D8\u91CF\u6821\u9A8C\u7ED3\u679C: \u603B\u8BA1 ${i} | \u901A\u8FC7 ${s} | \u7F3A\u5931 ${u} | \u5931\u8D25 ${t}`);const o=this.validationResults.filter(n=>n.status!=="pass");for(const n of o){const d=n.status==="missing"?"\u7F3A\u5931":"\u5931\u8D25";this.logger.warn(` [${d}] ${n.key}: ${n.message}`)}}injectRuntimeGuard(i){const s=C(this.options.required,this.options.runtimeGlobalName,this.options.runtimeGuardMode,this.validationResults);if(!s)return i;const u=E(i,"</head>",s);return u.injected?u.html:(this.logger.warn("\u672A\u627E\u5230 </head> \u6807\u7B7E\uFF0C\u8FD0\u884C\u65F6\u5B88\u536B\u4EE3\u7801\u672A\u80FD\u6CE8\u5165"),i)}getResult(){return this.guardResult}getValidationResults(){return[...this.validationResults]}}const w=v($);export{w 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("../../common/object/index.cjs"),require("fs"),require("path");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
|
+
"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("../../common/object/index.cjs"),require("fs"),require("path"),require("../../shared/vite-plugin.BrI73DHA.cjs"),require("../../common/script/index.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;
|
|
@@ -7,22 +7,36 @@ import '../../shared/vite-plugin.DRRlWY8P.cjs';
|
|
|
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
|
/**
|