next.js 为 NextJs 设置 ESLint

next.js Setting up ESLint for NextJs

我已经使用 "npx create-next-app" 创建了基本的 next.js 应用程序,并且创建了 .eslintrc.json 文件来添加 eslint rules.but 它不是 working.how 添加 linting 规则nextjs 配置

{
    "env": {
        "browser": true,
        "es6": true
    },
    "extends": [
        "standard"
    ],
    "globals": {
        "Atomics": "readonly",
        "SharedArrayBuffer": "readonly",
        "React": "writable"
    },
    "parserOptions": {
        "ecmaFeatures": {
            "jsx": true
        },
        "ecmaVersion": 2018,
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "react/react-in-jsx-scope": "off"
    }
}

我试过这个解决方案 - https://medium.com/@joelmasters/setting-up-eslint-for-nextjs-37163d4cabaa

您需要安装所需的 npm 模块。

使用 Npm:

npm i -D babel-eslint eslint-config-airbnb eslint eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks

使用纱线:

yarn add -D babel-eslint eslint-config-airbnb eslint eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks

这是相关文章

https://medium.com/@melih193/next-js-eslint-setup-tutorial-for-airbnb-config-c2b04183a92a

更新

NextJS 现在有将 eslint 添加到项目的官方指南:https://nextjs.org/docs/basic-features/eslint 另外你需要安装 ESLint extension.

此外,如果您正在寻找支持打字稿的 ESLint:https://gourav.io/blog/nextjs-cheatsheet

旧答案:

安装 ESLint

npm i eslint --save-dev

安装 ESLint 插件:

npx install-peerdeps --dev eslint-config-airbnb

以上 single command 将安装 6 个插件:eslint-config-airbnbeslint-plugin-importeslint-plugin-reacteslint-plugin-react-hookseslint-plugin-jsx-a11y。您也可以单独安装这些插件。

安装babel eslint

npm i -D babel-eslint

安装 prettier 插件(可选,这样 prettier 就不会搞乱 linting)

 npm i -D eslint-config-prettier eslint-plugin-prettier

您的“devDependencies”应该如下所示:

"devDependencies": {
    "babel-eslint": "^10.1.0",
    "eslint": "^6.8.0",
    "eslint-config-airbnb": "^18.1.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-import": "^2.20.2",
    "eslint-plugin-jsx-a11y": "^6.2.3",
    "eslint-plugin-prettier": "^3.1.3",
    "eslint-plugin-react": "^7.20.0",
    "eslint-plugin-react-hooks": "^2.5.1"
  }

现在,在项目的根目录下创建一个文件 .eslintrc.json。 粘贴到配置下方:

{
  "env": {
    "browser": true,
    "commonjs": true,
    "es6": true,
    "node": true
  },
  "parser": "babel-eslint",
  "extends": [
    "eslint:recommended",
    "airbnb",
    "airbnb/hooks",
    "plugin:react/recommended",
    "plugin:import/errors",
    "plugin:import/warnings",
    "plugin:jsx-a11y/recommended",
    // "plugin:react-hooks/recommended",
    // always put prettier at last
    "prettier"
  ],
  "globals": {
    "Atomics": "readonly",
    "SharedArrayBuffer": "readonly"
  },
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true // enable linting for jsx files
    },
    "ecmaVersion": 11,
    "sourceType": "module"
  },
  "settings": {
    "react": {
      "version": "detect"
    }
  },
  "plugins": ["react", "react-hooks"],
  "rules": {
    // NextJs specific fix: suppress errors for missing 'import React' in files for nextjs
    "react/react-in-jsx-scope": "off",
   // NextJs specific fix: allow jsx syntax in js files
    "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], //should add ".ts" if typescript project
    "react/display-name": 1
  }
}

此外,为 VSCode 安装 ESLint extension

重新加载 VSCode window 一次以获得正确的 linting

