A CLI tool for code quality.
😎 = 🇹 + 💃 + 📏
经过多年实践,我们发现衡量现代 JavaScript 工程的代码质量,主要有 3 个方面:
Formatting
之外的任何地方,例如重复定义变量、switch 不带 break、圈复杂度等。Note:
类型安全
和Linting
的关注点可能存在一定的交集,例如:“函数入参数量对不上”,既可能被类型安全的工具(如 TypeScript)检测到,也可能被 Linter(如 ESLint)检测出来。
Note:
Formatting
和Linting
的关注点,原则上不存在交集。早期 ESLint 也被用于格式化,但是近年来,Linter
和Formatter
分开已经被社区越来越广泛采纳,例如ESLint 废弃 Formatting Rules、Deno 和 Biome 均把Linter
和Formatter
分开。有些人会将后两者
Formatting
和Linting
合并起来一并处理,例如 @antfu/eslint-config。我们强烈不建议这样做。首先是因为它们目的不一样,专业的事情应该交给专业的工具。其次是它们的造成心智负担不同,Review 代码时,我们往往不需要关注 Formatting 的改动,但是我们必须要仔细检查确认 Linting 的改动,因为 Formatting 的改动一般是安全的,但是 Linting 的改动可存在错误的修复。
这 3 个方面也是更先进的运行时 Deno 所内置的功能,Node 并没有内置支持,取而代之的是社区里百花齐放的工具:TypeScript、Flow、Biome、ESLint、oxc-lint、Prettier、dprint。这些工具用在 Node 项目中存在 3 个非常影响开发体验的问题:
package.json
里)到处拉屎。一来不美观简洁,二来增加理解成本。每个 Node 项目可能工具统一但配置不统一,进一步导致开发体验不一致。为了解决上述问题,现在有非常多教程文章讲解 TypeScript + Prettier + ESLint 的配置和实践,这些文章教程能缓解一部分问题,但仍然将杂乱的工具链和繁琐的配置暴露给用户。这不是我们的目标,我们的目标是提供一个统一的工具屏蔽这些复杂的实践细节,给用户带来简单一致、开箱即用的良好开发体验。
Based on the philosophy outlined above, this tool offers the following features:
tsconfig
settings and type patches to bolster the type safety of TypeScript projects. It is also compatible with pure JavaScript projects.package.json
files.We place a high value on Development Experience
(DX).
prettier
, eslint
, lint-staged
or husky
.To quick start, run command below to check formatting and linting style in your project.
npx fenge
We recommend installing it as one of devDependencies
in your project.
npm i -D fenge
Each of the following usages is optional. You can choose the ones that best fit your needs.
tsconfig.json
Config tsconfig.json
file in your project root.
{
"extends": "fenge/tsconfig"
}
Config tsconfig.build.json
file in sub-package or project root.
{
"extends": "./tsconfig.json",
"include": ["src"],
"exclude": ["**/*.spec.ts", "**/*.test.ts"]
}
Build your project by executing tsc -p ./tsconfig.build.json
. Type-check your project by executing tsc -p ./tsconfig.build.json --noEmit
.
For more beat practices, please refer to @fenge/tsconfig.
Add a triple-slash-directive /// <reference types="fenge/types" />
at the top of the ts file that serves as the entry point for your application or package. This will make the entire project more type-safe.
Application/Package Entry Point (eg: src/main.ts
or src/app.ts
)
/// <reference types="fenge/types" />
import foo from "./foo";
Other File (eg: src/other-file.ts
)
console.log(JSON.parse('{"foo":"foo"}').bar);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ❌ Object is of type 'unknown'.
Here are some main commands to format or lint code.
# Check project's formatting problems only
$ fenge format
# Check project's formatting problems and apply updates
$ fenge format -u
# Check project's linting problems only
$ fenge lint
# Check project's linting problems and apply updates
$ fenge lint -u
# Check both formatting and linting problems
$ fenge
# Check both formatting and linting problems and apply updates
$ fenge -u
This tool does not require a configuration file. However, you can add a fenge.config.js
file to customize formatting and linting rules. This file should export an object with two properties:
format
: Accept a Prettier Config.lint
: Accept a ESLint Flat Config.export default {
format: {
semi: false,
singleQuote: true,
},
lint: [
{
files: ["**/*.{js,cjs,mjs,jsx}", "**/*.{ts,cts,mts,tsx}"],
rules: {
"no-unused-vars": "error",
},
},
],
};
Usually, we recommend reusing the built-in configurations rather than writing them from scratch.
// @ts-check
// See https://www.npmjs.com/package/@fenge/eslint-config for eslint-config detail usage
import { Builder } from "fenge/eslint-config";
// See https://www.npmjs.com/package/@fenge/prettier-config for prettier-config detail usage
import prettierConfig from "fenge/prettier-config";
export default {
format: {
...prettierConfig,
// add config below to override the default behavior
semi: false,
},
lint: new Builder()
.enablePackagejson({
pick: ["packagejson/top-types"], // only these rules will work for package.json files
})
.enableJavascript({
omit: ["no-var"], // these rules will not work for js files
})
.enableTypescript({
project: "tsconfig.json", // tsconfig.json path
extend: {
// apply additional rules for ts files
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/consistent-type-assertions": [
"error",
{ assertionStyle: "never" },
],
"@typescript-eslint/no-non-null-assertion": "error",
},
})
.toConfig(),
};
You can even install and use other third-party eslint-config, like @sxzz/eslint-config.
Executing fenge install
will write a pre-commit
file to the ${PROJECT_ROOT}/.git/hooks
folder. After editing package.json -> scripts -> prepare
script and executing it once, each commit (via Git) will trigger a code style check for the committed files.
{
"scripts": {
"prepare": "fenge install"
}
}
npm run prepare
corepack enable
.pnpm install
.pnpm style:update
to develop.Give a ⭐️ if this project helped you!
MIT