eslint、prettier、semistandard、standard 和 xo 都是用于提升 JavaScript 项目代码质量和一致性的工具,但它们在设计哲学、功能边界和配置灵活性上存在显著差异。eslint 是一个高度可配置的静态分析工具,专注于发现潜在错误和强制编码规范;prettier 则是一个“有主见”的代码格式化器,通过自动重写代码结构来消除风格争议;而 semistandard、standard 和 xo 均属于“零配置”风格的 lint 工具,它们在 eslint 基础上封装了预设规则,以减少团队配置成本。这些工具常被组合使用(如 eslint + prettier),也可独立运行,选择取决于团队对控制粒度、自动化程度和维护负担的权衡。
在现代前端工程中,保持代码一致性和避免常见错误是团队协作的基础。eslint、prettier、semistandard、standard 和 xo 是五种主流工具,但它们解决的问题层次不同 —— 有的专注逻辑错误检测,有的只管代码排版,有的则试图“全包”。本文从真实开发场景出发,深入比较它们的核心机制、适用边界和组合策略。
首先明确:eslint 是 linter(静态分析器),prettier 是 formatter(格式化器),其余三者是基于前两者封装的“一体化”方案。
eslint:检查代码中的潜在 bug、未使用变量、类型不匹配等,规则可开启/关闭/自定义。prettier:只关心代码怎么“看起来”,比如括号位置、换行、空格,输出完全由算法决定,不提供选项。standard / semistandard / xo:内部调用 eslint(有时也集成 prettier),提供一套固定规则,目标是“开箱即用”。💡 关键区别:linter 能发现
const x = 1; console.log(y);这样的未声明变量错误,formatter 只会把这段代码缩进对齐,但不会报错。
standard 和 semistandard:完全不可配置这两个工具坚持“约定优于配置”理念,不允许任何规则覆盖。你只能接受它的全部规则,或不用。
// standard 规则示例:必须用单引号、不能有分号、2 空格缩进
const greeting = 'hello'; // ✅
const message = "world"; // ❌ 报错:字符串必须用单引号
console.log(greeting) // ❌ 报错:缺少分号(standard 要求无分号,但此处因换行被解析为两个语句)
semistandard 与 standard 几乎相同,唯一区别是允许(甚至要求)使用分号:
// semistandard 规则示例
const greeting = 'hello'; // ✅ 必须加分号
const message = "world"; // ❌ 同样报错:必须用单引号
📌 注意:
semistandard的 GitHub 仓库近年更新极少,官方文档也未明确说明维护状态,新项目应谨慎评估。
xo:有限配置 + 现代默认值xo 在“零配置”和“可定制”之间取得平衡。它提供合理的现代 JavaScript 默认规则(如支持 top-level await、ES2023 语法),允许通过 package.json 或 xo 字段局部覆盖规则。
// package.json
{
"xo": {
"semicolon": false,
"space": true,
"rules": {
"unicorn/no-array-for-each": "off"
}
}
}
默认情况下,xo 会自动格式化代码(内部调用 prettier),并修复可自动修正的问题(如未使用变量)。
eslint:完全可编程eslint 的核心优势是细粒度控制。你可以逐条启用/禁用规则,设置错误级别(error/warn/off),甚至编写自定义规则。
// .eslintrc.js
module.exports = {
extends: ['eslint:recommended', 'plugin:react/recommended'],
rules: {
'no-console': 'warn',
'react/prop-types': 'off'
},
parserOptions: { ecmaVersion: 2022 }
};
这种灵活性使其成为大型项目的首选,但也意味着更高的初始配置成本。
prettier:格式即法律prettier 的哲学是“不要讨论格式,我来决定”。它只提供极少数选项(如 printWidth、tabWidth),一旦运行,代码结构会被强制重写。
// 输入代码
function greet( name, age ) { return 'Hello ' + name + ', you are ' + age + ' years old.'; }
// prettier 输出(默认配置)
function greet(name, age) {
return 'Hello ' + name + ', you are ' + age + ' years old.';
}
你无法配置“函数参数是否换行”或“对象字面量是否多行”——算法根据 printWidth 自动判断。
在专业项目中,eslint + prettier 是事实标准组合。原因很简单:
eslint 负责逻辑正确性(如变量作用域、API 使用)prettier 负责视觉一致性(如缩进、换行)但两者可能冲突(例如 eslint 要求对象末尾逗号,prettier 有自己的逗号规则)。解决方案是使用 eslint-config-prettier 关闭所有与 prettier 冲突的 eslint 规则:
// .eslintrc.js
module.exports = {
extends: [
'eslint:recommended',
'prettier' // 必须放在最后,以覆盖其他配置中的格式规则
],
plugins: ['prettier'],
rules: {
'prettier/prettier': 'error' // 将 prettier 错误作为 eslint 错误报告
}
};
而 standard、semistandard、xo 本质上是对这种组合的“封装简化版”:
standard = eslint (固定规则集) + 内置格式建议(但非 prettier)xo = eslint + prettier + 现代默认配置所有工具都支持 --fix 自动修复部分问题,但能力范围不同:
| 工具 | 可修复问题类型 | 示例 |
|---|---|---|
eslint | 规则允许的逻辑/风格问题 | 添加缺失分号、替换 var 为 let |
prettier | 所有格式问题 | 重排换行、调整缩进、统一引号 |
standard | 有限修复(基于其 eslint 规则) | 移除分号、修正缩进 |
semistandard | 同 standard,但保留分号 | 添加分号、修正缩进 |
xo | eslint 问题 + prettier 格式 | 同 eslint + prettier 组合 |
# 各工具的修复命令
npx eslint --fix src/
npx prettier --write src/
npx standard --fix
npx semistandard --fix
npx xo --fix
⚠️ 注意:
standard和semistandard的修复能力较弱,对于复杂格式问题(如长函数参数换行)可能无法处理,而prettier或xo能完美解决。
eslint:通过 @typescript-eslint/parser 和插件支持 TS,需手动配置。prettier:原生支持 TS、JSX、Flow 等,无需额外配置。standard / semistandard:不支持 TypeScript,仅限 JavaScript。xo:原生支持 TypeScript,默认启用 TS 解析,只需安装 typescript 依赖。// TypeScript 示例(xo 可直接处理)
const greet = (name: string): string => `Hello ${name}`;
若项目使用 TypeScript,standard 和 semistandard 应直接排除。
所有工具均有主流编辑器插件(VS Code、WebStorm 等),但体验略有差异:
eslint + prettier:需分别安装插件,配置保存时自动修复(需设置 editor.codeActionsOnSave)。xo:提供专用 VS Code 插件 xo,保存时自动格式化和修复,开箱即用。standard / semistandard:有对应插件,但因规则不可调,错误提示无法忽略特定行(除非用 // standard-disable-next-line 注释,但支持有限)。根据项目需求快速选择:
项目使用 TypeScript?
standard/semistandard,考虑 xo 或 eslint+prettier团队能否接受完全不可配置的规则?
standard(无分号)或 semistandard(有分号)xo(有限配置)或 eslint+prettier(完全控制)需要严格控制代码质量(如禁止特定 API)?
eslint(可自定义规则)xo 可能满足需求极度厌恶格式讨论,追求自动化?
prettier(单独或通过 xo)是必选项eslint:适合需要精细控制、长期维护的大型项目,学习曲线陡峭但回报高。prettier:应作为格式化基础组件,几乎适用于所有项目,单独使用或与 linter 配合。standard / semistandard:仅推荐给小型 JS 项目且团队完全认同其规则;semistandard 维护状态存疑,新项目慎用。xo:现代 JS/TS 项目的优秀“中间选项”,平衡了开箱即用和必要灵活性,特别适合中等规模团队。最终,工具只是手段。清晰的代码、可维护的架构、高效的协作流程,远比选择哪个 linter 更重要。但在达成这些目标的路上,选对工具能少走很多弯路。
选择 eslint 如果你需要对代码质量规则进行精细控制,例如自定义错误级别、集成特定框架(如 React、TypeScript)的插件,或在大型项目中逐步推行规范。它适合需要长期演进、多人协作且对代码健壮性要求高的工程,但需投入时间配置和维护规则集。
选择 prettier 如果你希望彻底消除团队在代码格式(如缩进、引号、换行)上的争论,并通过自动化格式化提升一致性。它不检查逻辑错误,仅处理代码外观,因此通常与 eslint 配合使用。适合追求开发效率、减少 PR 中格式讨论的团队。
选择 semistandard 如果你偏好 Standard 规范但希望保留分号。它是 standard 的一个分支,规则几乎完全相同,仅在是否强制省略分号这一点上不同。适合已有使用分号习惯、又想快速采用一套成熟规范的团队,但需注意其社区活跃度较低。
选择 standard 如果你希望零配置地启用一套广泛接受的 JavaScript 风格(如无分号、双引号转单引号、2 空格缩进),并愿意接受其不可定制的限制。它内置了基础 lint 规则和格式建议,适合小型项目或希望快速启动的原型开发,但在大型项目中可能因缺乏灵活性而受限。
选择 xo 如果你需要比 standard 更现代、更严格的默认规则(如支持 ES2023、TypeScript、自动修复),同时仍保持低配置开销。它基于 eslint 和 prettier 构建,提供合理的默认值并允许局部覆盖,适合追求现代化 JavaScript 实践且不愿从头配置 linting 的中等规模团队。
Website | Configure ESLint | Rules | Contribute to ESLint | Report Bugs | Code of Conduct | X | Discord | Mastodon | Bluesky
ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code. In many ways, it is similar to JSLint and JSHint with a few exceptions:
To use ESLint, you must have Node.js (^20.19.0, ^22.13.0, or >=24) installed and built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
If you use ESLint's TypeScript type definitions, TypeScript 5.3 or later is required.
You can install and configure ESLint using this command:
npm init @eslint/config@latest
After that, you can run ESLint on any file or directory like this:
npx eslint yourfile.js
To use ESLint with pnpm, we recommend setting up a .npmrc file with at least the following settings:
auto-install-peers=true
node-linker=hoisted
This ensures that pnpm installs dependencies in a way that is more compatible with npm and is less likely to produce errors.
You can configure rules in your eslint.config.js files as in this example:
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.js", "**/*.cjs", "**/*.mjs"],
rules: {
"prefer-const": "warn",
"no-constant-binary-expression": "error",
},
},
]);
The names "prefer-const" and "no-constant-binary-expression" are the names of rules in ESLint. The first value is the error level of the rule and can be one of these values:
"off" or 0 - turn the rule off"warn" or 1 - turn the rule on as a warning (doesn't affect exit code)"error" or 2 - turn the rule on as an error (exit code will be 1)The three error levels allow you fine-grained control over how ESLint applies rules (for more configuration options and details, see the configuration docs).
The ESLint team provides ongoing support for the current version and six months of limited support for the previous version. Limited support includes critical bug fixes, security issues, and compatibility issues only.
ESLint offers commercial support for both current and previous versions through our partners, Tidelift and HeroDevs.
See Version Support for more details.
ESLint adheres to the OpenJS Foundation Code of Conduct.
Before filing an issue, please be sure to read the guidelines for what you're reporting:
Yes, ESLint natively supports parsing JSX syntax (this must be enabled in configuration). Please note that supporting JSX syntax is not the same as supporting React. React applies specific semantics to JSX syntax that ESLint doesn't recognize. We recommend using eslint-plugin-react if you are using React and want React semantics.
No, ESLint and Prettier have different jobs: ESLint is a linter (looking for problematic patterns) and Prettier is a code formatter. Using both tools is common, refer to Prettier's documentation to learn how to configure them to work well with each other.
ESLint has full support for ECMAScript 3, 5, and every year from 2015 up until the most recent stage 4 specification (the default). You can set your desired ECMAScript syntax and other settings (like global variables) through configuration.
ESLint's parser only officially supports the latest final ECMAScript standard. We will make changes to core rules in order to avoid crashes on stage 3 ECMAScript syntax proposals (as long as they are implemented using the correct experimental ESTree syntax). We may make changes to core rules to better work with language extensions (such as JSX, Flow, and TypeScript) on a case-by-case basis.
In other cases (including if rules need to warn on more or fewer cases due to new syntax, rather than just not crashing), we recommend you use other parsers and/or rule plugins. If you are using Babel, you can use @babel/eslint-parser and @babel/eslint-plugin to use any option available in Babel.
Once a language feature has been adopted into the ECMAScript standard (stage 4 according to the TC39 process), we will accept issues and pull requests related to the new feature, subject to our contributing guidelines. Until then, please use the appropriate parser and plugin(s) for your experimental feature.
ESLint updates the supported Node.js versions with each major release of ESLint. At that time, ESLint's supported Node.js versions are updated to be:
ESLint is also expected to work with Node.js versions released after the Node.js Current release.
Refer to the Quick Start Guide for the officially supported Node.js versions for a given ESLint release.
Open a discussion or stop by our Discord server.
Lock files like package-lock.json are helpful for deployed applications. They ensure that dependencies are consistent between environments and across deployments.
Packages like eslint that get published to the npm registry do not include lock files. npm install eslint as a user will respect version constraints in ESLint's package.json. ESLint and its dependencies will be included in the user's lock file if one exists, but ESLint's own lock file would not be used.
We intentionally don't lock dependency versions so that we have the latest compatible dependency versions in development and CI that our users get when installing ESLint in a project.
The Twilio blog has a deeper dive to learn more.
We have scheduled releases every two weeks on Friday or Saturday. You can follow a release issue for updates about the scheduling of any particular release.
ESLint takes security seriously. We work hard to ensure that ESLint is safe for everyone and that security issues are addressed quickly and responsibly. Read the full security policy.
ESLint follows semantic versioning. However, due to the nature of ESLint as a code quality tool, it's not always clear when a minor or major version bump occurs. To help clarify this for everyone, we've defined the following semantic versioning policy for ESLint:
eslint:recommended is updated and will result in strictly fewer linting errors (e.g., rule removals).eslint:recommended is updated and may result in new linting errors (e.g., rule additions, most rule option updates).According to our policy, any minor update may report more linting errors than the previous release (ex: from a bug fix). As such, we recommend using the tilde (~) in package.json e.g. "eslint": "~3.1.0" to guarantee the results of your builds.
Since ESLint is a CommonJS package, there are restrictions on which ESM-only packages can be used as dependencies.
Packages that are controlled by the ESLint team and have no external dependencies can be safely loaded synchronously using require(esm) and therefore used in any contexts.
For external packages, we don't use require(esm) because a package could add a top-level await and thus break ESLint. We can use an external ESM-only package only in case it is needed only in asynchronous code, in which case it can be loaded using dynamic import().
These policies don't apply to packages intended for our own usage only, such as eslint-config-eslint.
MIT License
Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
These folks keep the project moving and are resources for help.
The people who manage releases, review feature requests, and meet regularly to ensure ESLint is properly maintained.
![]() Nicholas C. Zakas |
![]() Francesco Trotta |
![]() Milos Djermanovic |
The people who review and implement new features.
![]() 唯然 |
![]() Nitin Kumar |
The people who review and fix bugs and help triage issues.
![]() fnx |
![]() Josh Goldberg ✨ |
![]() Sweta Tanwar |
![]() Tanuj Kanti |
![]() lumir |
Pixel998 |
Team members who focus specifically on eslint.org
![]() Amaresh S M |
![]() Harish |
![]() Percy Ma |
The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. Become a Sponsor to get your logo on our READMEs and website.