From 0e7bc717e6640644f062957ec5031506f0dab215 Mon Sep 17 00:00:00 2001 From: linzhe <40790268+linzhe141@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:53:49 +0800 Subject: [PATCH] fix(compiler-sfc): nested css supports atrule and comment (#11899) close #11896 --- .../__tests__/compileStyle.spec.ts | 32 +++++++++++++++++++ .../compiler-sfc/src/style/pluginScoped.ts | 31 ++++++++++++------ 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/packages/compiler-sfc/__tests__/compileStyle.spec.ts b/packages/compiler-sfc/__tests__/compileStyle.spec.ts index 72727c43196..b76414364dc 100644 --- a/packages/compiler-sfc/__tests__/compileStyle.spec.ts +++ b/packages/compiler-sfc/__tests__/compileStyle.spec.ts @@ -47,6 +47,38 @@ describe('SFC scoped CSS', () => { ) }) + test('nesting selector with atrule and comment', () => { + expect( + compileScoped( + `h1 { +color: red; +/*background-color: pink;*/ +@media only screen and (max-width: 800px) { + background-color: green; + .bar { color: white } +} +.foo { color: red; } +}`, + ), + ).toMatch( + `h1 { +&[data-v-test] { +color: red +/*background-color: pink;*/ +} +@media only screen and (max-width: 800px) { +&[data-v-test] { + background-color: green +} +.bar[data-v-test] { color: white +} +} +.foo[data-v-test] { color: red; +} +}`, + ) + }) + test('multiple selectors', () => { expect(compileScoped(`h1 .foo, .bar, .baz { color: red; }`)).toMatch( `h1 .foo[data-v-test], .bar[data-v-test], .baz[data-v-test] { color: red;`, diff --git a/packages/compiler-sfc/src/style/pluginScoped.ts b/packages/compiler-sfc/src/style/pluginScoped.ts index 6a588b56726..b0224cf20d8 100644 --- a/packages/compiler-sfc/src/style/pluginScoped.ts +++ b/packages/compiler-sfc/src/style/pluginScoped.ts @@ -233,16 +233,12 @@ function rewriteSelector( if (rule.nodes.some(node => node.type === 'rule')) { const deep = (rule as any).__deep - const decls = rule.nodes.filter(node => node.type === 'decl') - if (!deep && decls.length) { - for (const decl of decls) { - rule.removeChild(decl) + if (!deep) { + extractAndWrapNodes(rule) + const atruleNodes = rule.nodes.filter(node => node.type === 'atrule') + for (const atnode of atruleNodes) { + extractAndWrapNodes(atnode) } - const hostRule = new Rule({ - nodes: decls, - selector: '&', - }) - rule.prepend(hostRule) } shouldInject = deep } @@ -286,5 +282,22 @@ function isSpaceCombinator(node: selectorParser.Node) { return node.type === 'combinator' && /^\s+$/.test(node.value) } +function extractAndWrapNodes(parentNode: Rule | AtRule) { + if (!parentNode.nodes) return + const nodes = parentNode.nodes.filter( + node => node.type === 'decl' || node.type === 'comment', + ) + if (nodes.length) { + for (const node of nodes) { + parentNode.removeChild(node) + } + const wrappedRule = new Rule({ + nodes: nodes, + selector: '&', + }) + parentNode.prepend(wrappedRule) + } +} + scopedPlugin.postcss = true export default scopedPlugin