Using .less files with React
Asked Answered
M

8

26

I am trying to use .less files with a minimalist React app (created with create-react-app). I've added less and less-loader to my package.json as well as a module rule in my webpack.config.js file. The class reference is not being added to the HTML element however (should have class="customColor").

<p>Hello world in a custom color.</p>

I'm wondering what I'm doing wrong.

App.js

import React from 'react';
import './App.css';
import styles from './custom.less';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <p className={styles.customColor}>
          Hello world in a custom color.
        </p>
      </header>
    </div>
  );
}

export default App;

custom.less

@custom-color: red;

.customColor {
  color: @custom-color;
}

package.json

{
  "name": "sample",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-scripts": "3.1.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "devDependencies": {
    "less": "^3.10.3",
    "less-loader": "^5.0.0"
  }
}

webpack.config.js

module.exports = {
    rules: [{
        test: /\.less$/,
        use: [{
            loader: 'style-loader',
        }, {
            loader: 'css-loader', // translates CSS into CommonJS
        }, {
            loader: 'less-loader', // compiles Less to CSS
        }],
    }],
}
Munford answered 1/9, 2019 at 21:46 Comment(3)
Assuming you are using CRA v2 you need to eject first then modify the webpack.config.js fileWinkelman
Alternatively you can try forking CRA auth0.com/blog/how-to-configure-create-react-appStelu
Ok, I ran npm run eject but it didn't fix the issue. I think I was missing a module attribute in webpack.config.js, so I added it. Still not working though ... my webpack.config.js file looks like this now: module.exports = { module: { rules: [ .... Munford
M
20

to use less files in a react project created with create-react-app follow these steps:

  1. npm run eject
  2. npm i less less-loader
  3. open webpack.config.js file located at config folder created after eject script:

look at the return value of exported function(that's the main config)

find where last style-loader added which is sass-loader

       {
          test: sassModuleRegex,
          use: getStyleLoaders(
            {
              importLoaders: 3,
              sourceMap: isEnvProduction && shouldUseSourceMap,
              modules: {
                getLocalIdent: getCSSModuleLocalIdent,
              },
            },
            'sass-loader'
          ),
        },

and add less-loader under sass-loader like this:

       {
          test: sassModuleRegex,
          use: getStyleLoaders(
            {
              importLoaders: 3,
              sourceMap: isEnvProduction && shouldUseSourceMap,
              modules: {
                getLocalIdent: getCSSModuleLocalIdent,
              },
            },
            'sass-loader'
          ),
        },
        {
          test: /\.less$/,
          use: getStyleLoaders(
            {
              modules: true,
              importLoaders: 3,
              sourceMap: isEnvProduction && shouldUseSourceMap,
            },
            'less-loader'
          ),
          // Don't consider CSS imports dead code even if the
          // containing package claims to have no side effects.
          // Remove this when webpack adds a warning or an error for this.
          // See https://github.com/webpack/webpack/issues/6571
          sideEffects: true,
        },

importLoaders option inside less-loader should be 3.

two loaders from getStyleLoaders + our less-loader.

The option importLoaders allows you to configure how many loaders before css-loader should be applied to @imported resources.

why module option is true?

// index.less file

.header {
  background-color: skyblue;
}

if you want to use stylesheet file like this:

import styles from './index.less';

<div className={styles.header}></div>

you should set modules: true

but if you want to use it like below:

import './index.less';

<div className="header"></div>

you should set modules: false

Milliken answered 15/10, 2020 at 11:38 Comment(8)
Welcome to StackOverflow. Please don't just post some tool or library as an answer. At least demonstrate how it solves the problem in the answer itself. Link-only answers can become invalid if the linked page changes and answers that are little more than a link may be deleted.Footcloth
This is an excellent answer and clearly saved me days of searching. Thank you very much for the detail and the explanations. Super useful!Michelsen
Anything that requires to eject is an instant downvote. This is obviously an issue encountered 1) by a beginner, 2) in the early stage of the project. Two very good reasons NOT to eject.Esperance
why you do need to eject the app?Entophyte
to add custom loaders to webpack @EntophyteMilliken
you can reach any customisations with the customize-cra, don't ya?Entophyte
Sorry for the late reply Looks like customize-cra is not maintaining. Last publish of customize-cra is for 3 years ago @Andy.Milliken
interesting, I went with customize-cra + react-app-rewired and then just used the addLessLoader in my config-overrides.js config fileEntophyte
M
13

If you're using CRA, I would suggest going without ejecting.

First install less, less-watch-compiler and concurrently:

npm install less less-watch-compiler concurrently --save-dev

Then in your root directory create less-watcher.config.json and set the configuration:

{
    "watchFolder": "src/",
    "outputFolder": "src/",
    "runOnce": false,
    "sourceMap": true,
    "enableJs": true
}

Rename App.css to App.less

Replace start script in package.json with the following:

"scripts": {
    "start": "concurrently --kill-others \"less-watch-compiler --config less-watcher.config.json\" \"react-scripts start\"",
    "build": "react-scripts build",
    ....
}

and run the application. Enjoy :)

Maxama answered 17/3, 2021 at 16:27 Comment(2)
This didn't work for me, I ended with the following problem #76366662Charmeuse
In late 2023 this does not work unless "sourceMap": true, is added to less-watcher.config.json. I've edited the answer above, it's a great answer!Thermoelectrometer
A
10

After upgrading my react to v 18 you can do it with react-app-rewired library without ejecting your whole config of react, it's more cleaner.

install react-app-rewired

npm i react-app-rewired

install less and less loader

npm install less less-loader --save-dev

change your scripts in package.json to

 "start": "react-app-rewired start",
  "build": "react-app-rewired build",
  "test": "react-app-rewired test",

after that you need a file named config-overrides.js in your main application folder to configure your application you need to add this config

module.exports = function override(config, env) {
  config.module.rules[1].oneOf.splice(2, 0, {
    test: /\.less$/i,
    exclude: /\.module\.(less)$/,
    use: [
      { loader: "style-loader" },
      { loader: "css-loader" },
      {
        loader: "less-loader",
        options: {
          lessOptions: {
            javascriptEnabled: true,
          },
        },
      },
    ],
  })

  return config
}

and that's it.

Adulate answered 26/5, 2022 at 11:34 Comment(0)
W
5

CRA (Create React App) by default supports only SASS and CSS if you want to use LESS you need to do npm run eject first and then modify webpack configs.

However there is a way to do that w/o ejecting tho I have to say I personally prefer ejecting. You can find instructions here

Winkelman answered 1/9, 2019 at 23:3 Comment(1)
Can you link a source that lists css and scss as only two supported options?Cesaria
T
2

Use:

npm i -D react-scripts-less

Then:

"scripts": {
    "start": "react-scripts-less start",
    "build": "react-scripts-less build",
    "test": "react-scripts-less test",
}
Trot answered 21/10, 2022 at 5:36 Comment(1)
Thanks a lot @Ruslan, this indeed solved the less problem for me as well! it should be marked as accepted answer for future reference. I despise these lazy SO users who don't mark the answer as accepted due to laziness.Charmeuse
G
0

Try:

{test:/\.less$/, use:['style-loader','css-loader','less-loader']}
Gallous answered 19/5, 2020 at 18:1 Comment(0)
L
0

After ejecting and configuring the webpack.config.js, you also need to add the less file module declaration in react-app-env.d.ts.

declare module "*.less" {
  const content: { [className: string]: string };
  export default content;
}

Or you will get some error like this.

Cannot find module ‘xxx.less‘ or its corresponding type declarations. TS2307
Lapp answered 25/12, 2023 at 3:32 Comment(0)
T
-2

Is it relevant to use this method in large projects?

npm run eject
npm i less less-loader

Open webpack.config.js located at config folder created after eject script. Look at the return value of exported function (that's the main config). Find where last style-loader added which is sass-loader.

{
  test: sassModuleRegex,
  use: getStyleLoaders(
    {
      importLoaders: 3,
      sourceMap: isEnvProduction && shouldUseSourceMap,
      modules: {
        getLocalIdent: getCSSModuleLocalIdent,
      },
    },
    'sass-loader'
  ),
},
{
  test: /\.less$/,
  use: getStyleLoaders(
    {
      modules: true,
      importLoaders: 3,
      sourceMap: isEnvProduction && shouldUseSourceMap,
    },
    'less-loader'
  ),
  // Don't consider CSS imports dead code even if the containing package claims to have no side effects.
  // Remove this when webpack adds a warning or an error for this.
  // See https://github.com/webpack/webpack/issues/6571
  sideEffects: true,
},
Thissa answered 31/12, 2021 at 22:20 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.