next-compose-plugins icon indicating copy to clipboard operation
next-compose-plugins copied to clipboard

Incompatible with next.js 12.2.0: "Invalid next.config.js options detected"

Open fabb opened this issue 2 years ago • 26 comments

When compiling with next.js 12.2.0, this warning is shown, even when an empty array is passed for the plugins parameter:

warn  - Invalid next.config.js options detected: 
[
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "webpackDevMiddleware"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "configOrigin"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "target"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "analyticsId"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "webpack5"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "/amp/canonicalBase",
    "schemaPath": "#/properties/amp/properties/canonicalBase/minLength",
    "keyword": "minLength",
    "params": {
      "limit": 1
    },
    "message": "must NOT have fewer than 1 characters"
  },
  {
    "instancePath": "/basePath",
    "schemaPath": "#/properties/basePath/minLength",
    "keyword": "minLength",
    "params": {
      "limit": 1
    },
    "message": "must NOT have fewer than 1 characters"
  },
  {
    "instancePath": "/generateEtags",
    "schemaPath": "#/properties/generateEtags/isFunction",
    "keyword": "isFunction",
    "params": {},
    "message": "must pass \"isFunction\" keyword validation"
  },
  {
    "instancePath": "/i18n",
    "schemaPath": "#/properties/i18n/type",
    "keyword": "type",
    "params": {
      "type": "object"
    },
    "message": "must be object"
  },
  {
    "instancePath": "/webpack",
    "schemaPath": "#/properties/webpack/isFunction",
    "keyword": "isFunction",
    "params": {},
    "message": "must pass \"isFunction\" keyword validation"
  }
] 

fabb avatar Jul 22 '22 07:07 fabb

I am using next-compose-plugins with next-pwa, @sentry/nextjs and @next/bundle-analyzer and I get similar warnings

const nextPlugins = [
  [withBundleAnalyzer],
  [
    withPWA,
    {
      pwa: {
        dest: 'public',
        register: true,
        skipWaiting: true,
        disable: process.env.NODE_ENV === 'development',
        buildExcludes: [/middleware-manifest.json$/],
      },
    },
  ],
  (nextConfig) => withSentryConfig(nextConfig, sentryWebpackPluginOptions),
];
...
module.exports = withPlugins(nextPlugins, nextConfig);

theabdulmateen avatar Jul 22 '22 10:07 theabdulmateen

I ditched next-compose-plugins since it's unmaintained and replaced it with these lines:

module.exports = (_phase, { defaultConfig }) => {
    const plugins = [withStaticImport, withBundleAnalyzer, withCustomWebpack]
    return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...config })
}

fabb avatar Jul 22 '22 12:07 fabb

I ditched next-compose-plugins since it's unmaintained and replaced it with these lines:

module.exports = (_phase, { defaultConfig }) => {
    const plugins = [withStaticImport, withBundleAnalyzer, withCustomWebpack]
    return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...config })
}

How would you use the extend feature with your method? I have a ton of redirects so I put them in their own separate config file.

jordanlambrecht avatar Jul 23 '22 03:07 jordanlambrecht

Just spread them too.

fabb avatar Jul 23 '22 06:07 fabb

I ditched next-compose-plugins since it's unmaintained and replaced it with these lines:

module.exports = (_phase, { defaultConfig }) => {
    const plugins = [withStaticImport, withBundleAnalyzer, withCustomWebpack]
    return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...config })
}

Hey @fabb... using your example, I see the same warning message:

warn  - Invalid next.config.js options detected: 
[
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "webpackDevMiddleware"
    },
    "message": "must NOT have additional properties"
  },

...

brenopolanski avatar Jul 23 '22 12:07 brenopolanski

For me the warnings are gone, so I guess one of your plugins or your config sets webpackDevMiddleware etc. somewhere?

fabb avatar Jul 23 '22 13:07 fabb

module.exports = (_phase, { defaultConfig }) => { const plugins = [withStaticImport, withBundleAnalyzer, withCustomWebpack] return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...config }) }

Strange... i am just using the withBundleAnalyzer plugin for now.

In my tests I tried this code below:

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

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
}

module.exports = (_phase, { defaultConfig }) => {
    const plugins = [withBundleAnalyzer]
    return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...nextConfig })
}

brenopolanski avatar Jul 23 '22 18:07 brenopolanski

related issue https://github.com/vercel/next.js/issues/38909

shifenhutu avatar Jul 24 '22 04:07 shifenhutu

I ditched next-compose-plugins since it's unmaintained and replaced it with these lines:

module.exports = (_phase, { defaultConfig }) => {
    const plugins = [withStaticImport, withBundleAnalyzer, withCustomWebpack]
    return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...config })
}

why i got like this

image

