Skip to content

Commit 3258541

Browse files
committed
转义不支持的选择器名称字符
1 parent bc38499 commit 3258541

5 files changed

Lines changed: 83 additions & 1 deletion

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,4 @@
115115
"engines": {
116116
"node": ">=14.0.0"
117117
}
118-
}
118+
}

src/lib/adaptMiniPrograms.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export default function adaptMiniPrograms(context) {
2+
const config = context.tailwindConfig
3+
return (root) => {
4+
if (!config.miniPrograms) return
5+
6+
// 转义小程序不支持的选择器字符
7+
// 例如:.first\:mt-[20px]:first-child -> .first_mt-_20px_:first-child
8+
root.walkRules((rule) => {
9+
rule.selector = rule.selector.replace(/\\[:\[\]]/g, '_')
10+
})
11+
}
12+
}

src/processTailwindFeatures.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import resolveDefaultsAtRules from './lib/resolveDefaultsAtRules'
77
import collapseAdjacentRules from './lib/collapseAdjacentRules'
88
import collapseDuplicateDeclarations from './lib/collapseDuplicateDeclarations'
99
import partitionApplyAtRules from './lib/partitionApplyAtRules'
10+
import adaptMiniPrograms from './lib/adaptMiniPrograms'
1011
import { createContext } from './lib/setupContextUtils'
1112
import { issueFlagNotices } from './featureFlags'
1213

@@ -52,5 +53,8 @@ export default function processTailwindFeatures(setupContext) {
5253
resolveDefaultsAtRules(context)(root, result)
5354
collapseAdjacentRules(context)(root, result)
5455
collapseDuplicateDeclarations(context)(root, result)
56+
57+
// 适配小程序
58+
adaptMiniPrograms(context)(root, result)
5559
}
5660
}

src/vite/index.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export default function modifyClasses() {
2+
return {
3+
name: 'modify-classes',
4+
enforce: 'pre',
5+
transform(code, id) {
6+
// 仅处理 HTML / Vue / Svelte 文件
7+
if (!/\.(html|vue|svelte)$/.test(id)) {
8+
return
9+
}
10+
11+
// 替换所有 class="..."
12+
const transformed = code.replace(/class\s*=\s*"([^"]+)"/g, (_, classValue) => {
13+
const newClasses = classValue
14+
.split(/\s+/)
15+
.map((cls) => replaceInvalidChars(cls))
16+
.join(' ')
17+
return `class="${newClasses}"`
18+
})
19+
return transformed
20+
},
21+
}
22+
}
23+
24+
// 自定义替换规则函数
25+
function replaceInvalidChars(cls) {
26+
// 这里按需调整:微信小程序不支持 :, [, ]
27+
return cls.replace(/[:\[\]]/g, '_')
28+
}

tests/mini-programs.test.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { run, html, css } from './util/run'
2+
import modifyClasses from '../src/vite'
3+
4+
test('Escape special characters', async () => {
5+
const config = {
6+
content: [
7+
{
8+
raw: html`<div class="first:mt-[20rpx]"></div>`,
9+
},
10+
],
11+
miniPrograms: true,
12+
}
13+
14+
const input = css`
15+
@tailwind utilities;
16+
`
17+
const result = await run(input, config)
18+
return expect(result.css).toMatchFormattedCss(css`
19+
.first_mt-_20rpx_:first-child {
20+
margin-top: 20rpx;
21+
}
22+
`)
23+
})
24+
25+
test('vite plugin', async () => {
26+
const source = html`
27+
<template>
28+
<div class="first:mt-[20rpx] hover:bg-gray-100"></div>
29+
</template>
30+
`
31+
expect(modifyClasses().transform(source, 'App.vue')).toMatchInlineSnapshot(`
32+
"
33+
<template>
34+
<div class="first_mt-_20rpx_ hover_bg-gray-100"></div>
35+
</template>
36+
"
37+
`)
38+
})

0 commit comments

Comments
 (0)