@vue/compiler-sfc: Partly unscoped styling with selector list & :deep & nesting
Version
3.6.0-rc.2
Reproduction link
Steps to reproduce
When a <style scoped> rule has (1) a comma-separated selector list, where (2) one member uses :deep(), and (3) the rule contains nested child rules, the scope id ([data-v-xxx]) is not injected into the non-:deep() selectors in the list. Those selectors become unscoped and leak globally.
An example which triggers this bug:
.a,
.b :deep(.c) {
color: red;
> span { color: blue; }
}
What is expected?
.a[data-v-7ba5bd90],
.b[data-v-7ba5bd90] .c {
& {
color: red;
}
> span { color: blue;
}
}
What is actually happening?
.a is unscoped.
.a,
.b[data-v-7ba5bd90] .c {
& {
color: red;
}
> span { color: blue;
}
}
According to Claude, the problem seems to be caused as follows. Note that I did not verify this.
Root cause appears to be in
rewriteSelector(packages/compiler-sfc/src/style/pluginScoped.ts):rule.__deepis tracked per-rule but set as a side effect while rewriting whichever member contains:deep(). When a nested rule is detected, the code setsshouldInject = rule.__deepand defers injection to a generated& { ... }wrapper. Because selectors are processed in source order, a plain selector processed before the:deep()member seesrule.__deepstill unset (→ skips injection on itself), while the later&wrapper seesrule.__deep === true(→ also skips injection), so the scope id lands nowhere.
Source: vuejs/core