rsnext/packages/next/lib/eslint/writeDefaultConfig.ts
Houssein Djirdeh 7a1c9eb17e
[ESLint] Introduce a new setup process when next lint is run for the first time (#26584)
This PR introduces an improved developer experience when `next lint` is run for the first time.

### Current behavior

`eslint-config-next` is a required package that must be installed before proceeding with `next lint` or `next build`:

![image](https://user-images.githubusercontent.com/12476932/123468791-43088100-d5c0-11eb-9ad0-5beb80b6c968.png)

Although this has helped many developers start using the new ESLint config, this has also resulted in a few issues:

- Users are required to install the full config (`eslint-config-next`) even if they do not use it or use the Next.js plugin directly (`eslint-plugin-next`).
  - #26348

- There's some confusion  on why `eslint-config-next` needs to be installed or how it should be used instead of `eslint-plugin-next`.
  - #26574
  - #26475
  - #26438

### New behavior

Instead of enforcing `eslint-config-next` as a required package, this PR prompts the user by asking what config they would like to start. This happens when `next lint` is run for the first time **and** if no ESLint configuration is detected in the application.

<img src="https://user-images.githubusercontent.com/12476932/124331177-e1668a80-db5c-11eb-8915-38d3dc20f5d4.gif" width="800" />

- The CLI will take care of installing `eslint` or `eslint-config-next` if either is not already installed
- Users now have the option to choose between a strict configuration (`next/core-web-vitals`) or just the base configuration (`next`)
- For users that decide to create their own ESLint configuration, or already have an existing one, **installing `eslint-config-next` will not be a requirement for `next lint` or `next build` to run**. A warning message will just show if the Next.js ESLint plugin is not detected in an ESLint config. 

  <img width="682" alt="Screen Shot 2021-06-25 at 3 02 12 PM" src="https://user-images.githubusercontent.com/12476932/123473329-6cc4a680-d5c6-11eb-9a57-d5c0b89a2732.png">

---

In addition, this PR also:

- Fixes #26348
- Updates documentation to make it more clear what approach to take for new and existing ESLint configurations
2021-08-04 21:53:15 +00:00

67 lines
1.9 KiB
TypeScript

import { promises as fs } from 'fs'
import chalk from 'chalk'
import os from 'os'
import path from 'path'
import * as CommentJson from 'next/dist/compiled/comment-json'
import { ConfigAvailable } from './hasEslintConfiguration'
import * as Log from '../../build/output/log'
export async function writeDefaultConfig(
baseDir: string,
{ exists, emptyEslintrc, emptyPkgJsonConfig }: ConfigAvailable,
selectedConfig: any,
eslintrcFile: string | null,
pkgJsonPath: string | null,
packageJsonConfig: { eslintConfig: any } | null
) {
if (!exists && emptyEslintrc && eslintrcFile) {
const ext = path.extname(eslintrcFile)
let newFileContent
if (ext === '.yaml' || ext === '.yml') {
newFileContent = "extends: 'next'"
} else {
newFileContent = CommentJson.stringify(selectedConfig, null, 2)
if (ext === '.js') {
newFileContent = 'module.exports = ' + newFileContent
}
}
await fs.writeFile(eslintrcFile, newFileContent + os.EOL)
Log.info(
`We detected an empty ESLint configuration file (${chalk.bold(
path.basename(eslintrcFile)
)}) and updated it for you!`
)
} else if (!exists && emptyPkgJsonConfig && packageJsonConfig) {
packageJsonConfig.eslintConfig = selectedConfig
if (pkgJsonPath)
await fs.writeFile(
pkgJsonPath,
CommentJson.stringify(packageJsonConfig, null, 2) + os.EOL
)
Log.info(
`We detected an empty ${chalk.bold(
'eslintConfig'
)} field in package.json and updated it for you!`
)
} else if (!exists) {
await fs.writeFile(
path.join(baseDir, '.eslintrc.json'),
CommentJson.stringify(selectedConfig, null, 2) + os.EOL
)
console.log(
chalk.green(
`We created the ${chalk.bold(
'.eslintrc.json'
)} file for you and included your selected configuration.`
)
)
}
}