Antd and webpack5 configuration problem in nextjs - reactjs

I have problem with configuring antd in nextjs version 12.0.8. I know i can fix this with downgrading webpack to version 4 but its necessary for me to use webpack 5.
antd version: 4.18.3
Webpack version: 5.65.0
nextjs version: 12.0.8
Here is my next config:
module.exports = withImages({...withFonts({
...withCss({
...withLess({
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars: themeVariables, // make your antd custom effective
importLoaders: 0
},
cssLoaderOptions: {
importLoaders: 3,
localIdentName: '[local]___[hash:base64:5]'
},
// webpack5: false,
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'
});
}
// config.module.rules.push({
// test: /\.(png|jpe?g|gif)$/i,
// loader: 'file-loader'
// })
return config;
}
})
})
})
});
But i got this error:
TypeError: Cannot set property 'styles' of undefined
at module.exports (/home/sajjad/Project/pishrun-frontend/node_modules/#zeit/next-css/css-loader-config.js:25:56)
at Object.webpack (/home/sajjad/Project/pishrun-frontend/node_modules/#zeit/next-css/index.js:15:36)
at Object.webpack (/home/sajjad/Project/pishrun-frontend/node_modules/next-fonts/index.js:42:27)
at Object.webpack (/home/sajjad/Project/pishrun-frontend/node_modules/next-images/index.js:63:27)
at Object.getBaseWebpackConfig [as default] (/home/sajjad/Project/pishrun-frontend/node_modules/next/dist/build/webpack-config.js:1390:32)
at async Promise.all (index 0)
at async Span.traceAsyncFn (/home/sajjad/Project/pishrun-frontend/node_modules/next/dist/trace/trace.js:75:20)
at async Span.traceAsyncFn (/home/sajjad/Project/pishrun-frontend/node_modules/next/dist/trace/trace.js:75:20)
at async HotReloader.start (/home/sajjad/Project/pishrun-frontend/node_modules/next/dist/server/dev/hot-reloader.js:329:25)
at async DevServer.prepare (/home/sajjad/Project/pishrun-frontend/node_modules/next/dist/server/dev/next-dev-server.js:295:9)
Thanks for your help.

Related

SyntaxError: pragma and pragmaFrag cannot be set when runtime is automatic

I'm migrating a project from Next 9 to Next 11 which uses webpack5 by default. After fixing the loader issue as shown in the next.config.js file, I get this error:
SyntaxError: pragma and pragmaFrag cannot be set when runtime is automatic
I've tried debugging with these solutions, and I still trigger the same error.
My code:
next.config.js
const withImages = require("next-images");
const { PHASE_DEVELOPMENT_SERVER } = require("next/constants");
const withYaml = require("next-plugin-yaml");
const babel = require('babel-plugin-import-glob-array');
module.exports = (phase) =>
withYaml(
withImages(
({
target: "serverless",
env: {
isDev: phase === PHASE_DEVELOPMENT_SERVER,
},
webpack5: true,
webpack: (config, options) => {
config.module.rules.push({
test: /\.mdx/,
use: [
options.defaultLoaders.babel,
{
loader: '#mdx-js/loader',
options: babel.options,
},
],
});
config.module.rules.unshift({
test: /\.svg$/,
use: ["#svgr/webpack"]
});
console.log(options.webpack.version); // 5.18.0
// eslint-disable-next-line no-param-reassign
config.experiments = {};
return config;
},
})
)
);
babel.config.json
{
"presets": ["next/babel", "#emotion/babel-preset-css-prop"],
"plugins": ["import-glob-array", "emotion"]
}
.tsx files
/** #jsx jsx */
import { css, jsx } from "#emotion/core";

Web Worker - Jest - Cannot use 'import.meta' outside a module

I'm working on a nextjs 10.1.3 built-in web application. We implemented a web worker to boost up the performance in one of the pages and the plan is to continue adding more workers; also, all the code is properly unit tested, and using the worker-loader in previous webpack versions (4th and below) we were able to test it.
With the new webpack 5 version, the worker-loader plugin is not needed anymore; instead, the way to load a web worker using the new version is new Worker(new URL("#/workers/task.worker.js", import.meta.url));.
Doing it this way, my code is working as expected with npm build && npm start; however, when I try to add the respective unit tests I got the following error: Cannot use 'import.meta' outside a module and everything happens because of the import.meta.url used to add the location of the worker in the browser.
I read many posts on the web regarding babel but I want to get away from that option. Is there any other option to mock the import.meta.url with jest?
Any help will be very welcome. This is the current configuration.
package.json
{
...
"#babel/core": "^7.8.6",
"next": "^10.1.3",
"react": "^16.13.0",
"webpack": "^5.37.1"
"devDependencies": {
...
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"jest": "^24.9.0",
"jest-cli": "^25.1.0",
...
}
...
}
next.config.js
const {
...
} = process.env;
const basePath = "";
const COMMIT_SHA = [];
const { parsed: localEnv } = require("dotenv").config();
const webpack = require("webpack");
const withBundleAnalyzer = require("#next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true",
});
const nextConfig = {
env: {
NEXT_PUBLIC_COMMIT_SHA: COMMIT_SHA,
},
images: {
domains: [
"...",
],
},
future: {
webpack5: true,
},
productionBrowserSourceMaps: true,
trailingSlash: true,
reactStrictMode: true,
webpack: (config, options) => {
if (localEnv) {
config.plugins.push(new webpack.EnvironmentPlugin(localEnv));
} else {
config.plugins.push(new webpack.EnvironmentPlugin(process.env));
}
config.module.rules.push({
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 100000,
name: "[name].[ext]",
},
},
});
config.output = {
...config.output,
chunkFilename: options.isServer
? `${options.dev ? "[name]" : "[name].[fullhash]"}.js`
: `static/chunks/${options.dev ? "[name]" : "[name].[fullhash]"}.js`,
publicPath: `/_next/`,
globalObject: `(typeof self !== 'undefined' ? self : this)`,
};
config.plugins.push(new webpack.IgnorePlugin(/pages.*\/__tests__.*/));
config.plugins.push(
new options.webpack.DefinePlugin({
"process.env.NEXT_IS_SERVER": JSON.stringify(
options.isServer.toString()
),
})
);
return config;
},
};
module.exports = withBundleAnalyzer(nextConfig);
The useEffect worker
useEffect(() => {
if (pageData.data?.length) {
workerRef.current = new Worker(new URL("#/workers/task.worker.js", import.meta.url));
workerRef.current.addEventListener("message", result => {
if (result.error) {
setWorkerError();
} else {
updateData(result.data);
}
});
const ids = pageData.data.map(store => store.id);
workerRef.current.postMessage(ids);
} else {
setNoDataFound();
}
return () => {
workerRef.current && workerRef.current.terminate();
};
}, []);
jest.config.js
module.exports = {
moduleDirectories: ["node_modules", "src", "static", "store"],
modulePathIgnorePatterns: [
"<rootDir>/node_modules/prismjs/plugins/line-numbers",
],
testPathIgnorePatterns: [
"<rootDir>/src/components/component-library",
"<rootDir>/.next",
"jest.config.js",
"next.config.js",
],
collectCoverageFrom: [
"**/src/**",
"**/store/**",
"**/pages/**",
"!**/__tests__/**",
"!**/node_modules/**",
"!**/component-library/**",
],
testEnvironment: "node",
collectCoverage: true,
verbose: false,
automock: false,
setupFiles: ["./setupTests.js"],
moduleNameMapper: {
"#/components/(.*)$": "<rootDir>/src/components/$1",
"#/functions/(.*)$": "<rootDir>/src/components/functions/$1",
"#/services/(.*)$": "<rootDir>/src/components/services/$1",
"#/workers/(.*)$": "<rootDir>/src/components/workers/$1",
"#/scripts(.*)$": "<rootDir>/src/scripts/$1",
"#/src(.*)$": "<rootDir>/src/$1",
"#/__mocks__(.*)$": "<rootDir>/__mocks__/$1",
"#/pages(.*)$": "<rootDir>/pages/$1",
"#/store(.*)$": "<rootDir>/store/$1",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js",
},
coveragePathIgnorePatterns: ["/node_modules/"],
coverageThreshold: {
global: {
branches: 67,
functions: 66,
lines: 73,
statements: 72,
},
},
runner: "groups",
extraGlobals: [],
testTimeout: 10000,
};
In my setup (typescript + ts-jest) I prepended the following node option to make it work:
NODE_OPTIONS=--experimental-vm-modules
Reference can be found here: https://jestjs.io/docs/ecmascript-modules

