-
Notifications
You must be signed in to change notification settings - Fork 0
/
vite-plugin-dynamic-theme.ts
167 lines (164 loc) · 5.08 KB
/
vite-plugin-dynamic-theme.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import { type PluginOption, createFilter } from 'vite'
import { generate } from '@ant-design/colors'
const filter = createFilter(/.css|less|sass|scss|stylus$/)
function vitePluginDynamicTheme(color: string): PluginOption {
const colors = generate(color)
const matchColors = [colors[5], colors[4], colors[0]]
let styleStr = ''
const hadTransform = new Set()
function loop(code: string) {
let idx = -1
let done = false
let result = ''
while (!done) {
++idx
const char = code[idx]
const nextChar = code[idx + 1]
let closeIdx = -1
// 注释区块跳过
if (char === '/') {
/* */
if (nextChar === '*') {
closeIdx = code.indexOf('*/', idx + 2)
if (closeIdx > -1) {
idx = closeIdx + 1
} else {
// 文件内容有错误
done = true
}
} else if (nextChar === '/') {
//
closeIdx = code.indexOf('\n', idx + 2)
if (closeIdx > -1) {
idx = closeIdx + 1
} else {
// 文件内容有错误
done = true
}
} else {
// 文件内容有错误
done = true
}
} else {
// 样式区块
// 选择器结束idx
const selectorEndIdx = code.indexOf('{', idx)
if (selectorEndIdx > -1) {
let selectorStyleEndIdx = -1
// 选择器样式结束idx 需考虑嵌套
let nestDone = false
let nestIdx = selectorEndIdx
let hadNest = false
let hadNestFlag = false
while (!nestDone) {
++nestIdx
const nestChar = code[nestIdx]
const nestNextChar = code[nestIdx + 1]
let nestCloseIdx = -1
// 注释区块跳过
if (nestChar === '/') {
/* */
if (nestNextChar === '*') {
nestCloseIdx = code.indexOf('*/', nestIdx + 2)
if (nestCloseIdx > -1) {
nestIdx = nestCloseIdx + 1
} else {
// 文件内容有错误
nestDone = true
}
} else if (nestNextChar === '/') {
//
nestCloseIdx = code.indexOf('\n', nestIdx + 2)
if (nestCloseIdx > -1) {
nestIdx = nestCloseIdx + 1
} else {
// 文件内容有错误
nestDone = true
}
}
} else {
if (nestChar === '{') {
hadNest = true
hadNestFlag = true
} else if (nestChar === '}') {
if (hadNest) hadNest = false
else {
selectorStyleEndIdx = nestIdx
nestDone = true
}
}
}
if (nestIdx === code.length - 1) {
nestDone = true
}
}
if (selectorStyleEndIdx > -1) {
const styleBlockStr = code.slice(selectorEndIdx + 1, selectorStyleEndIdx)
if (hadNestFlag) {
const nestRes = loop(styleBlockStr)
if (nestRes) result += `${code.slice(idx, selectorEndIdx + 1)}${nestRes}}`
} else {
// 过滤包含颜色值的样式项 其他样式项不要
const styleBlockArr = styleBlockStr.split(';')
const styleBlockHadColorArr = styleBlockArr.filter((block) =>
matchColors.some((color) => block.indexOf(color) > -1)
)
if (
styleBlockHadColorArr.length &&
// NOTE 排除 ant-btn:hover (可抽取成配置参数)
code.slice(idx, selectorEndIdx + 1).indexOf('.ant-btn:hover') === -1
) {
// 将样式区块加入结果中
result += `${code.slice(idx, selectorEndIdx + 1)}${styleBlockHadColorArr.join(
';'
)}}`
}
}
idx = selectorStyleEndIdx
} else {
// 文件内容有错误
done = true
}
} else {
// 文件内容有错误
done = true
}
}
if (idx === code.length - 1) {
done = true
}
}
return result
}
// NOTE 额外要处理的样式 (可抽取成配置参数)
const extraStyle = `.ant-btn:not(.ant-btn-primary):hover, .ant-btn:not(.ant-btn-primary):focus{
color: #40a9ff;
border-color: #40a9ff;
}`
return {
name: 'vite-plugin-dynamic-theme',
transformIndexHtml() {
return [
{
tag: 'style',
attrs: {
type: 'text/css',
'data-color': colors[5],
id: 'vite-plugin-dynamic-theme'
},
children: `${styleStr}${extraStyle}`,
injectTo: 'body'
}
]
},
transform(code, id) {
if (filter(id)) {
if (!hadTransform.has(id)) {
hadTransform.add(id)
styleStr += loop(code)
}
}
}
}
}
export default vitePluginDynamicTheme