Next.js: Next.js 9 with antd + less, yarn build get an error

Created on 22 Jul 2019  路  29Comments  路  Source: vercel/next.js

QUESTION

yarn dev is work, but yarn build get an error.

> Build error occurred
{ /<PROJECT-PATH>/node_modules/antd/lib/style/index.less:1
(function (exports, require, module, __filename, __dirname) { @import './themes/index';
                                                              ^

SyntaxError: Invalid or unexpected token
    at new Script (vm.js:79:7)
    at createScript (vm.js:251:10)
    at Object.runInThisContext (vm.js:303:10)
    at Module._compile (internal/modules/cjs/loader.js:656:28)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
    at Module.load (internal/modules/cjs/loader.js:598:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
    at Function.Module._load (internal/modules/cjs/loader.js:529:3)
    at Module.require (internal/modules/cjs/loader.js:636:17)
    at require (internal/modules/cjs/helpers.js:20:18) type: 'SyntaxError', '$error': '$error' }
error Command failed with exit code 1.

Most helpful comment

RESOLVE

i found that with-ant-design-less can handles this error, but project/pages's less style don't work. so I wrote a next-antd.config.js to solve this problem.

next.config.js

const fs = require('fs');
const path = require('path');

const lessToJS = require('less-vars-to-js');
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin');

const withImage = require('./configs/next-image.config');
const withDotenv = require('./configs/next-dotenv.config');
const withAntd = require('./configs/next-antd.config');

const antdVariables = lessToJS(fs.readFileSync(path.resolve(__dirname, './styles/variables.less'), 'utf8'));

// fix: prevents error when .less files are required by node
if (typeof require !== 'undefined') {
  require.extensions['.less'] = file => {};
}

module.exports = withDotenv(
  withImage(
    withAntd({
      cssModules: true,
      cssLoaderOptions: {
        sourceMap: false,
        importLoaders: 1,
      },
      lessLoaderOptions: {
        javascriptEnabled: true,
        modifyVars: antdVariables,
      },
      webpack: config => {
        config.plugins.push(
          new FilterWarningsPlugin({
            // ignore ANTD chunk styles [mini-css-extract-plugin] warning
            exclude: /mini-css-extract-plugin[^]*Conflicting order between:/,
          }),
        );

        return config;
      },
    }),
  ),
);

next-antd.config.js

const cssLoaderConfig = require('@zeit/next-css/css-loader-config');

module.exports = (nextConfig = {}) => ({
  ...nextConfig,
  ...{
    webpack(config, options) {
      if (!options.defaultLoaders) {
        throw new Error(
          'This plugin is not compatible with Next.js versions below 5.0.0 https://err.sh/next-plugins/upgrade',
        );
      }

      const { dev, isServer } = options;
      const { cssModules, cssLoaderOptions, postcssLoaderOptions, lessLoaderOptions = {} } = nextConfig;

      // for all less in clint
      const baseLessConfig = {
        extensions: ['less'],
        cssModules,
        cssLoaderOptions,
        postcssLoaderOptions,
        dev,
        isServer,
        loaders: [
          {
            loader: 'less-loader',
            options: lessLoaderOptions,
          },
        ],
      };

      config.module.rules.push({
        test: /\.less$/,
        exclude: /node_modules/,
        use: cssLoaderConfig(config, baseLessConfig),
      });

      // for antd less in client
      const antdLessConfig = {
        ...baseLessConfig,
        ...{ cssModules: false, cssLoaderOptions: {}, postcssLoaderOptions: {} },
      };

      config.module.rules.push({
        test: /\.less$/,
        include: /node_modules/,
        use: cssLoaderConfig(config, antdLessConfig),
      });

      // for antd less in server (yarn build)
      if (isServer) {
        const antdStyles = /antd\/.*?\/style.*?/;
        const rawExternals = [...config.externals];

        config.externals = [
          (context, request, callback) => {
            if (request.match(antdStyles)) {
              return callback();
            }

            if (typeof rawExternals[0] === 'function') {
              rawExternals[0](context, request, callback);
            } else {
              callback();
            }
          },
          ...(typeof rawExternals[0] === 'function' ? [] : rawExternals),
        ];

        config.module.rules.unshift({
          test: antdStyles,
          use: 'null-loader',
        });
      }

      if (typeof nextConfig.webpack === 'function') {
        return nextConfig.webpack(config, options);
      }

      return config;
    },
  },
});

.babelrc.js

module.exports = {
  presets: [['next/babel']],
  plugins: [
    [
      'import',
      {
        libraryName: 'antd',
        libraryDirectory: 'lib',
        style: true,
      },
    ],
  ],
  ignore: ['node_modules'],
};

package.json

 "devDependencies": {
    "@zeit/next-css": "^1.0.2-canary.2",
    "@zeit/next-less": "^1.0.1",
    "less": "^3.9.0",
    "less-vars-to-js": "^1.3.0",
    "null-loader": "^3.0.0",
    "webpack-filter-warnings-plugin": "^1.2.1"
  }

All 29 comments

RESOLVE

i found that with-ant-design-less can handles this error, but project/pages's less style don't work. so I wrote a next-antd.config.js to solve this problem.

next.config.js

const fs = require('fs');
const path = require('path');

const lessToJS = require('less-vars-to-js');
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin');

const withImage = require('./configs/next-image.config');
const withDotenv = require('./configs/next-dotenv.config');
const withAntd = require('./configs/next-antd.config');

const antdVariables = lessToJS(fs.readFileSync(path.resolve(__dirname, './styles/variables.less'), 'utf8'));

// fix: prevents error when .less files are required by node
if (typeof require !== 'undefined') {
  require.extensions['.less'] = file => {};
}

module.exports = withDotenv(
  withImage(
    withAntd({
      cssModules: true,
      cssLoaderOptions: {
        sourceMap: false,
        importLoaders: 1,
      },
      lessLoaderOptions: {
        javascriptEnabled: true,
        modifyVars: antdVariables,
      },
      webpack: config => {
        config.plugins.push(
          new FilterWarningsPlugin({
            // ignore ANTD chunk styles [mini-css-extract-plugin] warning
            exclude: /mini-css-extract-plugin[^]*Conflicting order between:/,
          }),
        );

        return config;
      },
    }),
  ),
);

next-antd.config.js

const cssLoaderConfig = require('@zeit/next-css/css-loader-config');

module.exports = (nextConfig = {}) => ({
  ...nextConfig,
  ...{
    webpack(config, options) {
      if (!options.defaultLoaders) {
        throw new Error(
          'This plugin is not compatible with Next.js versions below 5.0.0 https://err.sh/next-plugins/upgrade',
        );
      }

      const { dev, isServer } = options;
      const { cssModules, cssLoaderOptions, postcssLoaderOptions, lessLoaderOptions = {} } = nextConfig;

      // for all less in clint
      const baseLessConfig = {
        extensions: ['less'],
        cssModules,
        cssLoaderOptions,
        postcssLoaderOptions,
        dev,
        isServer,
        loaders: [
          {
            loader: 'less-loader',
            options: lessLoaderOptions,
          },
        ],
      };

      config.module.rules.push({
        test: /\.less$/,
        exclude: /node_modules/,
        use: cssLoaderConfig(config, baseLessConfig),
      });

      // for antd less in client
      const antdLessConfig = {
        ...baseLessConfig,
        ...{ cssModules: false, cssLoaderOptions: {}, postcssLoaderOptions: {} },
      };

      config.module.rules.push({
        test: /\.less$/,
        include: /node_modules/,
        use: cssLoaderConfig(config, antdLessConfig),
      });

      // for antd less in server (yarn build)
      if (isServer) {
        const antdStyles = /antd\/.*?\/style.*?/;
        const rawExternals = [...config.externals];

        config.externals = [
          (context, request, callback) => {
            if (request.match(antdStyles)) {
              return callback();
            }

            if (typeof rawExternals[0] === 'function') {
              rawExternals[0](context, request, callback);
            } else {
              callback();
            }
          },
          ...(typeof rawExternals[0] === 'function' ? [] : rawExternals),
        ];

        config.module.rules.unshift({
          test: antdStyles,
          use: 'null-loader',
        });
      }

      if (typeof nextConfig.webpack === 'function') {
        return nextConfig.webpack(config, options);
      }

      return config;
    },
  },
});

.babelrc.js

module.exports = {
  presets: [['next/babel']],
  plugins: [
    [
      'import',
      {
        libraryName: 'antd',
        libraryDirectory: 'lib',
        style: true,
      },
    ],
  ],
  ignore: ['node_modules'],
};

package.json

 "devDependencies": {
    "@zeit/next-css": "^1.0.2-canary.2",
    "@zeit/next-less": "^1.0.1",
    "less": "^3.9.0",
    "less-vars-to-js": "^1.3.0",
    "null-loader": "^3.0.0",
    "webpack-filter-warnings-plugin": "^1.2.1"
  }

@SolidZORO good job, thanks

@SolidZORO thanks ^_^

const fs = require('fs');
const path = require('path');

const lessToJS = require('less-vars-to-js');
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin');

const withImage = require('./configs/next-image.config');
const withDotenv = require('./configs/next-dotenv.config');
const withAntd = require('./configs/next-antd.config');

const antdVariables = lessToJS(fs.readFileSync(path.resolve(__dirname, './styles/variables.less'), 'utf8'));

// fix: prevents error when .less files are required by node
if (typeof require !== 'undefined') {
require.extensions['.less'] = file => {};
}

module.exports = withDotenv(
withImage(
withAntd({
cssModules: true,
cssLoaderOptions: {
sourceMap: false,
importLoaders: 1,
},
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars: antdVariables,
},
webpack: config => {
config.plugins.push(
new FilterWarningsPlugin({
// ignore ANTD chunk styles [mini-css-extract-plugin] warning
exclude: /mini-css-extract-plugin[^]*Conflicting order between:/,
}),
);

    return config;
  },
}),

),
);

Could you please explain more what changes you applied to the next config?

Thank you. I saw the code but I need to know exactly what causes this problem?

I added the next-ant.config to my project But what should I do exactly with my next config?

my next.config.js

const withPlugins = require('next-compose-plugins');
const withCss = require('@zeit/next-css');
const withSass = require('@zeit/next-sass');
const BrotliPlugin = require('brotli-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const withImages = require('next-images');

// add bundle analyzer config
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});

// fix: prevents error when .css files are required by node
// https://github.com/zeit/next.js/blob/master/examples/with-ant-design/next.config.js
if (typeof require !== 'undefined') {
  require.extensions[".css"] = file => {}; // eslint-disable-line
}

// main next config, including webpack
const nextConfig = {
  distDir: '_next', // used to define the name of build dir, we need it to be _next, for serving gzip files

  // next js caches pages in dev mode, this config is used to increase cache time to have better dev experience
  // https://github.com/zeit/next.js/issues/1939
  onDemandEntries: {
    // Make sure entries are not getting disposed.
    maxInactiveAge: 1000 * 60 * 60,
    // number of pages that should be kept simultaneously without being disposed
    pagesBufferLength: 5,
  },

  // webpack config
  webpack: (config, { dev }) => {
    // Add brotli plugin
    !dev &&
      config.plugins.push(
        new BrotliPlugin({
          asset: '[path].br[query]',
          test: /\.js$|\.css$|\.html$/,
          threshold: 10240,
          minRatio: 0.7,
        }),
      );

    // Add gzip compression plugin
    !dev &&
      config.plugins.push(
        new CompressionPlugin({
          filename: '[path].gz[query]',
          algorithm: 'gzip',
          test: /\.js$|\.css$|\.html$/,
          threshold: 10240,
          minRatio: 0.7,
        }),
      );
    return config;
  },
};

module.exports = withPlugins(
  [
    [withImages],
    [withCss],
    [
      withSass,
      {
        cssModules: true,
        cssLoaderOptions: {
          localIdentName: '[path]___[local]___[hash:base64:5]',
        },
      },
    ],
    [withBundleAnalyzer],
  ],
  nextConfig,
);

and my babel.config.js:

module.exports = {
  presets: ['next/babel'],
  plugins: [
    '@babel/plugin-proposal-optional-chaining',
    [
      'import',
      {
        libraryName: 'antd',
        style: 'css',
      },
    ],
    [
      'react-intl',
      {
        messagesDir: './locale',
        extractSourceLocation: true,
      },
    ],
  ],
};

because server don't know *.less, just browser know it. so we need to deal with this.

thanks

it's useful, tks!

you're a life saver

@SolidZORO Hi, I have installed and applied webpack-filter-warnings-plugin but I still get the warnings.

Here is my next.config.js file.

const withCss = require('@zeit/next-css')
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin')

module.exports = withCss({
  webpack: (config, { isServer }) => {
    if (isServer) {
      const antStyles = /antd\/.*?\/style\/css.*?/
      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.plugins.push(
        new FilterWarningsPlugin({
          // ignore ANTD chunk styles [mini-css-extract-plugin] warning
          exclude: /mini-css-extract-plugin[^]*Conflicting order between:/,
        }),
      );

      config.module.rules.unshift({
        test: antStyles,
        use: 'null-loader',
      })
    }

    // Fixes npm packages that depend on `fs` module
    config.node = {
      fs: 'empty'
    }

    return config
  },
  distDir: "../../dist/client"
})

@maotora

you can try exclude: /mini-css-extract-plugin[^]*Conflicting order between:/, change to exclude: /Conflicting order/,.

Hi @SolidZORO ,
Thanks for fast reply however I still get the warnings.

A mountain full of them
mini-css-extract-plugin warnings

@maotora I haven't written next.js code for a while, you may need to debug it yourself. 馃槶

you can see here. https://github.com/SolidZORO/leaa/blob/legacy-www/packages/leaa-www/tools/next/next-webpack.js

I think I have 馃榿 ...

I had to move the plugin code from the isServer block.

const withCss = require('@zeit/next-css')
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin')

module.exports = withCss({
  webpack: (config, { isServer }) => {
    config.plugins.push(
      new FilterWarningsPlugin({
        // ignore ANTD chunk styles [mini-css-extract-plugin] warning
        exclude: /Conflicting order/,
      })
    );

    if (isServer) {
      const antStyles = /antd\/.*?\/style\/css.*?/
      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',
      })
    }

    // Fixes npm packages that depend on `fs` module
    config.node = {
      fs: 'empty'
    }

    return config
  },
  distDir: "../../dist/client"
})