Configure multiple next plugins: withMDX, withBundleAnalyzer

I started a nextjs site with a tailwind blog starter that already comes with withBundleAnalyzer in next.config.js.
I am now trying to get .mdx files to work from the pages directly. Documentation says I need withMDX in my nextjs.config file. How do I get the two to play together? Should I only keep one or the other? I have installed next-compose-plugins but not sure how to set it all up.
Update
This is my next config file; it's still failing. Error:
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
TypeError: undefined is not a function
at _withPlugins (/home/xxx/xxx/nodeapps/my-web/node_modules/next-compose-plugins/lib/index.js:17:22)
at Object.<anonymous> (/home/xxx/xxx/nodeapps/my-web/next.config.js:11:18)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at loadConfig (/home/xxx/xxx/nodeapps/my-web/node_modules/next/dist/next-server/server/config.js:8:94)
at async NextServer.loadConfig (/home/xxx/xxx/nodeapps/my-web/node_modules/next/dist/server/next.js:1:2962)
const withPlugins = require('next-compose-plugins')
const withMDX = require('#next/mdx')({
extension: /\.mdx$/,
})
const withBundleAnalyzer = require('#next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
module.exports = withPlugins(
withMDX(
withBundleAnalyzer({
pageExtensions: ['js', 'jsx', 'md', 'mdx'],
future: {
webpack5: true,
},
webpack: (config, { dev, isServer }) => {
config.module.rules.push({
test: /\.(png|jpe?g|gif|mp4)$/i,
use: [
{
loader: 'file-loader',
options: {
publicPath: '/_next',
name: 'static/media/[name].[hash].[ext]',
},
},
],
})
config.module.rules.push({
test: /\.svg$/,
use: ['#svgr/webpack'],
})
if (!dev && !isServer) {
// Replace React with Preact only in client production build
Object.assign(config.resolve.alias, {
react: 'preact/compat',
'react-dom/test-utils': 'preact/test-utils',
'react-dom': 'preact/compat',
})
}
return config
},
})
)
)
As you mentioned you can use next-compose-plugins like this
const withPlugins = require('next-compose-plugins');
const withMDX = require('#next/mdx');
const withBundleAnalyzer = require('#next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withPlugins([
// add a plugin with specific configuration
[withMDX, {
// MDX plugin specific options
}],
// add it like this if no plugin configuration is needed
[withBundleAnalyzer],
]);
EDIT:
Here is your complete config file:
const withPlugins = require("next-compose-plugins");
const withMDX = require("#next/mdx")({
extension: /\.mdx?$/,
});
const withBundleAnalyzer = require("#next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true",
});
module.exports = withPlugins([[withBundleAnalyzer], [withMDX]], {
pageExtensions: ["js", "jsx", "md", "mdx"],
future: {
webpack5: true,
},
webpack: (config, { dev, isServer }) => {
config.module.rules.push({
test: /\.(png|jpe?g|gif|mp4)$/i,
use: [
{
loader: "file-loader",
options: {
publicPath: "/_next",
name: "static/media/[name].[hash].[ext]",
},
},
],
});
config.module.rules.push({
test: /\.svg$/,
use: ["#svgr/webpack"],
});
if (!dev && !isServer) {
// Replace React with Preact only in client production build
Object.assign(config.resolve.alias, {
react: "preact/compat",
"react-dom/test-utils": "preact/test-utils",
"react-dom": "preact/compat",
});
}
return config;
},
});
You can setup the config without using next-compose-plugins as well.
const withMDX = require('#next/mdx')({
extension: /\.mdx$/,
})
const withBundleAnalyzer = require('#next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
module.exports = withMDX(withBundleAnalyzer({
// Your Next.js configs, including withMDX-specific options
}))

Webpack build failing on upgrading Nextjs to v10 from v9

I'm quite new to frontend technologies. I tried Next.js v9.x.x and anyhow configured next.config.js to support less as well as .css files as AntDesign needed it which I'm using in the project. Here is thenext.config.js file which perfectly worked with Next.js-v9.x.x:
const themeVariables = lessToJS(
fs.readFileSync(path.resolve(__dirname, './assets/theme.less'), 'utf8'),
);
const plugins = [
[withLess({
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars: themeVariables, // make your antd custom effective
},
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',
});
}
const builtInLoader = config.module.rules.find((rule) => {
if (rule.oneOf) {
return (
rule.oneOf.find((deepRule) => deepRule.test && deepRule.test.toString().includes('/a^/')) !== undefined
);
}
return false;
});
if (typeof builtInLoader !== 'undefined') {
config.module.rules.push({
oneOf: [
...builtInLoader.oneOf.filter((rule) => (rule.test && rule.test.toString().includes('/a^/')) !== true),
],
});
}
config.resolve.alias['#'] = path.resolve(__dirname);
// SVGs loading
config.module.rules.push({
test: /\.svg$/,
issuer: {
test: /\.(js|ts)x?$/,
},
use: ['#svgr/webpack'],
});
return config;
},
})],
];
module.exports = withPlugins(plugins, nextConfig);
I just found that a major version (10.x.x) released by Next.js. I upgraded the project and the build started failing with:
Failed to compile.
Error: No module factory available for dependency type: CssDependency
> Build error occurred
Error: > Build failed because of webpack errors
at build (/Users/ss/Projects/Test/Frontend/node_modules/next/dist/build/index.js:15:918)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
Tried finding solutions online and found here that a missing mini-css-extract-plugin configuration might raise this error. I was confused as the same was working earlier so thought that they removed this dependency in the latest release but couldn't find any issue raised for this in their Github repo.
On debugging the project, I also found that mini-css-extract-plugin was missing in package-lock.json > "next" > "requires" section in v10.x.x while it was there in v9.x.x
Now I'm confused about how to re-configure the next.config.js for my case as I couldn't find any solutions online.
Can anyone please check? Any help would be appreciated. Thanks in advance.
I had the same issue, I fixed it by splitting the plugin to look like this:
module.exports = withPlugins([[
withLess, {
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars: themeVariables, // make your antd custom effective
},
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',
});
}
const builtInLoader = config.module.rules.find((rule) => {
if (rule.oneOf) {
return (
rule.oneOf.find((deepRule) => deepRule.test && deepRule.test.toString().includes('/a^/')) !== undefined
);
}
return false;
});
if (typeof builtInLoader !== 'undefined') {
config.module.rules.push({
oneOf: [
...builtInLoader.oneOf.filter((rule) => (rule.test && rule.test.toString().includes('/a^/')) !== true),
],
});
}
config.resolve.alias['#'] = path.resolve(__dirname);
// SVGs loading
config.module.rules.push({
test: /\.svg$/,
issuer: {
test: /\.(js|ts)x?$/,
},
use: ['#svgr/webpack'],
});
return config;
},
}]], nextConfig);
If this doesn't help, you can use this package next-plugin-antd-less
Using it with next-compose-plugins you'll have to follow the same structure as the above.
module.exports = withPlugins([
[
withAntdLess,
{
lessVarsFilePath: "./assets/theme.less",
},
],
])

