gajus / babel-plugin-react-css-modules

Transforms styleName to className using compile time CSS module resolution.
Other
2.05k stars 162 forks source link

SASS @at-root generated class names do not work with plugin #81

Open ncrum opened 7 years ago

ncrum commented 7 years ago

When using SASS @at-root directive and referencing the parent class name with #{&}, the babel plugin is unable to find a class, but the class exists at runtime. Below is the error I'm getting, here is the basic setup:

.ResultWrapperHeader {
  ...
  @at-root #{&}__title {
    ...
  }
}

Which outputs to:

.ResultWrapperHeader {...}
.ResultWrapperHeader__title {...}

The plugin gives me this error message: Could not resolve the styleName 'ResultWrapperHeader__title'.

This may just be something that is not supported with the babel plugin version, since the plugin would have to process the sass to css in order to know what the class name is. Is there a way around this issue and still use this nested pattern (other than not using nesting)?

marcin-mazurek commented 7 years ago

@ncrum Does it work when you remove @at-root? If so, can you share your config? I'm struggling to get the plugin working with any nested SASS rules, not only those with @at-root.

ncrum commented 7 years ago

I'm not certain the #{&} variable is supposed to work without @at-root, but it doesn't work for me. I did however try:

.ResultWrapperHeader {
  ...
  .ResultWrapperHeader__title {
    ...
  }
}

This kind of nesting works fine, so I'm just going to use this pattern for my scss files, even though it is a little more verbose, which is fine.

Also, if it helps you, this is how I configured my css/scss loaders using webpack 2:

{
    test : /\.(css|scss)$/,
    use : [
        'style-loader',
        'css-loader?importLoader=1&modules&localIdentName=[local]___[hash:base64:5]',
        'resolve-url-loader',
        {
            loader : 'sass-loader?sourceMap',
            options : {
                includePaths : [path.resolve(__dirname, 'app')],
            }
        }
    ],
    include : path.resolve(__dirname, 'app'),
}
marcin-mazurek commented 7 years ago

@ncrum Can you also share your babel-plugin-react-css-modules plugin config?

mvsmal commented 7 years ago

I had an issue with nested rules. Created a pull request to support extra postcss plugins, like postcss-nested PR #100

drewdecarme commented 7 years ago

I was having the same issue with standard sass syntax of nesting rules using &. Correct me if I'm wrong, but shouldn't this support sass out of the box without having to use a PostCSS plugin like postcss-nested?

I searched all over the web so far and this was the only solution that actually worked... but somehow I guess I'm still not satisfied that I'm using a PostCSS plugin to to do the work that Sass should be doing...

marcin-mazurek commented 7 years ago

@drewdecarme I did some research a few months ago, it turned out that the plugin does not compile SASS (which is even described in the docs: https://github.com/postcss/postcss#syntaxes). The fact that the postcss-nested works is just an accident, because this plugin has nothing to do with SASS. If you have any other non-standard CSS syntax this will fail again. The proper and safe solution is to pass SASS compiled to CSS to the plugin.

michalstocki commented 7 years ago

I have a similar issue with the following Less syntax:

.btn {
  // ...
  &--additional-info {
    // ...
  }
}

The plugin prints:

Error: Could not resolve the styleName 'btn--additional-info'.

      at node_modules/babel-plugin-react-css-modules/dist/browser/getClassName.js:83:15
          at Array.map (<anonymous>)
      at Object.<anonymous>.exports.default (node_modules/babel-plugin-react-css-modules/dist/browser/getClassName.js:66:6)

My webpack config:

  {
    rules: [
      {
        test: /\.less$/i,
        include: path.resolve(__dirname, 'src'),
        use: ExtractTextPlugin.extract({
          use: [
            {
              loader: 'css-loader',
              options: {
                importLoader: 1,
                modules: true,
                localIdentName: '[local]___[hash:base64:5]',
              },
            },
            'less-loader',
          ],
          fallback: 'style-loader',
        }),
      },
      {
        test: /\.(jsx|js)$/,
        include: path.resolve(__dirname, 'src'),
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: require('./.babelrc.json'),
        },
      },
    ],
  }

My Babel config (.babelrc.json):

    {
      "presets": [
        "es2015",
        "react"
      ],
      "plugins": [
        [
          "babel-plugin-react-css-modules",
          {
            "filetypes": {
              ".less": {
                "syntax": "postcss-less"
              }
            },
            "generateScopedName": "[local]___[hash:base64:5]"
          }
        ]
      ]
    }
michalstocki commented 7 years ago

Finally I got it to work by adding postcss-nested plugin to a .babelrc.json configuration:

@@ -10,7 +13,10 @@
           {
             "filetypes": {
               ".less": {
-                "syntax": "postcss-less"
+                "syntax": "postcss-less",
+                "plugins": [
+                  "postcss-nested"
+                ]
               }
             },
             "generateScopedName": "[local]___[hash:base64:5]"