ESLint 将自动开始检测 *.js*.jsx 文件中的 errors/warnings。如果不是这种情况,那么要么您的项目没有 linting 错误,要么 ESLint 设置不正确。 测试 linting 是否有效 运行 终端中带有文件夹路径的 eslint 命令,即 eslint pages/** 和通知输出。

要禁用某些 files/folders 的 linting,您可以在项目的根目录下创建一个 .eslintignore

.eslintignore:

# don't ever lint node_modules
node_modules
# don't lint build output (make sure it's set to your correct build folder name)
dist
# don't lint nyc coverage output
coverage

最后,您还可以将 linting 添加到 package.json 中的 scripts 作为 build/deploy 过程的一部分:

"scripts": {
    "lint": "eslint ./components/** ./pages/** -c .eslintrc.json --ext js,jsx",
    "lint-fix": "eslint ./components/** ./pages/** -c .eslintrc.json --fix --ext js,jsx",
}

查看 NextJS Typescript 项目的当前 ESLint 配置:https://github.com/GorvGoyl/Personal-Site-Gourav.io/blob/main/.eslintrc.js

官方树内示例

作为 ,在 Next.js 11.

周围添加了一些更好的集成

虽然在以下位置有文档:https://nextjs.org/docs/basic-features/eslint 作为一个 eslint 新手,我只是不明白我应该做什么,所以我只是查看示例/并找到了一些实际的工作代码:

examples/with-eslint

https://github.com/vercel/next.js/tree/v12.0.7/examples/with-eslint

最小的 eslint 示例。

设置包含:

package.json

{
  "name": "with-eslint",
  "version": "1.0.0",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "license": "MIT",
  "dependencies": {
    "next": "12.0.7",
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "devDependencies": {
    "eslint": "^7.24.0",
    "eslint-config-next": "12.0.7"
  }
}

.eslintrc

{
  "extends": "next",
  "root": true
}

pages/index.js

const Home = () => (
  <div>
    <script src="https://fake-script.com" />
    <p>Home</p>
  </div>
)

export default Home

例如做:

cd examples/with-eslint
npm install
npm run lint

给出所需的错误:

3:5 Warning: External synchronous scripts are forbidden. See: https://nextjs.org/docs/messages/no-sync-scripts. @next/next/no-sync-scripts

我们可以稍微修改 pages/index.js 以添加更多我们可能希望失败的案例:

import React from 'react'

const Home = () => {
  let s = 'abc'
  s = "abc"
  let unused
  if (false) {
    React.useEffect(() => 1)
  }
  return (
    <div>
      <script src="https://fake-script.com" />
      <p>Home</p>
    </div>
  )
}

export default Home

结果是:

examples/with-typescript-eslint-jest

https://github.com/vercel/next.js/tree/v12.0.7/examples/with-typescript-eslint-jest

也用打字稿举例。

请注意,此示例不能 运行 在树中,否则会失败:

ESLint couldn't find the plugin "eslint-plugin-jest".

必须从 repo 顶层获取:

The plugin "eslint-plugin-jest" was referenced from the config file in "../../.eslintrc.json#overrides[0]".

你必须先把它复制到外面的某个地方,比如:

cp -rv examples/with-typescript-eslint-jest /tmp
cd /tmp/with-typescript-eslint-jest

但我认为这个示例有点过时,因为它没有使用

  "extends": "next",

预设。

我推荐的 Next 12 typescript + 更漂亮的设置

由于树内“examples/with-typescript-eslint-jest”看起来不是很新,这里有一个版本应该是(不开玩笑):

package.json

{
  "name": "with-eslint",
  "version": "1.0.0",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "format": "prettier --ignore-path .gitignore --write .",
    "type-check": "tsc"
  },
  "license": "MIT",
  "dependencies": {
    "install": "0.13.0",
    "next": "12.0.7",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  },
  "devDependencies": {
    "@types/node": "12.12.21",
    "@types/react": "17.0.2",
    "@types/react-dom": "17.0.1",
    "eslint": "8.5.0",
    "eslint-config-next": "12.0.7",
    "eslint-config-prettier": "7.2.0",
    "eslint-plugin-prettier": "4.0.0",
    "prettier": "2.5.1",
    "typescript": "4.5.4"
  },
  "prettier": {
    "printWidth": 80,
    "semi": false,
    "singleQuote": true
  }
}

.eslintrc.json

{
  "extends": ["eslint:recommended", "next", "prettier"],
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": "error"
  }
}

tsconfig.json(当您 运行 npm run dev 时由 Next 自动生成)

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

.gitignore

# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# vercel
.vercel

# typescript
*.tsbuildinfo

pages/index.tsx

import React from 'react'

const Home = () => {
  let n: number
  let s = 'abc'
  s = "abc"
  let unused
  if (false) {
    React.useEffect(() => 1)
  }
  return (
    <div>
      <script src="https://fake-script.com" />
      <p>Home</p>
    </div>
  )
}

export default Home

使用此设置执行:

npm run lint

如我们所愿捕获所有问题:

4:7  Error: 'n' is defined but never used.  no-unused-vars
6:3  Error: 's' is assigned a value but never used.  no-unused-vars
6:7  Error: Replace `"abc"` with `'abc'`  prettier/prettier
7:7  Error: 'unused' is defined but never used.  no-unused-vars
8:7  Error: Unexpected constant condition.  no-constant-condition
9:5  Error: React Hook "React.useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.  react-hooks/rules-of-hooks
13:7  Warning: External synchronous scripts are forbidden. See: https://nextjs.org/docs/messages/no-sync-scripts.  @next/next/no-sync-scripts

更漂亮的错误可以通过自动格式化自动修复:

npm run format

自动为我们打补丁:

--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -3,7 +3,7 @@ import React from 'react'
 const Home = () => {
   let n: number
   let s = 'abc'
-  s = "abc"
+  s = 'abc'
   let unused
   if (false) {

运行:

npm run type-check

捕捉到类型错误:

pages/index.tsx:9:27 - error TS2322: Type 'number' is not assignable to type 'void | Destructor'.

9     React.useEffect(() => 1)

npm run lintnpm run type-check 都是 npm run build 自动 运行。

默认情况下,Lint 仅在 pages/components/lib/ 上启用

如在以下位置所述:https://nextjs.org/docs/basic-features/eslint#linting-custom-directories-and-files

要在项目的任何地方启用它:

module.exports = {
  eslint: {
    dirs: ['.'],
  },
}