From 6f0f944d8326463be97610096c4730ddaa7e3178 Mon Sep 17 00:00:00 2001 From: daiwei Date: Sat, 5 Apr 2025 10:27:27 +0800 Subject: [PATCH 1/2] fix(compile-sfc): auto add nesting combinators for ::v-deep in scoped CSS --- .../__tests__/compileStyle.spec.ts | 12 ++++++++++ .../compiler-sfc/src/style/pluginScoped.ts | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/packages/compiler-sfc/__tests__/compileStyle.spec.ts b/packages/compiler-sfc/__tests__/compileStyle.spec.ts index b76414364..ff5ca2a95 100644 --- a/packages/compiler-sfc/__tests__/compileStyle.spec.ts +++ b/packages/compiler-sfc/__tests__/compileStyle.spec.ts @@ -140,6 +140,18 @@ color: red } }" `) + expect(compileScoped(`.foo { :deep(.bar) { color: red; }}`)) + .toMatchInlineSnapshot(` + ".foo { + &[data-v-test] .bar { color: red; + }}" + `) + expect(compileScoped(`.foo { & :deep(.bar) { color: red; }}`)) + .toMatchInlineSnapshot(` + ".foo { + &[data-v-test] .bar { color: red; + }}" + `) }) test('::v-slotted', () => { diff --git a/packages/compiler-sfc/src/style/pluginScoped.ts b/packages/compiler-sfc/src/style/pluginScoped.ts index d0aaddd76..b0854a22e 100644 --- a/packages/compiler-sfc/src/style/pluginScoped.ts +++ b/packages/compiler-sfc/src/style/pluginScoped.ts @@ -133,6 +133,29 @@ function rewriteSelector( selector.insertAfter(last, ss) last = ss }) + + // if css nesting is used, we need to insert a nesting combinator + // before the ::v-deep node + // .foo { ::v-deep(.bar) } -> .foo { &[xxxxxxx] .bar } + const isNestedRule = rule.parent && rule.parent.type === 'rule' + if (isNestedRule && n.parent) { + let hasNestingCombinator = false + let index = n.parent.index(n) - 1 + while (index >= 0) { + const prev = n.parent.at(index) + if (!prev) break + if (prev.type === 'nesting') { + hasNestingCombinator = true + break + } + index-- + } + if (!hasNestingCombinator) { + node = selectorParser.nesting() + selector.insertBefore(n, node) + } + } + // insert a space combinator before if it doesn't already have one const prev = selector.at(selector.index(n) - 1) if (!prev || !isSpaceCombinator(prev)) { From bfd11af47410359644d3528e11a4e1b38bb33fb1 Mon Sep 17 00:00:00 2001 From: daiwei Date: Sat, 5 Apr 2025 10:32:02 +0800 Subject: [PATCH 2/2] chore: update --- .../__tests__/compileStyle.spec.ts | 6 ++++++ .../compiler-sfc/src/style/pluginScoped.ts | 21 +++++++------------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/compiler-sfc/__tests__/compileStyle.spec.ts b/packages/compiler-sfc/__tests__/compileStyle.spec.ts index ff5ca2a95..48e6ea8c3 100644 --- a/packages/compiler-sfc/__tests__/compileStyle.spec.ts +++ b/packages/compiler-sfc/__tests__/compileStyle.spec.ts @@ -146,6 +146,12 @@ color: red &[data-v-test] .bar { color: red; }}" `) + expect(compileScoped(`.foo { :deep(.bar),:deep(.baz) { color: red; }}`)) + .toMatchInlineSnapshot(` + ".foo { + &[data-v-test] .bar,&[data-v-test] .baz { color: red; + }}" + `) expect(compileScoped(`.foo { & :deep(.bar) { color: red; }}`)) .toMatchInlineSnapshot(` ".foo { diff --git a/packages/compiler-sfc/src/style/pluginScoped.ts b/packages/compiler-sfc/src/style/pluginScoped.ts index b0854a22e..0c7f700e1 100644 --- a/packages/compiler-sfc/src/style/pluginScoped.ts +++ b/packages/compiler-sfc/src/style/pluginScoped.ts @@ -134,23 +134,16 @@ function rewriteSelector( last = ss }) - // if css nesting is used, we need to insert a nesting combinator - // before the ::v-deep node + // if css nesting is used, we need to insert a nesting selector + // before the ::v-deep's inner selector. // .foo { ::v-deep(.bar) } -> .foo { &[xxxxxxx] .bar } const isNestedRule = rule.parent && rule.parent.type === 'rule' if (isNestedRule && n.parent) { - let hasNestingCombinator = false - let index = n.parent.index(n) - 1 - while (index >= 0) { - const prev = n.parent.at(index) - if (!prev) break - if (prev.type === 'nesting') { - hasNestingCombinator = true - break - } - index-- - } - if (!hasNestingCombinator) { + const hasNestingSelector = n.parent.nodes + .slice(0, n.parent.index(n)) + .some(node => node.type === 'nesting') + + if (!hasNestingSelector) { node = selectorParser.nesting() selector.insertBefore(n, node) }