Using LESS variables in a react project with .less files imported by the components

Viewed 2046

I am in a react project, compiled using webpack, and using less. The root of the application imports a top-level styles.less which imports variables.less which defines a bunch of LESS variables.

There is also a directory components which has a number of folders, each folder has a styles.less and an index.jsx which imports it.

At the moment, if I try to access variables from the components (e.g. Card/styles.less) I get a 'Variable [x] is undefined` error.

Is there a way I can make these variables 'globally accessible' to all the less in the project?

Versions:

  • React 16.7
  • webpack 4.28
  • babel 7.5
  • less 3.9
  • less-loader 5.0

webpack config

   module: {
        rules: [
            {
                test: /\.less$/,
                use: [
                    'style-loader',
                    'css-loader',
                    {
                        loader: 'less-loader',
                        options: {
                            modifyVars: { // this modifies the antd variables
                                'primary-color': '#5c31a8',
                                'border-radius-base': '2px'
                            },
                            javascriptEnabled: true
                        }
                    }
                ]
            }
        ]
    },
2 Answers

I have had the same issue before, thought I would add my solution incase anyone else stumbles across this:

You can write a custom Webpack loader to preload less files:

lessImports.js

const loaderUtils = require('loader-utils');
const reduce = require('lodash/reduce');

const getFileNames = ({ files, fileName }) => {
  const index = files.indexOf(fileName);
  if (index >= 0) {
    return files.slice(0, index);
  }
  return files;
};

const addNewImports = ({ file, source, alias }) =>
  reduce(
    file,
    (existingFiles, file) => {
      return `${existingFiles}\n @import "${alias}/${file}.less";`;
    },
    source,
  );

const addGlobalImports = ({ files, fileName, source, alias }) => {
  const getFiles = getFileNames({
    files,
    fileName,
  });
  return addNewImports({
    files: getFiles,
    source,
    alias,
  });
};

module.exports = function lessImport(source) {
  const options = loaderUtils.getOptions(this);

  const fileType = loaderUtils.interpolateName(this, '[ext]', {});
  const fileName = loaderUtils.interpolateName(this, '[name]', {});
  const files = (options && options.files) || [];
  const alias = (options && options.alias) || '';

  let processedLess = source;
  if (fileType === 'less') {
    processedLess = addGlobalImports({
      files,
      fileName,
      source,
      alias,
    });
  }

  return processedLess;
};

And load it in the Webpack config:

  module: {
    rules: [
      {
        test: /\.(less)$/,
        use: [
          {
            loader: 'less-loader', // compiles Less to CSS
          },
          {
            loader: 'lessImports.js',
            options: {
              files: ['variables'],
              alias: '~less',
            },
          },
        ],
      },
    ],
  },
Related