Browse Source

fix(compiler-sfc): nested css supports atrule and comment (#11899)

close #11896
linzhe 1 year ago
parent
commit
0e7bc717e6

+ 32 - 0
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;`,

+ 22 - 9
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