Skip to content

Commit 16fa18d

Browse files
committed
fix(compiler-sfc): fix css v-bind inside other css functions
fix #5302, close #5306
1 parent 283df0a commit 16fa18d

File tree

3 files changed

+27
-8
lines changed

3 files changed

+27
-8
lines changed

packages/compiler-sfc/__tests__/__snapshots__/cssVars.spec.ts.snap

+4-2
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,16 @@ export default {
7474
expose();
7575
7676
_useCssVars(_ctx => ({
77-
\\"xxxxxxxx-_a___b____2____px__\\": ((_unref(a) + _unref(b)) / 2 + 'px' ),
77+
\\"xxxxxxxx-foo\\": (_unref(foo)),
78+
\\"xxxxxxxx-_a___b____2____px_\\": ((_unref(a) + _unref(b)) / 2 + 'px'),
7879
\\"xxxxxxxx-__a___b______2___a_\\": (((_unref(a) + _unref(b))) / (2 * _unref(a)))
7980
}))
8081
8182
let a = 100
8283
let b = 200
84+
let foo = 300
8385
84-
return { a, b }
86+
return { a, b, foo }
8587
}
8688
8789
}"

packages/compiler-sfc/__tests__/cssVars.spec.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,13 @@ describe('CSS vars injection', () => {
204204
`<script setup>
205205
let a = 100
206206
let b = 200
207+
let foo = 300
207208
</script>\n` +
208209
`<style>
210+
p{
211+
width: calc(v-bind(foo) - 3px);
212+
height: calc(v-bind('foo') - 3px);
213+
}
209214
div {
210215
color: v-bind((a + b) / 2 + 'px' );
211216
}
@@ -218,7 +223,8 @@ describe('CSS vars injection', () => {
218223
</style>`
219224
)
220225
expect(content).toMatch(`_useCssVars(_ctx => ({
221-
"${mockId}-_a___b____2____px__": ((_unref(a) + _unref(b)) / 2 + 'px' ),
226+
"${mockId}-foo": (_unref(foo)),
227+
"${mockId}-_a___b____2____px_": ((_unref(a) + _unref(b)) / 2 + 'px'),
222228
"${mockId}-__a___b______2___a_": (((_unref(a) + _unref(b))) / (2 * _unref(a)))
223229
})`)
224230
assertCode(content)

packages/compiler-sfc/src/cssVars.ts

+16-5
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import { PluginCreator } from 'postcss'
1212
import hash from 'hash-sum'
1313

1414
export const CSS_VARS_HELPER = `useCssVars`
15-
export const cssVarRE =
16-
/\bv-bind\s*\(\s*(?:'([^']+)'|"([^"]+)"|([^'"][^;]*))\s*\)/g
15+
// match v-bind() with max 2-levels of nested parens.
16+
const cssVarRE = /v-bind\s*\(((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*)\)/g
1717

1818
export function genCssVarsFromList(
1919
vars: string[],
@@ -33,14 +33,25 @@ function genVarName(id: string, raw: string, isProd: boolean): string {
3333
}
3434
}
3535

36+
function noramlizeExpression(exp: string) {
37+
exp = exp.trim()
38+
if (
39+
(exp[0] === `'` && exp[exp.length - 1] === `'`) ||
40+
(exp[0] === `"` && exp[exp.length - 1] === `"`)
41+
) {
42+
return exp.slice(1, -1)
43+
}
44+
return exp
45+
}
46+
3647
export function parseCssVars(sfc: SFCDescriptor): string[] {
3748
const vars: string[] = []
3849
sfc.styles.forEach(style => {
3950
let match
4051
// ignore v-bind() in comments /* ... */
4152
const content = style.content.replace(/\/\*([\s\S]*?)\*\//g, '')
4253
while ((match = cssVarRE.exec(content))) {
43-
const variable = match[1] || match[2] || match[3]
54+
const variable = noramlizeExpression(match[1])
4455
if (!vars.includes(variable)) {
4556
vars.push(variable)
4657
}
@@ -62,8 +73,8 @@ export const cssVarsPlugin: PluginCreator<CssVarsPluginOptions> = opts => {
6273
Declaration(decl) {
6374
// rewrite CSS variables
6475
if (cssVarRE.test(decl.value)) {
65-
decl.value = decl.value.replace(cssVarRE, (_, $1, $2, $3) => {
66-
return `var(--${genVarName(id, $1 || $2 || $3, isProd)})`
76+
decl.value = decl.value.replace(cssVarRE, (_, $1) => {
77+
return `var(--${genVarName(id, noramlizeExpression($1), isProd)})`
6778
})
6879
}
6980
}

0 commit comments

Comments
 (0)