question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Change Request: Support ESM plugins

See original GitHub issue

ESLint version

v8.4.1

What problem do you want to solve?

I have implemented an eslint-plugin that relies on a 3rd-party npm package. Using a 3rd-party npm package allows me to reuse existing assets and develop an eslint-plugin quickly.

On the other hand, there is an increasing number of pure ESM npm packages on npmjs.com. Dynamic import is the only way to import pure ESM packages from CJS (ref). Currently, ESLint only supports eslint-plugin in CJS format and does not allow async plugins, making it virtually impossible to use Pure ESM packages with eslint-plugin (ref: #15394).

> yarn add -D git://github.com/mizdra/eslint-plugin-layout-shift.git#2a97ffba28749d0311f068f2eacd96180686bf40
> yarn run lint:eslint
yarn run v1.22.15
$ eslint .

Oops! Something went wrong! :(

ESLint: 8.4.1

Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@mizdra/eslint-plugin-layout-shift/lib/index.js from /Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@eslint/eslintrc/dist/eslintrc.cjs not supported.
Instead change the require of index.js in /Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@eslint/eslintrc/dist/eslintrc.cjs to a dynamic import() which is available in all CommonJS modules.
    at ConfigArrayFactory._loadPlugin (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3342:42)
    at /Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3214:33
    at Array.reduce (<anonymous>)
    at ConfigArrayFactory._loadPlugins (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3210:22)
    at ConfigArrayFactory._normalizeObjectConfigDataBody (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3031:44)
    at _normalizeObjectConfigDataBody.next (<anonymous>)
    at ConfigArrayFactory._normalizeObjectConfigData (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2971:20)
    at _normalizeObjectConfigData.next (<anonymous>)
    at ConfigArrayFactory.loadInDirectory (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2817:28)
    at CascadingConfigArrayFactory._loadConfigInAncestors (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3772:46)
    at CascadingConfigArrayFactory.getConfigArrayForFile (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3693:18)
    at FileEnumerator._iterateFilesRecursive (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/eslint/lib/cli-engine/file-enumerator.js:482:49)
    at _iterateFilesRecursive.next (<anonymous>)
    at FileEnumerator.iterateFiles (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/eslint/lib/cli-engine/file-enumerator.js:297:49)
    at iterateFiles.next (<anonymous>)
    at CLIEngine.executeOnFiles (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/eslint/lib/cli-engine/cli-engine.js:778:48)
    at ESLint.lintFiles (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/eslint/lib/eslint/eslint.js:559:23)
    at Object.execute (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/eslint/lib/cli.js:301:36)
    at main (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/eslint/bin/eslint.js:132:52)
    at Object.<anonymous> (/Users/mizdra/src/github.com/mizdra/scrapbox-userscript-icon-suggestion/node_modules/eslint/bin/eslint.js:136:2)
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

What do you think is the correct solution?

I would like to see ESLint support the eslint-plugin for ESM. This will allow us to import Pure ESM packages from eslint-plugin with an import statement.

Internally, we need a mechanism to switch the import method depending on whether eslint-plugin is CJS or ESM. Jest’s implementation of switching the import method for jest.config.js (in pkg.type == 'module') / jest.config.cjs may be helpful (ref1, ref2).

Here are the lines that need to be changed:

Participation

  • I am willing to submit a pull request for this change.

Additional comments

  • Does eslint/eslintrc allow asynchronous code in the first place?
    • I didn’t understand it. Is this feature difficult to implement for the same reason as #15394?
  • This feature is related to #15394
    • #15394 also allows ESM import with eslint-plugin (or rule)
  • This feature may also be related to #14139

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:16 (9 by maintainers)

github_iconTop GitHub Comments

5reactions
mdjermanoviccommented, Dec 26, 2021

The current eslintrc config system is frozen as we are working on the new flat config system (https://github.com/eslint/eslint/issues/13481).

The new config system will expect config files to load plugins instead of just specifying them by name, so I believe that ESM plugins can “just work”.

For example, if this is an ESM plugin:

//------ eslint-plugin-foo (ESM) ------

export default {
    rules: {
        "my-rule": {
            create(context) {
                // rule implementation ...
            }
        }
    }
}

then, it can be used in ESM config files like this:

//------ eslint.config.js (ESM) ------

import foo from "eslint-plugin-foo";

export default [{
    plugins: {
        foo
    },
    rules: {
        "foo/my-rule": "error"
    }
}];

and a bit more complicated in CJS config files, like this:

//------ eslint.config.js (CJS) ------

module.exports = async () => [{
    plugins: {
        foo: (await import("eslint-plugin-foo")).default
    },
    rules: {
        "foo/my-rule": "error"
    }
}];
3reactions
nzakascommented, Dec 28, 2021

Yes, the current config system is frozen. It doesn’t make sense to open any further issues for config changes until the new config system is available for testing (you may be requesting something that already works).

As best I can tell from my prototype, ESM should “just work” as expected in the new config system. Hopefully we will have a developer preview available in the next couple of months.

Read more comments on GitHub >

github_iconTop Results From Across the Web

What does it take to support Node.js ESM?
To add support ESM for Node.js, you have two alternatives: ... If you have a top-level require , changing it to ESM should...
Read more >
Output
The method to load chunks (methods included by default are 'jsonp' (web), 'import' (ESM), 'importScripts' (WebWorker), 'require' (sync node.js), 'async-node' ( ...
Read more >
JavaScript · Bootstrap v5.0
Bring Bootstrap to life with our optional JavaScript plugins. Learn about each plugin, our data and programmatic API options, and more.
Read more >
Plugins
This is useful in case a plugin depends on changes made to the Fastify instance by a preceding ... ESM is supported as...
Read more >
Activate Service Portal
Locate the Service Portal for Enterprise Service Management [com.glide.service-portal.esm] plugin in the list of plugins.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found