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

docs: Config Migration Guide #17230

Merged
merged 22 commits into from Jul 13, 2023
Merged
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
365 changes: 365 additions & 0 deletions docs/src/use/configure/migration-guide.md
Copy link
Member

@fasttime fasttime Jun 25, 2023

Choose a reason for hiding this comment

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

The user guide lists migration instructions for all major versions up to 8.0.0. I was thinking that in order to maintain the current convention, this file should be named migrating-to-9.0.0.md or migrate-to-9.0.0.md.
I can't say if it would be good to add a link to this new guide now or wait until version 9.0.0 is released.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

would defer to the ESLint team on this naming and framing

Copy link
Member

Choose a reason for hiding this comment

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

@fasttime this would separate from the major version migration guides as it will span multiple versions.

@@ -0,0 +1,365 @@
---
title: Configuration Migration Guide
eleventyNavigation:
key: migration guide
parent: configure
title: Configuration Migration Guide
order: 8
---

This guide provides an overview of how you can migrate your ESLint configuration file from the `.eslintrc` format to the new configuration file format, `eslint.config.js`.
bpmutter marked this conversation as resolved.
Show resolved Hide resolved

To learn more about the `eslint.config.js` file format, refer to [this blog post](https://eslint.org/blog/2022/08/new-config-system-part-2/).
bpmutter marked this conversation as resolved.
Show resolved Hide resolved

For reference information on these configuration formats, refer to the following documentation:

* [`.eslintrc` configuration files](configuration-files)
* [`eslint.config.js` configuration files](configuration-files-new)
bpmutter marked this conversation as resolved.
Show resolved Hide resolved

## Start Using `eslint.config.js`

As of ESLint v9.0.0, the `eslint.config.js` file format is the default configuration file format. If you are using ESLint v9.0.0 or later, you can start using the `eslint.config.js` file format without any additional configuration.
Copy link
Member

Choose a reason for hiding this comment

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

it's a bit misleading to me - eslint v9 has not been released.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe the intention is for this guide to be published when v9 comes out. Please correct me if I'm wrong, and I can adjust the text.

Copy link
Member

Choose a reason for hiding this comment

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

We'll release this prior to v9 to encourage people to start the transition.


To use `eslint.config.js` with ESLint v8, place a `eslint.config.js` file in the root of your project **or** set an `ESLINT_USE_FLAT_CONFIG` environment variable to `true`.

## Key Differences between Configuration Formats
bpmutter marked this conversation as resolved.
Show resolved Hide resolved

A few of the most notable differences between the `.eslintrc` and `eslint.config.js` formats are the following:

### Importing Plugins and Custom Parsers
Copy link
Member

Choose a reason for hiding this comment

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

To me, the key difference is that in eslintrc files, plugins are specified by a string and loaded from a package by ESLint itself. On the other hand, with the flat config, it's the config file that is responsible for loading a plugin as an object (with require() or import()), and it's this object that is passed to ESLint.
Ultimately, with the flat config, the plugin doesn't have to be loaded from a package; it can be created by any programmatic means.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

rephrased here ff8aa3a


#### .eslintrc
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be helpful to summarize the difference under each header and then show the examples without headers. Maybe something like:

In eslintrc, plugins are loaded by specifying the name of the plugin in the plugins array; in flat config, you'll need to import the plugin object and then assign it to a property in the plugins object.


String-based import system with the `plugins` property to load plugins and `extends` to load configurations from the plugins.

```javascript
// .eslintrc.js

{
bpmutter marked this conversation as resolved.
Show resolved Hide resolved
// ...other config
plugins: ["jsdoc"],
rules: {
"jsdoc/require-description": "error",
"jsdoc/check-values": "error"
}
// ...other config
}
bpmutter marked this conversation as resolved.
Show resolved Hide resolved
```

#### eslint.config.js

Uses CommonJS `requires()` or ESModule `import` to load plugins and custom parsers.

```javascript
// eslint.config.js

import jsdoc from "eslint-plugin-jsdoc";

export default [
{
files: ["**/*.js"],
plugins: {
jsdoc: jsdoc
},
rules: {
"jsdoc/require-description": "error",
"jsdoc/check-values": "error"
}
}
];
```

### Custom Parsers

#### .eslintrc

Importing a custom parser is very similar to importing a plugin. However, a parser must be a separate module.

```javascript
// .eslintrc.js

{
bpmutter marked this conversation as resolved.
Show resolved Hide resolved
// ...other config
parser: "@babel/eslint-parser",
// ...other config
}
bpmutter marked this conversation as resolved.
Show resolved Hide resolved
```

#### eslint.config.js

To import a custom parser, import the parser as a module. Then assign it to the `languageOptions.parser` property of a configuration object:

```javascript
// eslint.config.js

import babelParser from "@babel/eslint-parser";

export default [
{
Copy link
Member

Choose a reason for hiding this comment

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

Lines 107-113 are missing one indentation space. Can you check, please?

// ...other config
languageOptions: {
parser: babelParser
}
// ...other config
}
];
```

### Glob-Based Configs

#### .eslintrc

By default, .`eslintrc` files lint all files (except those covered by `.gitignore`) in the directory in which they’re placed and its child directories:

```javascript
// .eslintrc.js

module.exports = {
// ...other config
rules: {
semi: ["warn", "always"]
}
};
```

If you want to have different configurations for different file glob patterns, you can specify them in the `overrides` property:

```javascript
// .eslintrc.js

module.exports = {
// ...other config
extends: "eslint:recommended",
bpmutter marked this conversation as resolved.
Show resolved Hide resolved
overrides: [
{
files: ["src/**/*"],
rules: {
semi: ["warn", "always"]
}
},
{
files:["test/**/*"],
rules: {
"no-console": "off"
}
}
]
};
```

#### eslint.config.js

By default, `eslint.config.js` files support different glob pattern-based configs in exported array. You can include the glob pattern in a config object's `files` property. If you don't specify a `files` property, the config defaults to the glob pattern `"**/*.{js,mjs,cjs}"`.

Basically, all configuration in the `eslint.config.js` file is like the .`eslintrc` `overrides` property.

Here is a configuration with the default glob pattern:

```javascript
// eslint.config.js

import js from "@eslint/js";

export default [
js.configs.recommended, // Recommended config applied to all files
bpmutter marked this conversation as resolved.
Show resolved Hide resolved
// Override the recommended config
{
rules: {
indent: ["error", 2],
Copy link
Member

Choose a reason for hiding this comment

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

Lines 174 and 175 are missing one indentation space.

"no-unused-vars": "warn"
}
// ...other configuration
}
];
```

An example configuration supporting multiple configs for different glob patterns:

```javascript
// eslint.config.js

import js from "@eslint/js";

export default [
js.configs.recommended, // Recommended config applied to all files
// File-pattern specific overrides
{
files: ["src/**/*", "test/**/*"],
rules: {
semi: ["warn", "always"]
bpmutter marked this conversation as resolved.
Show resolved Hide resolved
}
},
{
files:["test/**/*"],
rules: {
"no-console": "off"
}
}
// ...other configurations
];
```

### Configuring Language Options

#### .eslintrc

In `.eslintrc` files, you configure various language options across the `env`, `globals` and `parserOptions` properties.

Global variables for specific runtimes (e.g `document` for browser JavaScript and `process` for Node.js ) are configured with the `env` property.

```javascript
// .eslintrc

module.exports = {
env: {
browser: true,
},
globals: {
myCustomGlobal: "readonly",
},
parserOptions: {
ecmaVersion: 2022,
sourceType: "module"
}
// ...other config
}
```

#### eslint.config.js

In the `eslint.config.js`, the `globals`, and `parserOptions` are consolidated under the `languageOptions` key.

There is no longer the `env` property in `eslint.config.js`. Global variables for specific runtimes are imported from the [globals](https://www.npmjs.com/package/globals) npm package and included in the `globals` property. You can use the spread operator (`...`) to import all globals:

```javascript
// eslint.config.js

import globals from "globals";

export default [
{
languageOptions: {
globals: {
...globals.browser,
myCustomGlobal: "readonly"
},
parserOptions: {
ecmaVersion: 2022,
sourceType: "module"
}
}
// ...other config
}
];
```

### Predefined Configs

#### .eslintrc

To use predefined configs, use the `extends` property:

```javascript
// .eslintrc.js

module.exports = {
// ...other config
extends: "eslint:recommended",
rules: {
semi: ["warn", "always"]
},
// ...other config
}
```

ESLint comes with two predefined configs:

* `eslint:recommended`: the rules recommended by ESLint
* `eslint:all`: all rules shipped with ESLint

You can also use the `extends` property to extend a custom config. Custom configs can either be paths to local config files or npm package names:

```javascript
// .eslintrc.js

module.exports = {
// ...other config
extends: ["eslint:recommended", "./custom-config.js", "eslint-config-my-config"],
rules: {
semi: ["warn", "always"]
},
// ...other config
}
```

#### eslint.config.js

Predefined configs are imported from separate modules into `eslint.config.js` files.

The recommended and all rules configs are located in the [`@eslint/js`](https://www.npmjs.com/package/@eslint/js) package. You must import this package to use these configs:
bpmutter marked this conversation as resolved.
Show resolved Hide resolved

```shell
npm install @eslint/js -D
```

You can add each of these configs to the exported array or expose specific rules from them.

You must import the modules for local config files and npm package configs with `eslint.config.js`:

```javascript
// eslint.config.js

import js from "@eslint/js";
import customConfig from "./custom-config.js";
import myConfig from "eslint-config-my-config";

export default [
js.configs.recommended,
bpmutter marked this conversation as resolved.
Show resolved Hide resolved
customConfig,
myConfig,
{
rules: {
semi: ["warn", "always"]
},
// ...other config
}
];
```

Note that because you are just importing JavaScript modules, you can mutate the config objects before exporting them. For example, you might want to have a certain config object only apply to your test files:
bpmutter marked this conversation as resolved.
Show resolved Hide resolved

```javascript
// eslint.config.js

import js from "@eslint/js";
import customTestConfig from "./custom-test-config.js";

export default [
js.configs.recommended,
{
...customTestConfig,
files: ["**/*.test.js"],
},
];
```

## Things That Haven’t Changed between Configuration File Formats
Copy link
Contributor Author

Choose a reason for hiding this comment

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

to reviewer: other notable things which should be highlighted?

Copy link
Member

Choose a reason for hiding this comment

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

I think we should put this section first, to let people know "these are the things you don't have to worry about".

I think it's also helpful to point out that globals are configured the same way, just in a different location.


While all the above mentioned features have changed from `.eslintrc` to `eslint.config.js` configurations, the following has stayed the same:

* Syntax for adding rules
Copy link
Member

Choose a reason for hiding this comment

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

Do you mean syntax for configuring rules?

You don't use "syntax" elsewhere, so maybe just "Rule configuration"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah i meant 'adding rules to the configuration file', so i think saying 'Rule configuration' expresses that more concisely.

* Processors
* All functionality. Just the way to configure it has changed.
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure what "all functionality" means here. I think we can remove this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

by this, i mean "how ESLint lints files and reports errors". just the way to set up the configuration has changed.

i'll play w the phrasing a bit here.

* The CLI
Copy link
Member

Choose a reason for hiding this comment

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

as stated in the rfc, the following cli options will be no longer supported:

  • --rulesdir
  • --ext
  • --resolve-plugins-relative-to

Copy link
Member

Choose a reason for hiding this comment

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

--no-eslintrc has been replaced with --no-config-lookup.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added new CLI changes section


## TypeScript Types for eslint.config.js

You can see the TypeScript types for the eslint.config.js file format in the DefinitelyTyped project. The interface for the objects in the config’s array is called the `FlatConfig`.
bpmutter marked this conversation as resolved.
Show resolved Hide resolved

You can view the type definitions in the [DefinitelyTyped repository on Github](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/eslint/index.d.ts).

## Further Reading

* [Overview of the eslint.config.js file format blog post](https://eslint.org/blog/2022/08/new-config-system-part-2/)
bpmutter marked this conversation as resolved.
Show resolved Hide resolved
* [API usage of new configuration system blog post](https://eslint.org/blog/2022/08/new-config-system-part-3/)
* [Background to new configuration system blog post](https://eslint.org/blog/2022/08/new-config-system-part-1/)