with config

const withPWA = require('next-pwa');

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: false,
  swcMinify: true,
  compiler: {
    removeConsole: true,
  },
};

module.exports = (_phase, { defaultConfig }) => {
  const plugins = [
    withPWA({
      pwa: {
        dest: 'public',
        disable: process.env.NODE_ENV === 'development',
        register: true,
      },
    }),
  ];
  return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...nextConfig });
};

d-string avatar Jul 29 '22 02:07 d-string

I don't understand, I don't have webpack customisations but I get lots of warnings:

/** @type {import('next').NextConfig} */
const config = {
  reactStrictMode: true,
};

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

const withMDX = require('@next/mdx')({
  extension: /\.mdx?$/,
  pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'mdx'],
});

const plugins = [withBundleAnalyzer, withMDX];

module.exports = (_phase, { defaultConfig }) => {
  const finalConfig = { ...defaultConfig, config };
  plugins.forEach(plugin => plugin(finalConfig));
  return finalConfig;
}

Next yells about:

$ next dev -p 80
ready - started server on 0.0.0.0:80, url: http://localhost:80
info  - Loaded env from /Users/damians/Desktop/webapp/.env
warn  - Invalid next.config.js options detected:
[
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "webpackDevMiddleware"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "configOrigin"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "target"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "analyticsId"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "webpack5"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "config"
    },
    "message": "must NOT have additional properties"
  },
  {
    "instancePath": "/amp/canonicalBase",
    "schemaPath": "#/properties/amp/properties/canonicalBase/minLength",
    "keyword": "minLength",
    "params": {
      "limit": 1
    },
    "message": "must NOT have fewer than 1 characters"
  },
  {
    "instancePath": "/assetPrefix",
    "schemaPath": "#/properties/assetPrefix/minLength",
    "keyword": "minLength",
    "params": {
      "limit": 1
    },
    "message": "must NOT have fewer than 1 characters"
  },
  {
    "instancePath": "/basePath",
    "schemaPath": "#/properties/basePath/minLength",
    "keyword": "minLength",
    "params": {
      "limit": 1
    },
    "message": "must NOT have fewer than 1 characters"
  },
  {
    "instancePath": "/experimental/outputFileTracingRoot",
    "schemaPath": "#/properties/experimental/properties/outputFileTracingRoot/minLength",
    "keyword": "minLength",
    "params": {
      "limit": 1
    },
    "message": "must NOT have fewer than 1 characters"
  },
  {
    "instancePath": "/generateEtags",
    "schemaPath": "#/properties/generateEtags/isFunction",
    "keyword": "isFunction",
    "params": {},
    "message": "must pass \"isFunction\" keyword validation"
  },
  {
    "instancePath": "/i18n",
    "schemaPath": "#/properties/i18n/type",
    "keyword": "type",
    "params": {
      "type": "object"
    },
    "message": "must be object"
  },
  {
    "instancePath": "/webpack",
    "schemaPath": "#/properties/webpack/isFunction",
    "keyword": "isFunction",
    "params": {},
    "message": "must pass \"isFunction\" keyword validation"
  }
]
See more info here: https://nextjs.org/docs/messages/invalid-next-config

damianobarbati avatar Jul 29 '22 09:07 damianobarbati

i got fixing config next-pwa (v 5.5.5) with this config

const withPWA = require('next-pwa');

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  compiler: {
    removeConsole: process.env.NODE_ENV !== 'development',
  },
  pwa: {
    dest: 'public',
    disable: process.env.NODE_ENV === 'development',
    register: true,
  },
};

module.exports = () => {
  const plugins = [withPWA];
  const config = plugins.reduce((acc, next) => next(acc), {
    ...nextConfig,
  });
  return config;
};

but i go twice print [PWA] Compile server like this

image

or [PWA] PWA support is disabled

image

d-string avatar Jul 29 '22 18:07 d-string

I ditched since it's unmaintained and replaced it with these lines:next-compose-plugins

module.exports = (_phase, { defaultConfig }) => {
    const plugins = [withStaticImport, withBundleAnalyzer, withCustomWebpack]
    return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...config })
}

Hey @fabb... using your example, I see the same warning message:

warn  - Invalid next.config.js options detected: 
[
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "webpackDevMiddleware"
    },
    "message": "must NOT have additional properties"
  },

...

I faced the same problem, but it worked fine by removing defaultConfig.

/** @type {import('next').NextConfig} */
const nextConfig = {
  // ...
};

module.exports = (_phase, { defaultConfig }) => {
    const plugins = [/* ... */]
    return plugins.reduce((acc, plugin) => plugin(acc), { ...nextConfig })
}

gendaineko2222 avatar Aug 09 '22 09:08 gendaineko2222

