Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dashes in CSS class names with Gatsby v3 (css-loader v5)

In Gatsby v2 you could enable this syntax className={styles["block__element--modifier"]} by adding the following code to gatsby-node.js:

const process_rule = rule => {
  if (rule.oneOf) {
    return {
      ...rule,
      oneOf: rule.oneOf.map(process_rule),
    };
  }

  if (Array.isArray(rule.use)) {
    return {
      ...rule,
      use: rule.use.map(use => {
        const css_loader_regex = /\/css-loader\//;

        if (!css_loader_regex.test(use.loader)) {
          return use;
        }

        return {
          ...use,
          options: {
            ...use.options,
            camelCase: false,
          },
        };
      }),
    };
  }

  return rule;
};

exports.onCreateWebpackConfig = ({ getConfig, actions }) => {
  const config = getConfig();

  const new_config = {
    ...config,
    module: {
      ...config.module,
      rules: config.module.rules.map(process_rule),
    },
  };
  actions.replaceWebpackConfig(new_config);
};

However Gatsby v3 is using css-loader v5 which no longer accepts the camelCase: false field in options. Instead it has the field exportLocalsConvention which can take the value asIs, but when enabling namedExport the compiler throws the error:

The "modules.namedExport" option requires the "modules.exportLocalsConvention" option to be "camelCaseOnly" or "dashesOnly".

I've tried:

options: {
  ...use.options,
  modules: {
    ...use.options.modules,
    auto: true,
    exportLocalsConvention: "asIs",
    exportOnlyLocals: false,
    namedExport: false,
  },
},

But this doesn't make the CSS class names accessible in JSX and gives the warning:

warn Attempted import error: 'block' is not exported from './styles.module.css' (imported as 'styles').

It looks like namedExport must be set to true in order to access the compiled class names in JSX however then css-loader will only accept camelCaseOnly or dashesOnly for exportLocalsConvention.

I'm not sure how to enable the same functionality as Gatsby v2 in v3. I'd like to be able to continue using the className={styles["block__element--modifier"]} syntax because it makes identifying CSS classes easy and also just keeps things consistent between CSS and JSX (also I'd prefer not having to rewrite a bunch of my code).

I'm importing styles like the Gatsby v2 to v3 migration guide explains:

import * as styles from "./styles.module.css"

I've also tried importing them in the old way (import styles from "./styles.module.css") but it made no difference unfortunately.

like image 364
pks Avatar asked Nov 06 '22 02:11

pks


1 Answers

So it turns out the issue is with the esModule field in the css-loader options. It is enabled by default and:

generates JS modules that use the ES modules syntax. There are some cases in which using ES modules is beneficial, like in the case of module concatenation and tree shaking.

As far as I understand it, this converts CSS class names into JS variables, which can't have hyphens so instead they are changed to camelcase.

So to keep the hyphens in the CSS class names and use the syntax className={styles["block__element--modifier"]) we need to override the css-loader options with:

options: {
  ...use.options,
  esModule: false,
  modules: {
    exportLocalsConvention: "asIs",
    namedExport: false,
  },
},

However I am still running into a build error when passing these options directly to webpack config through gatsby-node.js but have found a workaround using the Gatsby plugin gatsby-plugin-postcss (only 129B minified + gzipped) with these options in gatsby-config.js:

{
  resolve: "gatsby-plugin-postcss",
  options: {
    cssLoaderOptions: {
      esModule: false,
      modules: {
        exportLocalsConvention: "asIs",
        namedExport: false,
      },
    },
  },
},

This will produce the warning:

warn You did not set any plugins, parser, or stringifier. Right now, PostCSS does nothing. Pick plugins for your case on https://www.postcss.parts/ and use them in postcss.config.js.

However it's just a warning that doesn't cause any other issues!

With this implementation you will need to import styles using the Gatsby v2 method:

import styles from "./styles.module.css";

Bear in mind that this prevents the default tree shaking behaviour of Gatbsy v3 / css-loader v5.

Also it turns out this was actually covered in the migration guide here. It however does not indicate to use exportLocalsConvention: "asIs" which, from my testing, is required.

like image 65
pks Avatar answered Nov 12 '22 10:11

pks