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

chore: update eslint-config-eslint exports #17336

Merged
merged 8 commits into from Jul 10, 2023
Merged

Conversation

mdjermanovic
Copy link
Member

@mdjermanovic mdjermanovic commented Jul 3, 2023

Prerequisites checklist

What is the purpose of this pull request? (put an "X" next to an item)

[ ] Documentation update
[ ] Bug fix (template)
[ ] New rule (template)
[ ] Changes an existing rule (template)
[ ] Add autofix to a rule
[ ] Add a CLI option
[ ] Add something to the core
[x] Other, please explain:

Refs discussion in eslint/espree#577 (comment).

Currently, eslint-config-eslint exports a single config array suitable for CommonJS projects. That's fine for this repo, but most of the other repos are now ESM. Usage in an ESM repo would look like in eslint/espree#577:

import eslintConfigEslint from "eslint-config-eslint";
import nodeRecommendedModule from "eslint-plugin-n/configs/recommended-module.js";
import nodeRecommendedScript from "eslint-plugin-n/configs/recommended-script.js";

export default [
    // eslintConfigEslint[3] is eslint-plugin-n's recommended-script config
    ...eslintConfigEslint.slice(0, 3),
    {
        files: ["**/*.js"],
        ...nodeRecommendedModule
    },
    {
        files: ["**/*.cjs"],
        ...nodeRecommendedScript
    },
    ...eslintConfigEslint.slice(4)
];

That doesn't look very convenient.

What changes did you make? (Give an overview)

This PR changes eslint-config-eslint to export an object with 3 configs: base (config array), commonjs (config object), esm (config object), so that the usage would look like this:

import eslintConfigEslint from "eslint-config-eslint";

export default [
    ...eslintConfigEslint.base,
    {
        files: ["**/*.js"],
        ...eslintConfigEslint.esm
    },
    {
        files: ["**/*.cjs"],
        ...eslintConfigEslint.commonjs
    }
];

Is there anything you'd like reviewers to focus on?

Do the names make sense?

@mdjermanovic mdjermanovic added the chore This change is not user-facing label Jul 3, 2023
@mdjermanovic mdjermanovic requested a review from a team as a code owner July 3, 2023 18:40
@netlify
Copy link

netlify bot commented Jul 3, 2023

Deploy Preview for docs-eslint canceled.

Name Link
🔨 Latest commit 42ba8de
🔍 Latest deploy log https://app.netlify.com/sites/docs-eslint/deploys/64a86995b4e31700083f91c2

