简体   繁体   中英

Unable to skip 3rd party library CSS from CSS-Module transformation

I am trying CSS Modules for the first time with React and Webpack and I came across at least three ways to achieve it:

  1. css-loader
  2. react-css-modules
  3. babel-plugin-react-css-modules

I went with babel-plugin-react-css-modules in order to balance code simplicity and performance and everything seems to be working fine except for one thing: my 3rd party libraries (Bootstrap and Font Awesome) are also included in CSS Modules transformation.

<NavLink to="/about" styleName="navigation-button"></NavLink>

The above assigns a properly transformed className to the NavLink . However, a span inside needs to refer to global styles in order to render an icon.

<span className="fa fa-info" />

The above span is not assigned a transformed className which is expected, but my bundled stylesheet does not have these CSS classes as they are being transformed into something else, to simulate local scope.

Below is the content in my .babelrc file to activate babel-plugin-react-css-modules :

{
  "presets": ["env", "react"],
  "plugins": [
    ["react-css-modules", {
      "generateScopedName": "[name]__[local]___[hash:base64:5]",
      "filetypes": {
        ".less": {
          "syntax": "postcss-less"
        }
      }
    }]
  ]
}

In my Webpack configuration, below is the section to configure css-loader for transforms:

{
    test: /\.(less|css)$/,
    exclude: /node_modules/,
    use: extractCSS.extract({
        fallback: 'style-loader',
        use: [
            {
                loader: 'css-loader',
                options: {
                    minimize: true,
                    modules: true,
                    sourceMap: true,
                    localIdentName: '[name]__[local]___[hash:base64:5]'
                }
            },
            {
                loader: 'less-loader'
            }
        ]
    })
}

As far as I have read, the above rule should exclude the library stylesheets and I also tried adding another rule specifically for the excluded stylesheets, however that did not seem to work, as I guess as those stylesheets were still transformed with the original rule.

In order to import CSS from the two libraries, I have the below two lines in my parent stylesheet that declares some global styles:

@import '../../../node_modules/bootstrap/dist/css/bootstrap.min.css';
@import '../../../node_modules/font-awesome/css/font-awesome.min.css';

I find these two approaches below might be helpful:

In short, there seems to be no options to ignore/exclude certain paths from being modularized by the css-modules webpack plugin so far. Ideally it should be supported by the plugin, but here're some approaches you can try out:

use two webpack rules to utilise the webpack rule exclusion/inclusion :

module.exports = {
  rules: [
    {
      test: /\.css$/,
      exclude: /node_modules/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            modules: true,
            localIdentName: '[path]__[local]___[hash:base64:5]',
          },
        },
      ],
    },
    {
      test: /\.css$/,
      include: /node_modules/,
      use: ['style-loader', 'css-loader']
    }
  ]
}

...or, inject into webpack's getLocalIdent from the second answer above to manually exclude certain paths.

const getLocalIdent = require('css-loader/lib/getLocalIdent');

{
  loader: 'css-loader',
  options: {
    modules: true,
    localIdentName: '[path][name]__[local]--[hash:base64:5]',
    getLocalIdent: (loaderContext, localIdentName, localName, options) => {
      return loaderContext.resourcePath.includes('semantic-ui-css') ?
        localName :
        getLocalIdent(loaderContext, localIdentName, localName, options);
    }
  }
}

For me using :global worked :

.my-component {
    :global {
        .external-ui-component {
           padding: 16px;
           // Some other styling adjustments here
        }
        ...
    }
}

Ps: for doing it with webpack config, please see another answer.

source

Updated solution from playing771

 {
    loader: 'css-loader',
    options: {
      modules: {
        auto: (resourcePath) => !resourcePath.includes('node_modules'),
        localIdentName: '[name]__[local]__[hash:base64:5]',
      },
    },
 },

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM