react-dates v16.3: ejected create-react-app with CSS Modules enabled adds different local identifiers than SingleDatePicker's

Created on 9 Mar 2018  路  13Comments  路  Source: airbnb/react-dates

Please see the attached screenshots for the easiest reference to my issue.

I have a project built using the latest create-react-app and of course react-dates. I ejected create-react-app so that I could enable CSS Modules and some other goodies, but after doing so the _datepicker.css file ends up with different class names.

The screenshots show CSS Modules successfully getting imported as well as the final class names, along with how SingleDatePicker's class name gets rendered. The issue is visible in the 2 webpack screenshots where I found the problem - any plans to allow adding local Identifiers to classes? Or is there a better way to resolve this? I was hoping there would be some way to enforce class name inheritance from CSS Modules

broken-datepicker
component-class-name-hashing
_datepicker-in-index-html
webpack-file-mod
webpack-file-fix

Most helpful comment

I faced the same problem. My fix was to make a clause in the loaders specifically for node_modules css to avoid them being loaded as css modules:

{
        test: /node_modules\/.*\.css$/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              sourceMap: true,
            },
          },
        ],
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              modules: true,
              sourceMap: true,
              importLoaders: 1,
              localIdentName: '[name]__[local]__[hash:base64:5]',
            },
          },
        ],
      },

All 13 comments

Hi @mrgrotts, I think that this is actually possible but you'd be the first to use the feature! :) It would require your own theme/interface registration instead of using the initialize script.

Here is what you would need to do instead of calling import 'react-dates/initialize';:

import CSSInterface, { registerCSSInterfaceNamespace } from 'react-with-styles-interface-css';
import registerInterfaceWithDefaultTheme from 'react-dates/lib/utils/registerInterfaceWithDefaultTheme';

registerCSSInterfaceNamespace('datepicker');
registerInterfaceWithDefaultTheme(CSSInterface);

After you do this, you should be able to import and use your react-dates components as needed.

In theory, that should prefix all the classnames in the components with whatever string you provide (https://github.com/airbnb/react-with-styles-interface-css#interface). Let me know how it goes! If it doesn't work as is, we may need to go back and do some fixes to react-with-styles-interface-css.

Well that sounds exciting! I will give this a try when I get home. Thank you for the help either way :)

I gave this solution a try. I npm installed react-with-styles-interface-css and added the lines above in. Webpack compiles successfully and launches but the app crashes in browser right away with this error: "Uncaught TypeError: Object(...) is not a function"

So first I got that working by switching the import up:

import 'react-dates/lib/css/_datepicker.css';
import CSSInterface from 'react-with-styles-interface-css';
import registerCSSInterfaceNamespace from 'react-with-styles-interface-css/dist/utils/registerCSSInterfaceNamespace';
import registerInterfaceWithDefaultTheme from 'react-dates/lib/utils/registerInterfaceWithDefaultTheme';

registerCSSInterfaceNamespace('_datepicker');
registerInterfaceWithDefaultTheme(CSSInterface);

From here, I can get the prefixed namespace working correctly but adding a hashed suffix, like I was originally, does not because the namespace can only prefix the class name.

I fooled around for a bit but wasn't able to find the solution to that one yet. Seems like you need a handler for suffixes added during Webpack's build process, but that may not be possible because of loaderContext :(

Consider the following code that generates the hash: https://github.com/webpack-contrib/css-loader/blob/master/lib/getLocalIdent.js

I was facing the same issue. For other people who end up here needing a quick (and dirty) fix:

You can use the "Without Webpack" section of the README to configure these styles to be added directly in your <head> in which case Webpack won't change your classnames.

This approach comes with its cons, so hopefully other more maintainable approaches can still be found!

I faced the same problem. My fix was to make a clause in the loaders specifically for node_modules css to avoid them being loaded as css modules:

{
        test: /node_modules\/.*\.css$/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              sourceMap: true,
            },
          },
        ],
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              modules: true,
              sourceMap: true,
              importLoaders: 1,
              localIdentName: '[name]__[local]__[hash:base64:5]',
            },
          },
        ],
      },

@philippefutureboy thanks a lot for your solution it works fine for UNIX. If someone is using Windows you should change this line
test: /node_modules\/.*\.css$/,
on this one
test: /node_modules[\\\/].*\.css$/,

@philippefutureboy thank you very much it is working but if I do it my global styles are not being imported. Any ideas?

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css'; 
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
{
    test: /node_modules\/.*\.css$/,
    use: [{
        loader: 'style-loader',
        },
        {
        loader: 'css-loader',
        options: {
                sourceMap: true,
                    },
                },
            ],
        }, {
    test: /\.scss/,
    exclude: /node_modules/,
    use: [{
        loader: 'style-loader',
    },
    {
        loader: 'css-loader',
            options: {
                modules: true,
                sourceMap: true,
                importLoaders: 1,
                localIdentName: '[name]__[local]__[hash:base64:5]',
                },
                },
        'sass-loader'
                ],
            },

@gdi-user02 The file you are importing in App.js is a .css file. You seem to have forgotten to add a config block for .css files in your config.

@philippefutureboy thank you for quick response, any idea how can achieve that? Not much experience with Webpack.

@gdi-user02 You could try

{
  test: /node_modules\/.*\.css$/,
  use: [
    {
      loader: 'style-loader',
    },
    {
      loader: 'css-loader',
      options: {
        sourceMap: true,
      },
    },
  ],
},
{
- test: /\.scss/,
+ test: /\.(scss|css)$/,
  exclude: /node_modules/,
  use: [
    {
      loader: 'style-loader',
    },
    {
      loader: 'css-loader',
      options: {
        modules: true,
        sourceMap: true,
        importLoaders: 1,
        localIdentName: '[name]__[local]__[hash:base64:5]',
      },
    },
    'sass-loader',
  ],
},

In which case this config will match .scss files as well as .css files. style-loader and css-loader, defined in the use array, should be enough to handle css files.

@Jokinen that wouldn't work given that @gdi-user02 intends to use CSS as global CSS. Instead, I'd suggest something like this:

        test: /node_modules\/.*\.css$/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              sourceMap: true,
            },
          },
        ],
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              sourceMap: true,
              importLoaders: 1,
              localIdentName: '[name]__[local]__[hash:base64:5]',
            },
          },
        ],
      },
  {
    test: /\.scss/,
    exclude: /node_modules/,
    use: [
      {
        loader: 'style-loader',
      },
      {
        loader: 'css-loader',
        options: {
          modules: true,
          sourceMap: true,
          importLoaders: 1,
          localIdentName: '[name]__[local]__[hash:base64:5]',
        },
      },
      'sass-loader'
    ],
  },

I think it would be good if another cssmodules css file was generated along with the the regular css file. in the new generated cssmodules file, all classes should be global, this will make the life of those who use css modules easier.

It won't be hard to generate such a file using the buildCSS script https://github.com/airbnb/react-dates/blob/master/scripts/buildCSS.js, all what needs to be done is prefix all classes with :global or put all the classes into one huge :global block (:global {})

I think it would be good if another cssmodules css file was generated along with the the regular css file. in the new generated cssmodules file, all classes should be global, this will make the life of those who use css modules easier.

Is there any chance that this may happen? Am also running into the same issue and will use a workaround otherwise, but it would be nice to not have to :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Jesus-Gonzalez picture Jesus-Gonzalez  路  3Comments

Adam-Pendleton picture Adam-Pendleton  路  3Comments

augnustin picture augnustin  路  3Comments

yokomizor picture yokomizor  路  3Comments

mrseanbaines picture mrseanbaines  路  3Comments