Just ignore default config. Seems, its NextJS related issue.

Even using defaultConfig as is throws an error:

module.exports = async (phase, { defaultConfig }) => {
    return defaultConfig
};

Hence, its not a next-compose-plugins package error.

So, as a workaround, use it like below (just ignore defaultConfig existence):

module.exports = async (phase) => {
    /** @type {import('next').NextConfig} */
    const nextConfig = {
        reactStrictMode: true,
        swcMinify: true
    };

    const defaultConfig = {}
    return withPlugins([], nextConfig)(phase, { defaultConfig });
    // return withPlugins([], nextConfig)(phase, { undefined }); // also works
};

vsfedorenko avatar Aug 16 '22 21:08 vsfedorenko

For anyone who switched to @gendaineko2222's suggested solution (like I did) and ran into a TypeError: plugin is not a function when passing a plugin as an array with some plugin-specific configuration (as outline here: https://github.com/cyrilwanner/next-compose-plugins/#configuration-object), this is the change that I had to make to handle that case:

module.exports = (_phase, { defaultConfig }) => {
  return plugins.reduce(
    (acc, plugin) => {
      if (Array.isArray(plugin)) {
        return plugin[0](acc, plugin[1]);
      }
      return plugin(acc);
    },
    { ...nextConfig }
  );
};

raphaelsaunier avatar Aug 19 '22 14:08 raphaelsaunier

For anyone looking for a full next.config.js solution that removes the warnings, here's what I use:

/* eslint-disable @typescript-eslint/no-var-requires */
const CircularDependencyPlugin = require('circular-dependency-plugin')
const withPWA = require('next-pwa')({
  dest: 'public',
  disable: process.env.NODE_ENV === 'development',
})

const plugins = []

if (process.env.ANALYZE === 'true') {
  // only load dependency if env `ANALYZE` was set
  const withBundleAnalyzer = require('@next/bundle-analyzer')({
    enabled: true,
  })

  plugins.push(withBundleAnalyzer)
}

plugins.push(withPWA)

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  webpack: (config) => {
    config.plugins.push(
      new CircularDependencyPlugin({
        exclude: /a\.js|node_modules/,
        include: /src/,
        failOnError: true,
        allowAsyncCycles: false,
        cwd: process.cwd(),
      }),
    )

    return config
  },
}

module.exports = () => plugins.reduce((acc, next) => next(acc), nextConfig)

brenopolanski avatar Aug 29 '22 13:08 brenopolanski

module.exports = () => { const plugins = [withPWA]; const config = plugins.reduce((acc, next) => next(acc), { ...nextConfig, }); return config; };

This work for me

ahmadyusri avatar Sep 09 '22 23:09 ahmadyusri

Just ignore default config. Seems, its NextJS related issue.

Even using defaultConfig as is throws an error:

module.exports = async (phase, { defaultConfig }) => {
    return defaultConfig
};

Hence, its not a next-compose-plugins package error.

So, as a workaround, use it like below (just ignore defaultConfig existence):

module.exports = async (phase) => {
    /** @type {import('next').NextConfig} */
    const nextConfig = {
        reactStrictMode: true,
        swcMinify: true
    };

    const defaultConfig = {}
    return withPlugins([], nextConfig)(phase, { defaultConfig });
    // return withPlugins([], nextConfig)(phase, { undefined }); // also works
};

What you can do instead is:

import nextComposePlugins from 'next-compose-plugins'
const { withPlugins } = nextComposePlugins.extend(() => ({}))

and then as before

const config = withPlugins(
  [...],
  nextConfig
)

export default config

dmitriy-baltak avatar Sep 12 '22 10:09 dmitriy-baltak

I ditched next-compose-plugins since it's unmaintained and replaced it with these lines:

module.exports = (_phase, { defaultConfig }) => {
    const plugins = [withStaticImport, withBundleAnalyzer, withCustomWebpack]
    return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...config })
}

I was still seeing the warnings after this change because of what was in defaultConfig. This workaround resolved them for me, and still maintained the defaultConfig usage. Still seeing the warning about .assetPrefix as it errors if you remove the field.

module.exports = (_phase, { defaultConfig }) => {
    // Workaround
    delete defaultConfig.webpackDevMiddleware;
    delete defaultConfig.configOrigin;
    delete defaultConfig.target;
    delete defaultConfig.webpack5;
    delete defaultConfig.amp.canonicalBase;
    delete defaultConfig.experimental.outputFileTracingRoot;
    delete defaultConfig.i18n;

    const plugins = [withStaticImport, withBundleAnalyzer, withCustomWebpack]
    return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...config })
}

Related issue: https://github.com/vercel/next.js/issues/39161

jakeorr avatar Sep 15 '22 18:09 jakeorr

