postcss / postcss-nested

PostCSS plugin to unwrap nested rules like how Sass does it.
MIT License
1.16k stars 67 forks source link

Bubbling not working as expected #81

Closed Windvis closed 2 years ago

Windvis commented 5 years ago

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 5 years ago

Maybe this option will help you

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

Windvis commented 5 years ago

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 5 years ago

OK. Can you show the expected output?

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

Windvis commented 5 years ago

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 5 years ago

And what are your postcss-nested options?

Windvis commented 5 years ago

{ bubble: ['screen'] }

ai commented 5 years ago

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

Windvis commented 5 years ago

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 :-)

thoresuenert commented 5 years ago

@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 https://github.com/tailwindcss/tailwindcss/issues/94#issuecomment-341911398

dan2k3k4 commented 4 years ago

From @ai comments in the postcss-mixins module: https://github.com/postcss/postcss-mixins/issues/110#issuecomment-713938023

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 4 years ago

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 3 years ago

Can you try 5.0.6 release. The bug may be fixed by @bsak-shell in https://github.com/postcss/postcss-nested/pull/137