Search code examples
sasslessnext.jsantdcss-modules

How to configure Next.js with Antd / Less and Sass / CSS modules


I want to use Next.js with Sass and CSS modules but also want to use Ant Design and wanted to use the Less styles for smaller building size.

I'm able to enable either CSS modules or Less loader but not both at the same time. The examples from Next.js were not helping me complete that problem.


Solution

  • Edit: This answer is definitely outdated for current versions of next.js, check the other answers below.

    After multiple hours of research I found now finally the right solution and wanted to share it:

    .babelrc (no magic here)

    {
      "presets": ["next/babel"],
      "plugins": [
        [
          "import",
          {
            "libraryName": "antd",
            "style": true
          }
        ]
      ]
    }
    

    next.config.js:

    /* eslint-disable */
    const withLess = require('@zeit/next-less');
    const withSass = require('@zeit/next-sass');
    const lessToJS = require('less-vars-to-js');
    const fs = require('fs');
    const path = require('path');
    
    // Where your antd-custom.less file lives
    const themeVariables = lessToJS(
      fs.readFileSync(path.resolve(__dirname, './assets/antd-custom.less'), 'utf8')
    );
    
    module.exports = withSass({
      cssModules: true,
      ...withLess({
        lessLoaderOptions: {
          javascriptEnabled: true,
          modifyVars: themeVariables, // make your antd custom effective
          importLoaders: 0
        },
        cssLoaderOptions: {
          importLoaders: 3,
          localIdentName: '[local]___[hash:base64:5]'
        },
        webpack: (config, { isServer }) => {
          //Make Ant styles work with less
          if (isServer) {
            const antStyles = /antd\/.*?\/style.*?/;
            const origExternals = [...config.externals];
            config.externals = [
              (context, request, callback) => {
                if (request.match(antStyles)) return callback();
                if (typeof origExternals[0] === 'function') {
                  origExternals[0](context, request, callback);
                } else {
                  callback();
                }
              },
              ...(typeof origExternals[0] === 'function' ? [] : origExternals)
            ];
    
            config.module.rules.unshift({
              test: antStyles,
              use: 'null-loader'
            });
          }
          return config;
        }
      })
    });
    

    The final hint how to write the withSass withLess use and to put the cssModules: true in the outer object came from this comment here.

    While I was already trying different combinations derived from the examples before: next+ant+less next+sass

    For completion here the dependencies in my package.json:

    ...
    "dependencies": {
        "@zeit/next-less": "^1.0.1",
        "@zeit/next-sass": "^1.0.1",
        "antd": "^4.1.3",
        "babel-plugin-import": "^1.13.0",
        "less": "^3.11.1",
        "less-vars-to-js": "^1.3.0",
        "next": "^9.3.4",
        "node-sass": "^4.13.1",
        "null-loader": "^3.0.0",
        "react": "^16.13.1",
        "react-dom": "^16.13.1",
        "sass": "^1.26.3"
      }
    ...
    

    I hope this helps other people to find this solution faster. :)