nx/docs/shared/recipes/tips-n-tricks/migrating-to-flat-eslint.md
Jack Hsu b9c0e3db5f
feat(eslint): rename eslint.config.js to eslint.config.cjs to resolve them as CommonJS (#29334)
This PR updates our generators to use `eslint.config.cjs` instead of
`eslint.config.js` so that Node resolution will treat it as CommonJS.
This solves an issue where having `"type": "module"` in `package.json`
will result in an error when Node tries to resolve the config file as
ESM.

Also allows us to clean up out Remix generators to not have to rename to
`eslint.config.cjs` to solve the same issue.

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
2024-12-18 16:34:10 -05:00

174 lines
4.9 KiB
Markdown

# Switching to ESLint's flat config format
Version 8 of ESLint introduced a new configuration format called [Flat Config](https://eslint.org/docs/latest/use/configure/configuration-files-new). The next major version will use this config format by default. The purpose of this format is to:
- push towards a single configuration format (in contrast to the existing `JSON`, `Yaml` and `JS`-based configs)
- enforce explicit native loading (instead of the implicit imports in `JSON` and `Yaml`)
- use a flat cascading of rules (instead of a mix of rules and overrides)
See below a direct comparison between `JSON`, `JS` and `Flat` config:
{% tabs %}
{% tab label="Flat" %}
```js {% fileName="eslint.config.cjs" %}
// the older versions were magically interpreting all the imports
// in flat config we do it explicitly
const nxPlugin = require('@nx/eslint-plugin');
const js = require('@eslint/js');
const baseConfig = require('./eslint.base.config.cjs');
const globals = require('globals');
const jsoncParser = require('jsonc-eslint-parser');
const tsParser = require('@typescript-eslint/parser');
module.exports = [
js.configs.recommended,
// this will spread the export blocks from the base config
...baseConfig,
{ plugins: { '@nx': nxPlugin } },
{
languageOptions: {
parser: tsParser,
globals: {
...globals.node,
},
},
rules: {
'@typescript-eslint/explicit-module-boundary-types': ['error'],
},
},
// there are no overrides, all the config blocks are "flat"
{
files: ['*.json'],
languageOptions: {
parser: jsoncParser,
},
rules: {},
},
{
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
rules: {
'@nx/enforce-module-boundaries': [
'error',
{
enforceBuildableLibDependency: true,
allow: [],
depConstraints: [
{
sourceTag: '*',
onlyDependOnLibsWithTags: ['*'],
},
],
},
],
},
},
];
```
{% /tab %}
{% tab label="JSON" %}
```json {% fileName=".eslintrc.json" %}
{
"root": true,
"parser": "@typescript-eslint/parser",
"env": {
"node": true
},
"extends": ["eslint:recommended", "./.eslintrc.base.json"],
"plugins": ["@nx"],
"rules": {
"@typescript-eslint/explicit-module-boundary-types": "error"
},
"overrides": [
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {}
},
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {
"@nx/enforce-module-boundaries": [
"error",
{
"enforceBuildableLibDependency": true,
"allow": [],
"depConstraints": [
{
"sourceTag": "*",
"onlyDependOnLibsWithTags": ["*"]
}
]
}
]
}
}
]
}
```
{% /tab %}
{% tab label="JS" %}
```js {% fileName=".eslintrc.js" %}
module.exports = {
root: true,
env: {
node: true,
},
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', './.eslintrc.base.js'],
plugins: ['@nx'],
rules: {
'@typescript-eslint/explicit-module-boundary-types': ['error'],
},
overrides: [
{
files: ['*.json'],
parser: 'jsonc-eslint-parser',
rules: {},
},
{
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
rules: {
'@nx/enforce-module-boundaries': [
'error',
{
enforceBuildableLibDependency: true,
allow: [],
depConstraints: [
{
sourceTag: '*',
onlyDependOnLibsWithTags: ['*'],
},
],
},
],
},
},
],
};
```
{% /tab %}
{% /tabs %}
For additional details, head over to [ESLint's official blog post](https://eslint.org/blog/2022/08/new-config-system-part-2/).
Since version 16.8.0, Nx supports the usage of flat config in the [@nx/eslint:lint](/nx-api/eslint/executors/lint) executor and `@nx/*` generators, and provides an automated config conversion from `.eslintrc.json` config files.
## Converting workspace from .eslintrc.json to flat config
To convert workspace ESLint configurations from the default `.eslintrc.json` to the new flat config you need to run:
```shell
nx g @nx/eslint:convert-to-flat-config
```
The generator will go through all the projects and convert their configurations to the new format. It will also convert the base `.eslintrc.json` and `.eslintignore`.
## Correctness and best practices
The purpose of this generator is to create a flat config that works the same way as the original `JSON` config did. Depending on the complexity of your original config, it may be using the `FlatCompat` utility to provide a compatibility wrapper around parts of the original config. You can improve those by following the [official migration guide](https://eslint.org/docs/latest/use/configure/migration-guide).