Search code examples
reactjswebpacknext.jscss-modulescss-loader

How to hash CSS class names in Nextjs?


How can I edit localIdentName field of css-loader in Webpack configuration in Nextjs so that I can hash/hide/obfuscate css class names?

The example below is from the New York Times. Note the class names:

enter image description here


Solution

  • Unfortunately there is no build in support in Nextjs to pass custom configuration to Webpack loaders. But we can work around it by using next.config.js.

    First, create next.config.js in the root of your project directory.

    For Nextjs 11

    module.exports = {
      webpack(config, { buildId, dev, isServer, defaultLoaders, webpack }) {
        config.module.rules[3].oneOf.forEach((moduleLoader, i) => {
          Array.isArray(moduleLoader.use) &&
            moduleLoader.use.forEach((l) => {
              if (
                l.loader.includes("\\css-loader") &&
                !l.loader.includes("postcss-loader")
              ) {
                const { getLocalIdent, ...others } = l.options.modules;
    
                l.options = {
                  ...l.options,
                  modules: {
                    ...others,
                    localIdentName: "[hash:base64:6]",
                  },
                };
              }
            });
        });
        return config;
      },
    };
    

    For Next.js 10.2 or a newer version:

    module.exports = {
      webpack(config, { buildId, dev, isServer, defaultLoaders, webpack }) {
        config.module.rules[3].oneOf.forEach((moduleLoader, i) => {
          Array.isArray(moduleLoader.use) &&
            moduleLoader.use.forEach((l) => {
              if (
                l.loader.includes("\\css-loader") &&
                !l.loader.includes("postcss-loader")
              ) {
                const { getLocalIdent, ...others } = l.options.modules;
    
                l.options = {
                  ...l.options,
                  modules: {
                    ...others,
                    localIdentName: "[hash:base64:6]",
                  },
                };
              }
            });
        });
        return config;
      },
    };
    

    Otherwise use this:

    module.exports = {
      webpack(config, { buildId, dev, isServer, defaultLoaders, webpack }) {
        config.module.rules[1].oneOf.forEach((moduleLoader, i) => {
          Array.isArray(moduleLoader.use) &&
            moduleLoader.use.forEach((l) => {
              if (
                l.loader.includes('\\css-loader') &&
                !l.loader.includes('postcss-loader')
              ) {
                const { getLocalIdent, ...others } = l.options.modules;
    
                l.options = {
                  ...l.options,
                  modules: {
                    ...others,
                    localIdentName: '[hash:base64:6]',
                  },
                };
              }
            });
        });
        return config;
      },
    };
    

    If you want to hash the class names only in production, you can use process.env.NODE_ENV with an if statement. Like this:

    module.exports = {
      webpack(config, { buildId, dev, isServer, defaultLoaders, webpack }) {
        if (process.env.NODE_ENV === "production") {
          ...
          ...
    
          return config;
        } else {
          return config;
        }
      },
    };