Just like that warnings are gone!

@maotora In fact, I am very dissatisfied with the plugin ecosystem of next.js, it is like a black box, and there are many bugs. If it is as easy to use as Gatsby's plugin, there will be no problems. So I wrote this part of webpack independently and treat it like normal webpack. (Of course, this is also troublesome for people without webpack configuration experience. Also, you need to pay attention to the css-loader version and pay attention to package.json)

source: https://github.com/SolidZORO/leaa/blob/legacy-www/packages/leaa-www/tools/next/next-webpack.js

Here are the files that works fine for me :

"next": "9.2.2"
"less": "^3.11.1"
"antd": "^4.0.2"

next.config.js

const withLess = require('@zeit/next-less')

module.exports = () => {
    return withLess({
        lessLoaderOptions: {
            modifyVars: {
                'primary-color': '#066',
            },
            javascriptEnabled: true,
        },
        webpack: (config, { isServer }) => {
            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
        },
    })
}

.babelrc

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

@bahmannejati Did you try building the production build and start? It works when running yarn dev but not when yarn build and yarn start.

update: Found out it is due to my postcss config. So this is no longer an issue.

Thank you. I saw the code but I need to know exactly what causes this problem?

I have a similar problem with @ant-design/layout package. I've slowed the problem by using dynamic imports. Example: https://github.com/8iq/nodejs-hackathon-boilerplate-starter-kit/tree/f3779ff2ffd7b70ed98ad0e998923971372b7907/apps/_example04antpro