Used Fix: @meiblorn @comment.

From:

const withPlugins = require('next-compose-plugins');
const nextTranslate = require('next-translate');

const nextConfig = {
  reactStrictMode: true,
};

module.exports = withPlugins([[nextTranslate]], nextConfig);

To:

const withPlugins = require('next-compose-plugins');
const nextTranslate = require('next-translate');

const nextConfig = {
  reactStrictMode: true,
};

module.exports = async (phase) => withPlugins([nextTranslate], nextConfig)(phase, { undefined });

LaCocoRoco avatar Sep 28 '22 19:09 LaCocoRoco

If you want to keep the default config you could do the following:

module.exports = async (phase, { defaultConfig }) => 
    withPlugins([nextTranslate], nextConfig)(phase, { ...defaultConfig, ...nextConfig });

rubek-joshi avatar Oct 13 '22 06:10 rubek-joshi

I think all of the codes above make the things complex, you can just use one reduce line for composing all the plugins.

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

const nextTranslate = require('next-translate');

// Compose all the plugins one by one.
const plugins = [bundleAnalyzer, nextTranslate];

/** @type {import('next').NextConfig} */
const bookstairsConfig = {
  reactStrictMode: true,
};

module.exports = plugins.reduce((config, plugin) => plugin(config), bookstairsConfig)

syhily avatar Oct 23 '22 16:10 syhily

I think all of the codes above make the things complex, you can just use one reduce line for composing all the plugins.

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

const nextTranslate = require('next-translate');

// Compose all the plugins one by one.
const plugins = [bundleAnalyzer, nextTranslate];

/** @type {import('next').NextConfig} */
const bookstairsConfig = {
  reactStrictMode: true,
};

module.exports = plugins.reduce((config, plugin) => plugin(config), bookstairsConfig)

it keeps telling me TypeError : plugin is not a function

JalalMitali avatar Nov 07 '22 19:11 JalalMitali

I'm using next-pwa, @sentry/nextjs and @next/bundle-analyzer and completely removed next-compose-plugins. No warnings and works with @sentry/nextjs

const {PHASE_PRODUCTION_BUILD} = require('next/constants');

/** @type {import('next').NextConfig} */
const nextConfig = {
   // your config
  }
};

module.exports = phase => {
  const plugins = [];

  if (phase === PHASE_PRODUCTION_BUILD) {
    if (process.env.ANALYZE === '1') {
      plugins.push(
        require('@next/bundle-analyzer')({
          enabled: true
        }),
      );
    }

    plugins.push(
      require('next-pwa')({
        // your config
      }),
    );

    plugins.push(nextConfig =>
      require('@sentry/nextjs').withSentryConfig(
        {
          ...nextConfig,
          sentry: {
             // your config
          },
        },
        {silent: true},
      )(phase, {nextConfig}),
    );
  }

  return plugins.reduce((acc, plugin) => plugin(acc), nextConfig);
};

nghiepdev avatar Dec 04 '22 07:12 nghiepdev

I'm using next-pwa, @sentry/nextjs and @next/bundle-analyzer . Did this without next-compose-plugins

module.exports = withSentryConfig(withPWA(withBundleAnalyzer(yourNextConfig)), { silent: true });

Works fine 👍🏻

dalalRohit avatar Dec 06 '22 11:12 dalalRohit

I ditched next-compose-plugins since it's unmaintained and replaced it with these lines:

module.exports = (_phase, { defaultConfig }) => {
    const plugins = [withStaticImport, withBundleAnalyzer, withCustomWebpack]
    return plugins.reduce((acc, plugin) => plugin(acc), { ...defaultConfig, ...config })
}

For those using the .reduce() strategy, please be aware that the return value of plugin(acc) isn't always a function (depending on the plugin you use: https://github.com/getsentry/sentry-javascript/issues/6447#issuecomment-1340671081

I'd suggest the following edit:

const bundleAnalyzer = require(https://github.com/vercel/next.js/tree/master/packages/next-bundle-analyzer)({
  enabled: process.env.ANALYZE === 'true'
});

module.exports = (phase, defaultConfig) => {
  const plugins = [
    // other plugins
    bundleAnalyzer,
    (config) => withSentryConfig(config, sentryWebpackPluginOptions),
    // other plugins
  ];

  const config = plugins.reduce((acc, plugin) => {
    const update = plugin(acc);
    return typeof update === "function" ? update(phase, defaultConfig) : update;
  }, { ...nextConfig });

  return config;
};

kylemh avatar Dec 07 '22 14:12 kylemh

I have the same issue, but i cannot find out anything about target

image image

dangvanduc1999gspit avatar Dec 16 '22 06:12 dangvanduc1999gspit