Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not compatible with css-loader v4 #291

Open
fracmak opened this issue Aug 3, 2020 · 28 comments
Open

Not compatible with css-loader v4 #291

fracmak opened this issue Aug 3, 2020 · 28 comments

Comments

@fracmak
Copy link

fracmak commented Aug 3, 2020

It appears the new css-loader has changed their hash algorithm to use md4 instead of md5 (related to webpack/loader-utils#168 ), this means the hash generated by this babel plugin no longer matches what css-loader's hash is with no clear way around it

@birdofpreyru
Copy link

Here is my fork of the plugin, with fixed css-loader compatibility:
https://www.npmjs.com/package/@dr.pogodin/babel-plugin-react-css-modules

@epotockiy
Copy link

@birdofpreyru why you didn't try to create PR for this fix?

@birdofpreyru
Copy link

To move fast. It looks like the author does not maintain the package actively for a long time. I don't want to wait for review by the author, don't really want to discuss updates of dependencies I like to do, etc. Once I got it working, it took me no time to setup release as a separate package, and now if I need any other corrections I can do them fast.

@bhj
Copy link

bhj commented Aug 31, 2020

@gajus mind taking a look? This can be a whale of an issue to troubleshoot if one isn't aware of the changes OP mentions. And thank you for this awesome library!

@Hless
Copy link

Hless commented Sep 22, 2020

Pfew, lifesaver this one.

Anyway, what are the plans to maintain that fork? Do you aim for it to replace this plugin at some point?

@birdofpreyru
Copy link

@Hless do you ask me? I use my fork in my React projects, thus in the foreseen future I am planning to maintain it functional and up-to-date. At the same time, I don't have any issues with what it does and how it works, thus probably won't do with it anything beyond ocasional dependency updates when something breaks for me, or somebody asks for it.

Everybody else following the thread: it is almost two months since the issue ticket was created, since no reply from the repo owner. I hope you see now my choice between fork and PR was very reasonable :)

@Hless
Copy link

Hless commented Sep 29, 2020

@birdofpreyru I suppose you're right about the fork, repo does not seem actively maintained anymore, thanks for your work.

I decided to refactor my codebase not use the styleName prop anymore, but to refactor it to the standard import/className workflow. Webpack config is hard enough to maintain without having to rely upon plugins that are not actively maintained by a larger audience

@birdofpreyru
Copy link

@Hless What is your plan regarding CSS class name scoping? styleName prop itself is not a big deal.

From my seat, CSS modules worked fine for me for three years without any maintenance, thus it feels like spending a few days now to fix the compatibility with the latest PostCSS will make it a smooth ride for next few years.

@Hless
Copy link

Hless commented Sep 29, 2020

Well I did some digging and unless I'm mistaken the CSS module feature is part of css-loader now. So if you were to use react scripts you can see the documentation here:
https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/

Since I'm using a custom webpack config, I configured it using css-loader directly:

{
        loader: require.resolve("css-loader"),
        options:{
               modules: {
                  localIdentName: "[name]__[local]__[hash:base64:5]"
                },
        },
}, 

(Note: this is the v4 syntax)

Documentation on css-loader is here:
https://webpack.js.org/loaders/css-loader/#localidentname

I could be completely missing something here, as of now the only reason for using this babel plugin would be the styleName prop?

@birdofpreyru
Copy link