Or master branch: https://github.com/8iq/nodejs-hackathon-boilerplate-starter-kit/tree/master/apps/_example04antpro

hello, why I still get the error like this? @SolidZORO ,I make my config like yours, but it did't work when I run build

> Build error occurred
/{PATH}/node_modules/antd/dist/antd.less:1
@import "../lib/style/index.less";
^

SyntaxError: Invalid or unexpected token
    at wrapSafe (internal/modules/cjs/loader.js:1072:16)
    at Module._compile (internal/modules/cjs/loader.js:1122:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
    at Module.load (internal/modules/cjs/loader.js:1002:32)
    at Function.Module._load (internal/modules/cjs/loader.js:901:14)
    at Module.require (internal/modules/cjs/loader.js:1044:19)
    at require (internal/modules/cjs/helpers.js:77:18)
    at Object.<anonymous> (/Users/kevin/lian-med/lian-med-cms/node_modules/lian-med-design/lib/components/index.js:450:1)
    at Module._compile (internal/modules/cjs/loader.js:1158:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10) {
  type: 'SyntaxError'
}
error Command failed with exit code 1.

OK, I solved this, thank you guys.

Can I use antd variables and write styles on scss? I use default scss configs next9

Can I use antd variables and write styles on scss? I use default scss configs next9

I prefer to use scss. Did you solve this problem?

I prefer to use scss. Did you solve this problem?

No, I didn't...

I also prefer scss with scss-module. But we can鈥檛 use antd without custom next.config, and this in turn does not allow the use of native scss-module from the next9

@bahmannejati @StKostyantin
I replace all scss files to *.module.less. But I still get warning

./src/pages/_app.tsx
Module not found: Can't resolve 'null-loader' 

@qiwang97

Seems you have not null-loader package, install it first using npm:

npm install null-loader --save-dev

Or using yarn:

yarn add --dev null-loader

Consider along with changing .scss to .less, you should change the syntaxes too, less it different by sass

I replace all scss files to *.module.less. But I still get warning

As far as I know, less has not been added to the next9 box yet, and therefore it will not be possible to work with less without configuring the next.config

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jesselee34 picture jesselee34  路  3Comments

wagerfield picture wagerfield  路  3Comments

irrigator picture irrigator  路  3Comments

flybayer picture flybayer  路  3Comments

havefive picture havefive  路  3Comments