Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: Cannot redefine plugin #135

Closed
zwaittt opened this issue Nov 15, 2023 · 8 comments · Fixed by #137
Closed

TypeError: Cannot redefine plugin #135

zwaittt opened this issue Nov 15, 2023 · 8 comments · Fixed by #137
Assignees
Labels
accepted bug Something isn't working

Comments

@zwaittt
Copy link

zwaittt commented Nov 15, 2023

happens when migrate legacy eslintrc config with flat configs.

const { FlatCompat } = require("@eslint/eslintrc");
const antfu = require('@antfu/eslint-config').default;

const compat = new FlatCompat({});

module.exports = [
  ...compat.config({
    "extends": "next/core-web-vitals"
  }),
  ...antfu({
    typescript: true,
  }),
];
Oops! Something went wrong! :(

ESLint: 8.53.0

TypeError: Cannot redefine plugin "import".

both legacy and flat from @antfu/eslint-config contains eslint-plugin-import, but seems this was fixed in #91

@nzakas
Copy link
Member

nzakas commented Nov 16, 2023

If it seems it was fixed, then what is this issue reporting?

@zwaittt
Copy link
Author

zwaittt commented Nov 17, 2023

My bad, I mean maybe the issue related in #91 is't fixed actually. The following stackblitz project shows the error I encountered.
https://stackblitz.com/edit/stackblitz-starters-79aqit?file=package.json

image

@nzakas nzakas added the bug Something isn't working label Nov 17, 2023
@nzakas
Copy link
Member

nzakas commented Nov 17, 2023

Thanks, that's very helpful. I'll take a look.

@nzakas
Copy link
Member

nzakas commented Nov 20, 2023

Okay, so there is an issue here. As part of loading configuration information, we normalize the plugin:

function normalizePlugin(plugin) {
// first check the cache
let normalizedPlugin = normalizedPlugins.get(plugin);
if (normalizedPlugin) {
return normalizedPlugin;
}
normalizedPlugin = {
configs: plugin.configs || {},
environments: plugin.environments || {},
processors: plugin.processors || {},
rules: plugin.rules || {}
};
// save the reference for later
normalizedPlugins.set(plugin, normalizedPlugin);
return normalizedPlugin;
}

This is actually problematic for a couple of reasons:

  1. We lose the original plugin reference
  2. We lose any meta information that might be on the object.

I know the intent of this normalization was to prevent us from needing to check if a plugin had properly defined configs, rules, etc.

I see two potential solutions to this:

  1. Stop normalizing plugins. It appears that the only place that uses this information is config-array.js, so I think we can make this change without affecting ESLint as a whole.
  2. Normalize smarter. We could normalize in a way that retains the original plugin reference, perhaps by using Object.create() on the plugin first. This would also require a corresponding change in ESLint to check for the prototype (or wherever we store the original plugin reference).

I'd appreciate some thoughts from @eslint/eslint-team on this.

@mdjermanovic
Copy link
Member

mdjermanovic commented Nov 21, 2023

Maybe we could add new property ConfigDependency#originalDefinition (the original plugin reference) and use it in FlatCompat instead of the normalized definition.

const { definition: plugin, error } = eslintrcConfig.plugins[pluginName];

I think that would be the change with the least chance of breaking something.

I just tried it and the stackblitz example seems to be working well after the change.

@nzakas
Copy link
Member

nzakas commented Nov 21, 2023

Ah, that's a great idea variation of option 2. I'll put together a PR.

@nzakas nzakas self-assigned this Nov 21, 2023
nzakas added a commit that referenced this issue Nov 22, 2023
mdjermanovic pushed a commit that referenced this issue Nov 27, 2023
* fix: Use original plugin from disk in FlatCompat

Fixes #135

* Clean up lint errors

* Hide original field from serialization
@matthew-dean
Copy link

This issue is driving me crazy. I'm migrating to the flat config file format, and I have lots of errors like:

Cannot redefine plugin "vue"
...
Cannot redefine plugin "storybook"

I think the issue is that sub-configs, such as @nuxt/eslint-config use plugins like eslint-plugin-vue, with a different version. However, IMO that should be perfectly valid, especially when the "final" configuration for me .vue files is applying @nuxt/eslint-config.

This is an issue that's brand new to the eslint flat config and is not fixed yet. Please re-open.

@matthew-dean
Copy link

matthew-dean commented Jan 26, 2024

Note that I've run pnpm why eslint-plugin-storybook -r and there's only one version of this plugin installed.

Hmm, it seems that's because my root eslint.config.js has:

  ...compat.config({
    overrides: [
      {
        extends: ['standard', 'plugin:storybook/recommended'],
        files: ['*.js']
      }
    ]
  }),

And a package eslint.config.js has:

  ...compat.extends(
    '@nuxt/eslint-config',
    'plugin:storybook/recommended'
  ),

Removing the root fixes it, but regardless:

  1. This was not previously a problem.
  2. There's still only one plugin being referenced, but ESLint still gets confused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted bug Something isn't working
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

4 participants