postcss/postcss-nested

Bubbling not working as expected

Windvis opened this issue · 12 comments

Hey there!

I'm experimenting with a new PostCSS setup based on postcss-nested and Tailwind.

Tailwind has a set of @rules which I want to let play nice with postcss-nested. More specifically the @screen and @variants rules.

I added both to the bubble option of postcss-nested.

I'm trying to transform the following code:

.dummy-component {
  @apply p-8 rounded shadow bg-white border;

  &__content {
    @apply font-thin font-sans text-5xl text-center;
  }

  @screen xl {
    @apply w-1/3; /* This doesn't work */
    width: calc(100% / 3); /* This does */
  }

  /* @media behaves exactly the same  */
  @media (min-width: 768px) {
    @apply w-1/2; /* This doesn't work */
    width: 50%; /* This does */
  }

  @variants hover {
    @apply border-green;
    border-color: lime;
  }
}

And this is the result (before Tailwind does its thing):

.dummy-component {
  @apply p-8 rounded shadow bg-white border;
}
.dummy-component__content {
  @apply font-thin font-sans text-5xl text-center;
}
@screen xl {
  .dummy-component {
    /* This doesn't work */
    width: calc(100% / 3); /* This does */
  }
  @apply w-1/3;
}
/* @media behaves exactly the same  */
@media (min-width: 768px) {
  .dummy-component {
    /* This doesn't work */
    width: 50%; /* This does */
  }
  @apply w-1/2;
}
@variants hover {
  .dummy-component {
    border-color: lime;
  }
  @apply border-green;
}

The @apply rules (which Tailwind uses to "mixin" styles) don't get nested in the bubbled selector as classic css rules do.

Any idea what could be causing this?

ai commented

Maybe this option will help you

https://github.com/postcss/postcss-nested#bubble

No, that's what I'm using at the moment. The problem seems to be that at-rules children won't we bubbled. It seems to be coded that way.

ai commented

OK. Can you show the expected output?

Sorry, CSS example is too long, it is hard to me to understand it.

Yea sure, sorry!

Input:

.class {
  @screen xl { /* 'screen' is added to the bubble option of postcss-nested */
    @apply w-1/3; /* I want this to behave like a normal css rule */
    width: calc(100% / 3); /* Like this */
  }
}

expected output:

@screen xl {
  .class {
    @apply w-1/3;
    width: calc(100% / 3);
  }
}

actual output:

@screen xl {
  .class {
    width: calc(100% / 3);
  }
  @apply w-1/3; /* It doesn't get nested inside the selector */
}
ai commented

And what are your postcss-nested options?

{ bubble: ['screen'] }

ai commented

Sorry. Still had no time to fix it. Will try to do it on this weekend.

No worries man! It's open source, I could do it myself if it was blocking :-D. Besides It looks like it works like this by design, so there must be use cases where this behaviour is desired :-)

@Windvis the solution is:

const cssNested = require('postcss-nested')
mix.postCss('resources/css/app.css', 'public/css', [
        tailwindcss('tailwind.js'),
        cssNested({ bubble: ['screen'] }),
    ])

call postcss-nested plugin after tailwindcss mentiond by adam wathan tailwindlabs/tailwindcss#94 (comment)

From @ai comments in the postcss-mixins module: postcss/postcss-mixins#110 (comment)

I have tried the following patch:

diff --git a/index.js b/index.js
index d933ad1e91dd..05ea9d9b1206 100644
--- a/index.js
+++ b/index.js
@@ -190,7 +190,7 @@ module.exports = (opts = {}) => {
 
   return {
     postcssPlugin: 'postcss-nested',
-    Once (root, { Rule }) {
+    AtRule (root, { Rule }) {
       function process (node) {
         node.each(child => {
           if (child.type === 'rule') {
@@ -201,7 +201,10 @@ module.exports = (opts = {}) => {
         })
       }
       process(root)
-    }
+    },
+    Rule (root, { Rule }) {
+      processRule(root, bubble, unwrap, preserveEmpty, Rule)
+    },
   }
 }
 module.exports.postcss = true

However I get the following error when I build:

ERROR in ./storybook/styles.css
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
TypeError: Cannot set property 'parent' of undefined
    at /Users/dan/coding/postcss-project/storybook/components/menu.css:366:3
    at Root.removeChild (/Users/dan/coding/postcss-project/node_modules/postcss/lib/container.js:238:38)
    at Root.removeChild (/Users/dan/coding/postcss-project/node_modules/postcss/lib/root.js:21:18)
    at Proxy.remove (/Users/dan/coding/postcss-project/node_modules/postcss/lib/node.js:72:19)
    at processRule (/Users/dan/coding/postcss-project/node_modules/postcss-nested/index.js:168:39)
    at Rule (/Users/dan/coding/postcss-project/node_modules/postcss-nested/index.js:206:7)

If I comment out the following line in the postcss-nested module:
if (rule.nodes.length === 0) rule.remove()

Then it builds but I have many nested @media selectors at the top of the CSS file instead of where they would end up before (after the parent where they are nested from), as well as many empty selectors like .some-class {}

ai commented

However I get the following error when I build

Yeap, that changes are not enough. We need to debug and change the origin functions.

ai commented

Can you try 5.0.6 release. The bug may be fixed by @bsak-shell in #137