DEV Community

Peiwen Lu
Peiwen Lu

Posted on • Originally published at peiwen.lu

Selectors for Humans, Hashes for Machines

One aspect of CSS modules that I truly appreciate is its ability to compress class names into very short hashes. This feature allows me to keep my CSS selectors as long and descriptive as needed, while still compressing them into concise three or four character hashes. It aligns with my rule for CSS: selectors should be written for human readability, but compressed for machine efficiency.

However, setting the hash length too short can lead to hidden hash collision issues which are not easy to detect until you encounter a bug. To address this, I've developed a solution in Vite that utilizes the getJSON callback function provided by postcss-modules. By storing all used selector hashes in a map, we can easily check for any duplicates. If a duplicate hash is detected, an error is immediately raised, and the build process is halted. In such cases, the issue can be resolved by simply increasing the hash length and rebuilding the project.

// vite.config.js

let modulesConfig = {
  generateScopedName: "[local]-[hash:base64:4]" // original selectors and four-character hashes in the development environment
};

if (process.env.IS_PROD) {
  const fileSet = {};
  const hashSet = {};
  modulesConfig = {
    getJSON: function (file, json) {
      if (fileSet[file]) return; // skip checking files that have already been processed

      fileSet[file] = true;
      Object.values(json).forEach((i) => {
        if (hashSet[i]) throw Error("CSS MODULES HASH COLLISION ERROR");
        hashSet[i] = true;
      });
    },
    generateScopedName: "[hash:base64:2]" // two-character hashes in the production environment, increase the hash length for needed
  };
}


export default defineConfig({
  css: {
    modules: modulesConfig,
  }
});
Enter fullscreen mode Exit fullscreen mode

I have implemented this code snippet in my react-template, and I am extremely satisfied with the results. It strikes a perfect balance between readability and efficiency, ensuring that my CSS is both human-friendly and optimized for production.

Top comments (0)