It is a good point! I am also relying on this and another css-modules Babel plugins because in my setup I compile server-side version of code only with Babel, without Webpack; but your message makes me think that probably I should revisit how I do stuff, and indeed simplify it relying only on css-loader for style manipulations, and finding a better way, less dependent on the actual CSS transformations, to deel with styleName props (don't really want to abandon them). Anyway, in the closest future I intent to maintain my fork of this plugin, and maybe then come up with a full replacement which does not depend on that much stuff without active maintenance by a community.

@benmvp
Copy link
Contributor

benmvp commented Oct 22, 2020

So I've spent a few days trying to figure this out. 😅 The problem is a change in css-loader from this PR.

I've opened an issue here: webpack-contrib/css-loader#1214

The tl;dr is that the PR changed + to \x00 in the content it hashes, so the hashes generated by babel-plugin-react-css-modules (from here) is different than the one generated by css-loader (from here). That's why no matter how I tried to change how the content was hashed, the class names in the markup never matched those in the generated CSS.

@birdofpreyru
Copy link

Good job @benmvp , though it was figured out a while ago: webpack-contrib/css-loader#1152 and in the beginning of thread you have a link to my fork of the package which is patched to match the latest css-loader implementation, and also to rely on latest versions of all dependencies.

@benmvp
Copy link
Contributor

benmvp commented Oct 22, 2020

Good job @benmvp , though it was figured out a while ago: webpack-contrib/css-loader#1152 and in the beginning of thread you have a link to my fork of the package which is patched to match the latest css-loader implementation, and also to rely on latest versions of all dependencies.

Yeah @birdofpreyru I realized after doing the research and filing the bug that I should've just looked more closely at your fork to see what the problem was 🤦 Thanks for the links!

@fracmak
Copy link
Author

fracmak commented Oct 22, 2020

The way I got around it was by importing loader-utils@2.0.0, and then adding this to my babel.config.js

const { interpolateName } = require('loader-utils');

function generateScopedName(pattern) {
  const context = process.cwd();
  return function generate(localName, filepath) {
    const name = pattern.replace(/\[local\]/gi, localName);
    const loaderContext = {
      resourcePath: filepath,
    };

    const loaderOptions = {
      content: `${path.relative(context, filepath).replace(/\\/g, '/')}\u0000${localName}`,
      context,
    };

    const genericName = interpolateName(loaderContext, name, loaderOptions);
    return genericName
      .replace(new RegExp('[^a-zA-Z0-9\\-_\u00A0-\uFFFF]', 'g'), '-')
      .replace(/^((-?[0-9])|--)/, '_$1');
  };
}


const plugins = [
      [
        'babel-plugin-react-css-modules',
        {
          generateScopedName: generateScopedName('[name]__[local]_[hash:base64:5]'),
          exclude: 'node_modules',
        },
      ],
    ];

@benmvp
Copy link
Contributor

benmvp commented Oct 22, 2020

Yeah, I saw that it takes a string or a function, so that's a nice fix! 👏

@fracmak
Copy link
Author

fracmak commented Oct 22, 2020

Ya, since I mainly copied code that already existed in these underlying libraries, it would be nice if they were exposed so we could just flag on which behavior we wanted

@benmvp
Copy link
Contributor

benmvp commented Oct 23, 2020

@birdofpreyru - I've got a PR open (css-modules/generic-names#10) in generic-names to update to match css-loader. With it merged and released, it should make fixing the bug here in babel-plugin-react-css-modules as simple as bumping the dependency.

Hopefully we can get that merged here, but at the very least it should make maintaining the fix easier in your fork.

@zycoJamie
Copy link

Here is my fork of the plugin, with fixed css-loader compatibility:
https://www.npmjs.com/package/@dr.pogodin/babel-plugin-react-css-modules

nice,hash has matched css-loader,thank you!

@ThiefMaster
Copy link

@gajus could we please get an updated release that is compatible with the latest css-loader? :/

ThiefMaster added a commit to ThiefMaster/indico that referenced this issue Nov 25, 2020
Switched to a fork for the babel css module transform since upstream is
slow and not compatible with the latest css-loader anymore. See this
issue for details: gajus/babel-plugin-react-css-modules#291
@gajus
Copy link
Owner

gajus commented Nov 26, 2020

@gajus could we please get an updated release that is compatible with the latest css-loader? :/

If someone raises a PR, I will happily review it and integrate it.

@shallinta
Copy link

Upgrade generic-names to v3.0.0 will fix this rightly

@PaulSearcy
Copy link

PaulSearcy commented Dec 15, 2020

@gajus, @shallinta this isn't going to be as simple as npm i generic-names@3.0.0 and then making PR.

Initially cloned, installed packages and then ran the tests. 8/29 failed

Then I realized there is no package-lock.json and ^ (minor + patch) range is used for most dependencies. This means tests are going to pass or fail based on when the project was cloned and what versions the dependencies resolved to.

Edit

Read the whole thread and just dawned on me that @birdofpreyru also updated all the dependencies in his fork. If he would be kind enough to make a PR back here? For now I'm going to use his fork to keep the project I'm on moving.

@dr2009
Copy link

dr2009 commented Dec 17, 2020

const genericNames = require('generic-names'); // v3.0.0
const CSS_MODULE_LOCAL_IDENT_NAME = '[local]___[hash:base64:5]';
// old:  generateScopedName: CSS_MODULE_LOCAL_IDENT_NAME
generateScopedName: genericNames(CSS_MODULE_LOCAL_IDENT_NAME)

@eleven-net-cn
Copy link

const genericNames = require('generic-names'); // v3.0.0
const CSS_MODULE_LOCAL_IDENT_NAME = '[local]___[hash:base64:5]';
// old:  generateScopedName: CSS_MODULE_LOCAL_IDENT_NAME
generateScopedName: genericNames(CSS_MODULE_LOCAL_IDENT_NAME)

Nice !!!

@0es
Copy link

0es commented Jan 12, 2021

with another hash conversion problem, try to pass context to genericNames

const genericNames = require('generic-names'); // v3.0.0
const CSS_MODULE_LOCAL_IDENT_NAME = '[local]___[hash:base64:5]';
// old:  generateScopedName: CSS_MODULE_LOCAL_IDENT_NAME
generateScopedName: genericNames(CSS_MODULE_LOCAL_IDENT_NAME)
generateScopedName: genericNames(CSS_MODULE_LOCAL_IDENT_NAME, { context })

@zsjun
Copy link

zsjun commented Sep 2, 2021

解决:
在webpack.config.js中使用"generic-names": "^3.0.0", 生成类名,在babel.config.js中使用生成类名,也就是通过generic-names让两者达成一致。

webpack.config.js 配置如下:

const genericNames = require('generic-names');
const generateScope = genericNames(localIdentName, {

context: process.cwd(),

});
const getStyleLoaders = (cssOptions, preProcessor = []) => {

const loaders = [

// require.resolve('style-loader'),

MiniCssExtractPlugin.loader,

// isProd ? MiniCssExtractPlugin.loader : require.resolve('style-loader'),

{

loader: require.resolve('css-loader'),

options: cssOptions,

},

];

if (preProcessor.length > 0) {

for (let item of preProcessor) {

loaders.push(require.resolve(item));

}

}

return loaders;

};
{

test: /\.scss$/,

exclude: /node_modules/,

include: path.resolve(__dirname, 'src'),

use: getStyleLoaders(

{

importLoaders: 1,

// modules: {

// localIdentName: '[name]__[local]_[hash:base64:5]',

// localIdentContext: path.resolve(__dirname, 'src'),

// },

modules: {

getLocalIdent({ resourcePath }, localIdentName, localName) {

return generateScope(localName, resourcePath);

},

},

},

['sass-loader']

),

},

babel.config.js 配置如下:

const genericNames = require('generic-names'); // v3.0.0
// babel-plugin-react-css-modules

[

'react-css-modules',

{

generateScopedName: genericNames('[name]__[local]_[hash:base64:5]'),

filetypes: {

'.scss': {

syntax: 'postcss-scss',

},

},

exclude: 'node_modules',

},

],

@mbonaci
Copy link

mbonaci commented Oct 31, 2021

@Hless

the CSS module feature is part of css-loader now...
as of now the only reason for using this babel plugin would be the styleName prop?

AFAIK this was always the case

@owencyc
Copy link

owencyc commented Apr 13, 2022

解决: 在webpack.config.js中使用"generic-names": "^3.0.0", 生成类名,在babel.config.js中使用生成类名,也就是通过generic-names让两者达成一致。

webpack.config.js 配置如下:

const genericNames = require('generic-names');
const generateScope = genericNames(localIdentName, {

context: process.cwd(),

});
const getStyleLoaders = (cssOptions, preProcessor = []) => {

const loaders = [

// require.resolve('style-loader'),

MiniCssExtractPlugin.loader,

// isProd ? MiniCssExtractPlugin.loader : require.resolve('style-loader'),

{

loader: require.resolve('css-loader'),

options: cssOptions,

},

];

if (preProcessor.length > 0) {

for (let item of preProcessor) {

loaders.push(require.resolve(item));

}

}

return loaders;

};
{

test: /\.scss$/,

exclude: /node_modules/,

include: path.resolve(__dirname, 'src'),

use: getStyleLoaders(

{

importLoaders: 1,

// modules: {

// localIdentName: '[name]__[local]_[hash:base64:5]',

// localIdentContext: path.resolve(__dirname, 'src'),

// },

modules: {

getLocalIdent({ resourcePath }, localIdentName, localName) {

return generateScope(localName, resourcePath);

},

},

},

['sass-loader']

),

},

babel.config.js 配置如下:

const genericNames = require('generic-names'); // v3.0.0
// babel-plugin-react-css-modules

[

'react-css-modules',

{

generateScopedName: genericNames('[name]__[local]_[hash:base64:5]'),

filetypes: {

'.scss': {

syntax: 'postcss-scss',

},

},

exclude: 'node_modules',

},

],

老哥 这个稳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.