How to configure nextjs 9 and ant design less compatibility?

After upgrading react,react-dom and nextjs this error happens :
Build error occurred
/home/lenovo/.../node_modules/antd/lib/style/index.css:7
body {
^
SyntaxError: Unexpected token {
at Module._compile (internal/modules/cjs/loader.js:720:22)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:788:10)
at Module.load (internal/modules/cjs/loader.js:643:32) {
type: 'SyntaxError',
'$error': '$error'
}
events.js:180
throw er; // Unhandled 'error' event
^
Error: write EPIPE
...
at processTicksAndRejections (internal/process/task_queues.js:77:11)
Emitted 'error' event at:
at internal/child_process.js:810:39
at processTicksAndRejections (internal/process/task_queues.js:75:11) {
errno: 'EPIPE',
code: 'EPIPE',
syscall: 'write'
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
This is my next.config.js:
const nextConfig = {
distDir: '_next',
onDemandEntries: {
maxInactiveAge: 1000 * 60 * 60,
pagesBufferLength: 5,
},
webpack: (config, { dev }) => {
!dev &&
config.plugins.push(
new BrotliPlugin({
asset: '[path].br[query]',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.7,
}),
);
!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,
);
Do you know what is wrong with this?
Edit
It seems there is a compatibility problem with ant design and I found some sources but not get it though!
Based on this example in the Next.js repository
https://github.com/zeit/next.js/tree/canary/examples/with-ant-design
To resolve this problem, add these lines to your next.config.js:
const nextConfig = {
webpack: (config, { isServer }) => {
if (isServer) {
const antStyles = /antd\/.*?\/style\/css.*?/;
const origExternals = [...config.externals];
config.externals = [ // eslint-disable-line
(context, request, callback) => { // eslint-disable-line
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;
},
};
An example of what the next.config.js file would look like:
const withPlugins = require('next-compose-plugins');
const withCss = require('#zeit/next-css');
const withSass = require('#zeit/next-sass');
if (typeof require !== 'undefined') {
require.extensions['.css'] = file => {};
}
const nextConfig = {
webpack: (config, { isServer }) => {
if (isServer) {
const antStyles = /antd\/.*?\/style\/css.*?/;
const origExternals = [...config.externals];
config.externals = [ // eslint-disable-line
(context, request, callback) => { // eslint-disable-line
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;
},
};
module.exports = withPlugins(
[
[withCss],
[
withSass,
{
cssModules: true,
cssLoaderOptions: {
localIdentName: '[path]___[local]___[hash:base64:5]',
},
},
],
],
nextConfig,
);

Resources