Skip to content

CSS Module class name collisions #10190

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

Open
mbfisher opened this issue Dec 3, 2020 · 1 comment
Open

CSS Module class name collisions #10190

mbfisher opened this issue Dec 3, 2020 · 1 comment

Comments

@mbfisher
Copy link

mbfisher commented Dec 3, 2020

I raised this as a Discussion but haven't had any bites!

Hi! I work at Skyscanner. We build our UIs with React, and use react-scripts to build our micro-frontends and our component library Backpack.

Recently we've seen a few bugs related to the way CSS Module classNames are generated.

As an example, we have a React component we use to display the footer at the bottom of every page on the site:

// src/components/Footer/Footer.module.scss

.Footer {
  background-color: pink;
}
// src/components/Footer/Footer.jsx

import STYLES from './Footer.module.scss`;

export default function Footer() {
  return (
    <div className={STYLES.Footer}>
      ...
    </div>
  );
}

This results in the following HTML for the footer:

<style>
.Footer_Footer__1CwiK {
  background-color: pink;
}
</style>
...
<div class="Footer_Footer__1CwiK">
   ...
</div>

The value of the class property is generated by this getCSSModuleLocalIdent function, following this formula:

${fileOrFolderName}_${fileName}__${hashOfRelativePath}

The last component of the value, the hash 1CwiK, is a hash generated based on the relative path of CSS Module file i.e. src/components/Footer/Footer.module.scss.

The bug occurs when 2 different components, in to 2 different packages, have a CSS Module with the same relative path. For example, we have a component we use to display ads on the site, and an Ad has a Footer. This is not the same Footer component as above, but one local to the Ad component. The Ad package has files at src/components/Footer/Footer.jsx and src/components/Footer/Footer.module.scss.

This results in 2 CSS rules on the page for .Footer_Footer__1CwiK, which means Ad styles leak in to the Footer and vice versa.

The getCSSModuleLocalIdent function states that the hashes it produces "will be unique across a project, and close to globally unique.". For us, it's not close enough to globally unique! 😄

Would you consider updating the hashing approach to be globally unique? There's lots to discuss in terms of options, so far the ideas we've kicked around are:

  • Use the absolute path
  • Include the package name [and version] in the hash
  • Use contenthash

We use a fork of create-react-app internally; backpack-react-scripts. Our last resort would be to update the getCSSModuleLocalIdent function there. So far our fork only contains changes to the react-scripts package; changing that function would require us to fork react-dev-utils as well. In an ideal world we'd like an upstream change because it will allow others to benefit from it, but also because we'd like to move away from our fork and use react-scripts directly, so we're reluctant to diverge from it further.

If you've gotten this far, thanks for reading!

@pstrh
Copy link

pstrh commented Jan 27, 2022

Seeing the same issue in our projects. The hash generation based on the relative path was introduced by purpose in #6875 (has been based on the absolute path before). I think a per project uniqueness by adding the project name to the hash as suggested in #9134 would be helpful.

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

No branches or pull requests

2 participants