rules: {
"n/callback-return": ["error", ["cb", "callback", "next"]],
"n/handle-callback-err": ["error", "err"],
"n/no-deprecated-api": "error",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed n/no-deprecated-api from here because I believe it's already in eslint-plugin-n's recommended configs. Is that correct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@nzakas
Copy link
Member

nzakas commented Jul 3, 2023

Rather than forcing us to mix and match individual configs, what if we just exported an ESM-compatible array by default and included a CommonJS one under eslint-config-eslint/cjs?

That way, the default is equivalent to what we have now and the special case of CommonJS is set off to the side.

So you'd be able to do this:

import eslintConfigESLint from "eslint-config-eslint";

export default [
    ...eslintConfigESLint
];

And then in a CommonJS file do:

const eslintConfigESLint = require("eslint-config-eslint/cjs");

module.exports = [
    ...eslintConfigESLint
];

Comment on lines 27 to 29
"n/no-mixed-requires": "error",
"n/no-new-require": "error",
"n/no-path-concat": "error"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 3 rules will be in the commonjs config only because I believe they don't apply to ESM. Is that correct?

@mdjermanovic
Copy link
Member Author

Rather than forcing us to mix and match individual configs, what if we just exported an ESM-compatible array by default and included a CommonJS one under eslint-config-eslint/cjs?

That way, the default is equivalent to what we have now and the special case of CommonJS is set off to the side.

That's another option, but I think the usage would be more complicated in our ESM projects, where we have .js (ESM) and .cjs files. It would be something like this:

import eslintConfigESLint from "eslint-config-eslint";
import eslintConfigESLintCJS from "eslint-config-eslint/cjs";

export default [
    ...eslintConfigESLint.map(config => ({
        files: ["**/*.js"],
        ...config
    })),
    ...eslintConfigESLintCJS.map(config => ({
        files: ["**/*.cjs"],
        ...config
    }))
];

@nzakas
Copy link
Member

nzakas commented Jul 4, 2023

To me that seems less complicated because you don't have to mix and match a base with specific ESM or CJS configs. I'd like to plan for a future without CommonJS and design a solution that works optimally in that world even if its suboptimal in a current CommonJS repo.

@mdjermanovic
Copy link
Member Author

To me that seems less complicated because you don't have to mix and match a base with specific ESM or CJS configs. I'd like to plan for a future without CommonJS and design a solution that works optimally in that world even if its suboptimal in a current CommonJS repo.

Makes sense, I'll update the exports.

@mdjermanovic mdjermanovic changed the title chore: update eslint-config-eslint export chore: update eslint-config-eslint exports Jul 5, 2023
@aladdin-add
Copy link
Member

If had to choose, I would prefer the simpler way of usage. Can we export something like 4331d3c?

@mdjermanovic
Copy link
Member Author

I've updated exports so that the default export is the full configuration for ESM files, and there is an additional export /cjs that is the full configuration for CJS files.

I also added package.exports and updated package.engine because some plugins require "node": ">=16.0.0".

@mdjermanovic mdjermanovic marked this pull request as ready for review July 5, 2023 13:09
@mdjermanovic
Copy link
Member Author

If had to choose, I would prefer the simpler way of usage. Can we export something like 4331d3c?

That's another option, but since the new config system doesn't have a feature like eslintrc's overrides.extends that handles matching multiple lists, I think it should be best practice to avoid files in shareable configs.

@aladdin-add
Copy link
Member

That's another option, but since the new config system doesn't have a feature like eslintrc's overrides.extends that handles matching multiple lists, I think it should be best practice to avoid files in shareable configs.

just wondering the “best practice” should be strictly adhered to - it's much easier for users to move the files config to shared configs:

for esm projects:

const esmConfig = require("eslint-config-eslint/esm");
module.exports = [ ...esmConfig];

for cjs projects:

const cjsConfig = require("eslint-config-eslint/cjs");
module.exports = [ ...cjsConfig];

@mdjermanovic
Copy link
Member Author

The problem with files in shareable configs occurs when a shareable config should only be applied to some files. For example, in the eslint.org repo we have tools that run in Node (currently CommonJS modules but could be converted to ESM), modules that will be bundled in the Playground, and browser scripts. Assuming that we'll eventually convert tools to ESM, eslint-config-eslint's default export (or the esm export in your version) config array looks like a good candidate for those files, but not for the Playground modules and browser scripts, so it should be applied to tools/ only. If the config array contains a mix of ESM and CJS config items, restricting the config to a directory becomes complicated. I don't have a strong opinion on this though, and this is certainly a good exercise on creating and using shareable flat configs.

@aladdin-add
Copy link
Member

well, I see your point!

in my implementation, it has exported 3 configs: base, esm, cjs. They can easily be used directly in specific types of apps.

esm/cjs: only used for node.js apps (most eslint's repos should be using it).
base: for web apps like eslint.org, a new config can be created based on base.

I am happy with the current implementation, and I am somewhat discovering the flexibility of the new config system, we may need a little time to explore the best way to use it. 😄

Copy link
Member

@aladdin-add aladdin-add left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just waiting @nzakas to take another look.

Comment on lines 6 to 10
"exports": {
"./package.json": "./package.json",
".": "./index.js",
"./cjs": "./cjs.js"
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see a need to add this - we did this in the eslint package to avoid other devs using the internal modules, but this package is (mostly) only used by eslint. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be good to clarify which modules are intended to be public.

And with this, import "eslint-config-eslint/cjs" doesn't need .js extension :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to export ./eslintrc as well - it was used in .eslintrc.js:

"eslint/eslintrc"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Updated in 6f71c8e

@nzakas
Copy link
Member

nzakas commented Jul 6, 2023

That's another option, but since the new config system doesn't have a feature like eslintrc's overrides.extends that handles matching multiple lists, I think it should be best practice to avoid files in shareable configs

In general, I agree that a best practice would be to avoid files for any shareable configs intended to be modified and extended by other people. In our case, as we don't intend eslint-config-eslint to be used by anyone else, I think we should make it be as drop-in as possible. The fewer steps we need to make to properly use the config, the less likely we are to make mistakes.

I'm also fine with putting a big warning message on the README to this effect. :)

@mdjermanovic
Copy link
Member Author

All right, I'll update the config to include files.

@mdjermanovic mdjermanovic marked this pull request as draft July 6, 2023 19:46
@mdjermanovic mdjermanovic marked this pull request as ready for review July 7, 2023 23:37
@mdjermanovic
Copy link
Member Author

Ready for another review.

Copy link
Member

@aladdin-add aladdin-add left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. 👍

Copy link
Member

@nzakas nzakas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

@nzakas nzakas merged commit 5ca9b4d into main Jul 10, 2023
22 checks passed
@nzakas nzakas deleted the split-eslint-config-eslint branch July 10, 2023 15:38
bmish added a commit to bmish/eslint that referenced this pull request Jul 23, 2023
* main: (101 commits)
  docs: Migrating `eslint-env` configuration comments (eslint#17390)
  Merge pull request from GHSA-qwh7-v8hg-w8rh
  feat: adds option for allowing empty object patterns as parameter (eslint#17365)
  fix: FlatESLint#getRulesMetaForResults shouldn't throw on unknown rules (eslint#17393)
  docs: fix Ignoring Files section in config migration guide (eslint#17392)
  docs: Update README
  feat: Improve config error messages (eslint#17385)
  fix: Update no-loop-func to not overlap with no-undef (eslint#17358)
  docs: Update README
  docs: Update README
  8.45.0
  Build: changelog update for 8.45.0
  chore: package.json update for @eslint/js release
  docs: add playground links to correct and incorrect code blocks (eslint#17306)
  docs: Expand rule option schema docs (eslint#17198)
  docs: Config Migration Guide (eslint#17230)
  docs: Update README
  fix: Fix suggestion message in `no-useless-escape` (eslint#17339)
  docs: Update README
  chore: update eslint-config-eslint exports (eslint#17336)
  ...
@eslint-github-bot eslint-github-bot bot locked and limited conversation to collaborators Jan 7, 2024
@eslint-github-bot eslint-github-bot bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label Jan 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
archived due to age This issue has been archived; please open a new issue for any further discussion chore This change is not user-facing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants