DocSpring / craco-antd

A craco plugin to use Ant Design with create-react-app
MIT License
234 stars 49 forks source link

Can't get CSS modules and antd styles to work at the same time #14

Open gregoryforel opened 5 years ago

gregoryforel commented 5 years ago

Hi @ndbroadbent , @patricklafrance !

I am trying to get CSS Modules to work as well as antd.

So far, I either have antd's styles working, or CSS Modules, but I can't get both to work at the same time.

To get antd's styling to work, I have to comment out cssLoaderOptions... (see in my code below), but then CSS Modules don't work anymore.

If I leave cssLoaderOptions, CSS Modules work, but antd seems to lose some styling. For example, I can still see some animation when clicking on a button, but the color styling and shaping is gone.

Here's a link to my repo.

const CracoAntDesignPlugin = require("craco-antd");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
const WebpackBar = require("webpackbar");

// Don't open the browser during development
process.env.BROWSER = "none";

module.exports = {
  webpack: {
    plugins: [
      new WebpackBar({ profile: true }),
      ...(process.env.NODE_ENV === "development"
        ? [new BundleAnalyzerPlugin({ openAnalyzer: false })]
        : []),
    ],
  },
  plugins: [
    {
      plugin: CracoAntDesignPlugin,

      options: {
        modifyLessRule: function(lessRule, _context) {       
          lessRule.test = /\.less$/;
          lessRule.exclude = undefined;

          // console.log('lessRule', lessRule)
          // console.log('JSON', JSON.stringify(lessRule.use))        

          return lessRule;
        },       

        // CSS Modules. This makes the styling of antd to stop working. If I comment out, antd's styling works.
        cssLoaderOptions: {
          modules: true,
          localIdentName: `${
            process.env.NODE_ENV === "production"
              ? "[local]_[hash:base64:5]"
              : "[path][name]__[local]-"
          }-[hash:base64:8]`,
        },
      },
    },
  ],
};

I'm using those versions:

"@craco/craco": "5.0.2",
"antd": "^3.16.6",
"craco-antd": "1.10.0",
"react-scripts": "3.0.0",
"typescript": "^3.4.5"

This is the bundle analyzer when antd works (when I comment out cssLoaderOptions), 2.44Mb:

image

This is when CSS Module work (2.36Mb)

image

gregoryforel commented 5 years ago

@ndbroadbent , @patricklafrance gents! I'm really struggling with this one, I'd greatly appreciate some help, or even be told that this repo is not maintained anymore so I can try to move on to another solution. Thanks in advance

ndbroadbent commented 5 years ago

Hi @gregoryforel! Sorry for the lack of response!

My philosophy with this repo is that I just wanted to share what we have so far, but unfortunately I do not have any time to actively investigate issues like this and respond to any support requests. I would like for this repo to be more of a community effort where people can take what they need, but also contribute any bug fixes or features.

I wouldn’t say that this repo is unmaintained, but maybe “casually maintained”. Because I am always happy to merge in PRs. But it’s definitely more of a casual project where I don’t have the bandwidth to look into issues like this. Sorry about that!

It might even make sense for us to hire a contractor for a few hours, so that they can investigate this issue and try to find a good solution. (But I personally don’t have the resources or time to organize this.) But that would be one option.

I think I have built a good base with a solid test suite that should be easy to work with. Maybe you could add a new failing test case that shows some expected output, and I could have a look to see if I can fix the failing test?

Sorry again for not being able to jump in right now and fix things!

gregoryforel commented 5 years ago

@ndbroadbent thanks so much for the answer. I perfectly understand the lack of resource, same here. I can't file a failing test case yet, simply because I'm not a dev. I'll see if my friends can do it, but I'm afraid I might simply be using the lib the wrong way. I'll investigate further, if I end up hiring a contractor to solve the issue, I'll definitely share my findings / PR.

patricklafrance commented 5 years ago

Hi @gregoryforel

Sorry I missed the previous notifications for this issue.

I am in a situation similar to @ndbroadbent I dont have the needed resources to offer much support.

I gladly fix issues for the core repository of CRACO but sadly I cannot offer support for plugin development, other that understanding why it doesn't work with CRACO.

In this case, this is more of a Webpack + ANTD issue.

Thank you

Patrick

mdluo commented 5 years ago

@gregoryforel Here's my solution:

const path = require('path');

const WebpackBar = require('webpackbar');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CracoAntDesignPlugin = require('craco-antd');
const CracoLessPlugin = require('craco-less');

module.exports = {
  webpack: {
    plugins: [
      new WebpackBar({ profile: true }),
      ...(process.env.NODE_ENV === 'development'
        ? [new BundleAnalyzerPlugin({ openAnalyzer: false })]
        : []),
    ],
  },
  plugins: [
    {
      plugin: CracoAntDesignPlugin,
      options: {
        customizeTheme: getThemeVariables({
          dark: true,
        }),
        customizeThemeLessPath: path.join(__dirname, 'src/styles/theme.less'),
      },
    },
    {
      plugin: CracoLessPlugin,
      options: {
        cssLoaderOptions: {
          modules: { localIdentName: '[local]_[hash:base64:5]' },
        },
        modifyLessRule: function(lessRule, _context) {
          lessRule.test = /\.(module)\.(less)$/;
          lessRule.exclude = path.join(__dirname, 'node_modules');
          return lessRule;
        },
      },
    },
  ],
};

The first CracoAntDesignPlugin is to load the antd components and the customize theme variables file. And CSS modules option is turned off (by default), otherwise the antd component's styles won't be load properly.

And the second CracoLessPlugin is to load application-level .module.less files, with CSS modules enabled.

Updated the cssLoaderOptions, thanks to @pmosconi 's comment

rnel commented 4 years ago

@mdluo, another solution is to use getLocalIdent:

const path = require('path');
const CracoAntDesignPlugin = require("craco-antd");
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); // included in Create React App

module.exports = {
  plugins: [
    {
      plugin: CracoAntDesignPlugin,
      options: {
        cssLoaderOptions: {
          modules: true,
          getLocalIdent: (context, localIdentName, localName, options) => {
            if (context.resourcePath.includes('node_modules')) {
              return localName;
            }
            return getCSSModuleLocalIdent(context, localIdentName, localName, options);
          }
        },
        customizeThemeLessPath: path.join(__dirname, 'src/styles/theme.less')
      }
    }
  ]
};

For third-party LESS files (i.e. those inside node_modules), you should return localName to avoid adding hash to css class names.

gregoryforel commented 4 years ago

@mdluo, @rnel thanks for the feedback! I gave up a while ago and simply created my own fork of react-scripts. I thought it was overkill, but I could get everything working in 20mn.

pmosconi commented 4 years ago

cssLoaderOptions syntax has changed: it is now modules: {localIdentName: "[local]_[hash:base64:5]"},

@mdluo's solutions can be changed easily, while I've not been able to make @rnel's code working.

ermolaevp commented 4 years ago

@pmosconi add @rnel's getLocalIdent to the modules config section next to the localIdentName key. This is the only solution that works for me.

weiliang903 commented 4 years ago

@gregoryforel It's not working for me.

"craco-antd": "^1.18.0",
"@craco/craco": "^5.6.4",
"craco-less": "^1.17.0",

It's ok.

  plugins: [
    {
      plugin: CracoAntDesignPlugin,
      options: {
        cssLoaderOptions: {
          modules: {
            getLocalIdent: (context, localIdentName, localName, options) => {
              if (context.resourcePath.includes('node_modules')) {
                return localName;
              }
              return getCSSModuleLocalIdent(context, localIdentName, localName, options);
            }
          }
        },
        customizeTheme: {
          '@primary-color': '#fe8f24'
        }
      }
    }
  ]
empz commented 4 years ago

@weiliang903

The snippet you posted worked for me. CSS modules are working. But normal imports aren't.

I want to be able to use both.

For non-module imports I want to just be able to do import "./styles.less". For CSS modules imports I want to be able to do import styles from "./styles.module.less"

Is this achievable?

gregoryforel commented 4 years ago

@eparizzi I think so. I'm not great at regex, but I'd suggest you try to use the less module twice, once where you search for .module.less AND NOT for .less only, and another with the opposite rule.

IronSean commented 3 years ago

I took inspiration from all of the above and ended up with this

const path = require(`path`);
const CracoAntDesignPlugin = require("craco-antd");
const CracoLessPlugin = require("craco-less");
const getCSSModuleLocalIdent = require("react-dev-utils/getCSSModuleLocalIdent");

module.exports = {
  plugins: [
    {
      plugin: CracoAntDesignPlugin,
      options: {
        customizeTheme: {
          // "@primary-color": "#1DA57A",
          // "@link-color": "#1DA57A",
        },
        customizeThemeLessPath: path.join(__dirname, "src/styles/theme.less"),
      },
    },
    {
      plugin: CracoLessPlugin,
      options: {
        cssLoaderOptions: {
          modules: {
            getLocalIdent: (context, localIdentName, localName, options) => {
              if (context.resourcePath.includes("node_modules")) {
                return localName;
              }
              return getCSSModuleLocalIdent(
                context,
                localIdentName,
                localName,
                options
              );
            },
          },
        },
        lessLoaderOptions: {
          lessOptions: {
            modifyVars: { "@primary-color": "#1DA57A" },
            javascriptEnabled: true,
          },
        },
        modifyLessRule: function (lessRule, _context) {
          lessRule.test = /\.(module)\.(less)$/;
          lessRule.exclude = path.join(__dirname, "node_modules");
          return lessRule;
        },
      },
    },
  ],
};

Some of it might be redundant though. For instance is modifyLessRule still needed when getLocalIdent handles the check too?