进阶 04 规范代码:Linter、Prettier、EditorConfig
任何语言都需要强调编码风格的一致性。以相同的风格编写代码在团队开发中是至关重要的,这样才能更利于其他人阅读和维护。
团队多人协同开发项目的一个很大的问题是:无可避免地会出现每个开发者编码习惯不同、代码风格迥异,为了代码高可用、可维护性, 如何从项目管理上尽量统一和规范代码呢?
不要花费过多时间和精力讨论怎么样的风格是最好的——这通常也不会有结果。统一和规范代码的关键是怎么将规范落实。文档约定,靠开发者自我修养,这种方法是无法确保整个项目代码的规范化。在如今工程化开发的环境下,我们完全可以借助一些工具实现自动检查,规范代码的输出,确保提交到仓库的是高质量代码。
本文主要讲述规范代码的几个工具:ESlint、StyleLint、Prettier、EditorConfig,以及它们之间的冲突问题 。文章最后是一个 Git Hook 集成这些工具的示例,讲述了 husky(新版本) + lint-staged 用法 。
ESLint 是一个开源的 JavaScript 代码检查工具,由 Nicholas C. Zakas 于2013年6月创建。代码检查是一种静态的分析,常用于寻找有问题的模式或者代码,并且不依赖于具体的编码风格。对大多数编程语言来说都会有代码检查,一般来说编译程序会内置检查工具。
ESLint 的初衷是为了让程序员可以创建自己的检测规则。ESLint 的所有规则都被设计成可插入的。ESLint 的默认规则与其他的插件并没有什么区别,规则本身和测试可以依赖于同样的模式。为了便于人们使用,ESLint 内置了一些规则,当然,你可以在使用过程中自定义规则。
ESLint 的目标是保证代码的一致性和避免错误,是使用 Node.js 编写。
安装及配置
安装:npm i eslint -D
。
配置: 命令行运行 eslint --init
,在当前目录下生成一个.eslintrc.*
文件。
Eslint 使用 JavaScript、JSON 或者 YAML 文件为整个目录(处理你的主目录)和它的子目录指定配置信息。如果同一个目录下有多个配置文件,ESLint 只会使用一个,会按照以下优先级(从高到低)。
.eslintrc.js: JavaScript 文件;
.eslintrc.yaml > .eslintrc.yml: YAML 是专门用来写配置文件的语言,非常简洁和强大,远比 JSON 方便;
.eslintrc.json: 允许 JavaScript 风格的注释;
.eslintrc(已弃用): 可以是 JSON ,也可以是 YAML;
package.json: 在
package.json
文件的eslintConfig
属性定义配置。
默认情况下,ESLint 会在所有父级目录里寻找配置文件,一直到根目录。如果想要将 ESLint 限制到一个特定的项目,在你项目根目录下的 package.json
文件的 eslintConfig
字段或者 .eslintrc.*
配置文件中设置 "root": true
。ESLint 一旦发现配置文件中有 "root": true
,它会直接去根目录寻找配置文件,不会再在各级父目录中寻找。
完整的配置层次结构,从最高优先级到最低的优先级,如下:
行内配置:
/*eslint-disable*/
和/*eslint-enable*/
>/*global*/
>/*eslint*/
>/*eslint-env*/
命令行选项(或 CLIEngine 等价物):
--global
>--rule
>--env
>-c
、--config
项目级配置:与要检测的文件在同一目录下的
.eslintrc.*
或package.json
文件;如果没有,再继续在父级目录寻找.eslintrc
或package.json
文件,直到根目录(包括根目录)或直到发现一个有"root": true
的配置。如果不是(1)到(3)中的任何一种情况,退回到
~/.eslintrc
中自定义的默认配置。
使用方式
命令行: eslint [options] [file|dir|glob]*
。
--ext: 查找指定的文件扩展名。默认以
.js
作为唯一性文件扩展名。-c, --config: 指定一个额外的配置文件。
--rulesdir: 指定另一个加载规则文件的目录。
--ignore-path: 指定一个文件作为
.eslintignore
。默认情况下,ESLint 在当前工作目录下查找.eslintignore
。--quiet: 禁止报告警告。
-o, --output-file: 将报告写到一个文件。
-f, --format: 指定了控制台的输出格式。默认
stylish
。--fix: 指示 ESLint 试图修复尽可能多的问题。修复只针对实际文件本身,而且剩下的未修复的问题才会输出。不是所有的问题都能使用这个选项进行修复。
集成编辑器:集成 Visual Studio Code、Sublime Text 3、Atom 等编辑器使用。
构建工具:Webpack、Gulp、Grunt、Rollup 等构建工具中使用。
Git Hooks: 比如,git 的钩子函数 Precommit、pre-commit。
本人在用的一份 Vue 项目的 .eslintrc.js 配置
root: 为
true
表示停止寻找配置文件,从根目录下查找package.json
文件的配置或者.eslintrc.*
配置文件。parser: 指定解析器,即将 Js 语句解析成语法树的插件。ESLint 默认使用 Espree (查看 Espree DEMO)作为其解析器,你可以在配置文件中指定一个不同的解析器,但该解析器需要符合一些要求,并且 ESLint 不会修复与其它解析器不兼容的相关 bug。
可以与 ESLint 兼容的解析器有:Esprima、Babel-ESLint、@typescript-eslint/parser。
parserOptions: 指定解析器选项。
注意: Vue 项目中,如果想为
.vue
文件的 script 使用单独的 parser 可以将parserOptions.parser
指定为想使用的 parser。ecmaVersion: 指定要使用的 ECMAScript 版本,默认设置为 3,5(默认)。可选版本号: 6(同2015)、7(同2016)、 8(同 2017)、9(同2018)、10 (同2019)。
**sourceType:**生成的 Js 的类型,默认 script,可先:module(如果你的代码是 ECMAScript 模块)。
ecmaFeatures: 表示你想使用的额外的语言特性。globalReturn 允许在全局作用域下使用 return 语句;impliedStrict 启用全局 strict mode (如果 ecmaVersion 是 5 或更高);jsx - 启用 JSX;experimentalObjectRestSpread - 启用实验性的属性。
processor: 指定处理器,从另一种文件中提取 JavaScript 代码,或者在预处理中转换 JavaScript 代码,然后让 ESLint 检测 JavaScript 代码。
env: 指定环境。一个环境定义了一组预定义的全局变量,可定义多个。点击查看 所有可用环境,一般常用的环境有:
browser: 浏览器环境中的全局变量;
node: Node.js 全局变量和 Node.js 作用域;
commonjs: CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码);
shared-node-browser: Node.js 和 Browser 通用全局变量。
es6: 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置
ecmaVersion
解析器选项为 6)。amd: 将
require()
和define()
定义为像 amd 一样的全局变量。
可以为特定的插件,指定环境:
globals: 指定自定义的全局变量。
writable
表示允许重写变量;readonly
表示不允许重写变量;off
表示禁用全局变量。由于历史原因,布尔值 false 和字符串值
readable
等价于readonly
。类似地,布尔值 true 和字符串值writeable
等价于writable
。但是,不建议使用旧值。plugins: 指定第三方插件。插件名称可以省略 eslint-plugin- 前缀。
rules: 添加检验规则(Eslint 规则列表)。如上:
no-unused-vars
规则的名称。值是错误级别,可以是字符串或数字:off | 0: 关闭规则;
**warn | 1:**开启规则,使用警告级别的错误(不会导致程序退出);
**error | 2:**开启规则,使用错误级别的错误(当被触发的时候,程序会退出)。
settings: 添加共享设置。它将值提供给每一个将被执行的规则。如果你想添加的自定义规则而且使它们可以访问到相同的信息,这将会很有用,并且很容易配置。
extends: 指定一个和多个可以继承的配置文件,值可以是一个表文件路径或配置名称的字符串,也可以是字符串数组(数组中的每个配置继承它前面的配置)。这些配置文件的规则可以被 rules 属性中的配置覆盖。
配置名称:
eslint:recommended
是 Eslint 推荐的配置名称,启用一系列核心规则 。这个推荐的规则只能在 ESLint 主要版本进行更新。还有一个
eslint:all
,启用当前安装的 ESLint 中所有的核心规则。不推荐使用,因为它可能在 ESLint 的任何版本进行更改。配置对象npm包:
eslint-config-standard
是一个可共享的配置,是一个 npm 包,它输出一个配置对象。可以省略包名的前缀eslint-config-
。插件配置: 一些插件也可以输出一个或多个命名的 配置,plugins 属性值 可以省略包名的前缀
eslint-plugin-
。plugin:vue/recommended
等同plugin:eslint-plugin-vue/recommended
。指定配置文件: 可以是到基本配置文件的绝对路径,也可以是相对路径。
overrides: 添加一些更精细的配置。比如: 如果同一个目录下的文件需要有不同的配置。
同一配置文件中,overrides 配置比其他常规配置具有更高的优先级。overrides 的配置几乎与 ESLint 的其他配置相同,除了 root。
eslint-config-* 和 eslint-plugin-* 的区别
eslint-config-*:
eslint-config-*
其实就是一个 常规的.eslintrc
文件。最终被 eslint 所识别的配置文件就是所有继承文件的属性合并,并且子类覆盖父类。eslint-plugin-*:
eslint-plugin-*
可以理解为只是一个定义规则的包。extends
引入的 plugins 在没有对应 config 文件的情况下,如果没有指定rules
,它的规则其实是不会发生校验的。
忽略代码
在文件中以注释形式,指定忽略的代码。
.eslintignore
创建一个 .eslintignore
文件告诉 ESLint 去忽略特定的文件和目录。.eslintignore
文件是一个纯文本文件,其中的每一行都是一个 glob 模式表明哪些路径应该忽略检测。
除了 .eslintignore
文件中的模式,ESLint 总是忽略 /node_modules/*
和 /bower_components/*
中的文件。
如果没有发现 .eslintignore
文件,也没有指定替代文件,ESLint 将在 package.json
文件中查找 eslintIgnore
属性,来检查要忽略的文件。
自定义规则的方式有两种:
创建一个
eslint-plugin-*
插件,在配置文件的extends
中引用。创建插件最简单的方式是使用 Yeoman generator。创建单个或多个规则,放在一个目录下,用命令行的
--rulesdir
参数指定规则目录。
以创建规则为例,按照以下步骤:
自定义规则,把所有的规则放在同一个目录下,如:
rules/lib
;一个规则的源文件输出一个对象,包含以下属性。
meta: 规则的元数据。type 表规则的类型、docs 表对规则的描述(在自定义的规则或插件中,可省略或包含部分属性)、messages 定义一些报错信息。
create: 返回一个对象。其中包含了 ESLint 在遍历 JavaScript 代码的抽象语法树 AST (ESTree 定义的 AST) 时,用来访问节点的方法。create 函数的参数 context 对象包含额外的功能,有利于规则完成他们的工作。顾名思义,context 对象包含与规则上下文相关的信息。
创建一个配置文件:在 rules 属性下指定你的规则 ID、错误级别,否则,规则将不会运行;
运行命令行:使用
--rulesdir
选项指定规则的目录。
一款与 Eslint 类型的插件,不过,是用于校验 Css 的,可以帮助你避免错误和强制约定一些代码风格。
安装及配置
安装:npm install stylelint stylelint-config-standard -D
。
配置: 在项目中加配置文件,查找和加载配置对象从当前工作目录开始,它将按以下顺序查找以下可能的源:
package.json
中的stylelint
属性;.stylelintrc
: 没有扩展名,可以是 JSON 或 YAML 格式。也可以添加文件扩展名以指定格式:.stylelintrc.json
、.stylelintrc.yaml
、.stylelintrc.yml
、.stylelintrc.js
。;stylelint.config.js
文件。
找到并解析其中一个后,搜索将停止并将使用该对象。可以使用 config
或 configFile
选项指定配置文件。
使用方式
命令行:
stylelint [options] [file|dir|glob]*
。Node 应用程序接口: 通过 Node 应用程序接口使用 stylelint 的一些示例和选项。
PostCSS 插件: 使用 PostCSS 插件的一些示例及选项。
辅助工具: 社区提供的编辑器(Sublime Text、Atom、Visual Studio Code 等)插件、构建工具(Gulp、Webpack 等)插件、以及其他工具(Git 中的构子)的汇总。
extends: 继承现有配置(无论您自己的配置还是第三方配置)。当一个配置继承另一个配置时,它从另一个配置的属性开始,然后添加并覆盖其中的内容。
extends 可以是数组,数组中的每个项都优先于前一项,而当前文件配置的优于所有数组中的配置文件。
extends 的值是一个 定位符(或者是一个定位符数组),最终通过
require()
加载,所以可以是任何适用于 Node 的require.resolve()
算法的格式。这意味着 定位符 可以是:node_modules 中模块的名称(如:stylelint-config-standard,从该模块导入的文件必须是有效的 JSON 配置);
使用 .js 或 .json 扩展名的文件绝对路径;
相对于引用配置的使用 .js 或 .json 扩展名的文件相对路径。
plugins: 插件是社区构建的支持方法、工具集、非标准 CSS 功能或非常具体的用例的规则或规则集。
plugins 用于配置一组插件。其值是一个定位符数组。与上面的 extends 一样,定位符可以是 npm 模块名称、绝对路径或相对于调用配置文件的路径。
一旦声明了插件,在您的 "rules" 对象中,您需要为插件的规则添加选项,就像任何标准规则一样。您需要查看插件的文档才能知道规则名称应该是什么。
如:
stylelint-selector-bem-pattern
是一款 stylelint 扩展插件,用于为 Css 选择器指定正则匹配。rules: 指定 Stylelint 要启用的校验规则。默认情况下没有打开任何规则。
rules 属性是一个键作为规则名称,值作为规则配置的对象。每条规则配置都符合以下格式之一:
单个值: 主选项;
包含两个值的数组: [主选项, 辅助选项];
null: 关闭规则。
点击查看 stylelint 所有内置规则,或者在 示例配置 中找到主要规则选项的完整列表。
默认情况下,所有规则都是 "error" 级别的严重性。您可以通过在配置中添加 defaultSeverity 属性来更改此默认值,或者使用辅助选项
severity
调整任何特定规则的严重性。severity 的可用值是:warning|error。所有规则都接受一个
message
辅助选项,如果指定该选项,任何标准消息都将被替为换指定的内容。processors: 处理器是一些社区包,使 stylelint 能够从非样式表文件中提取样式。它只能与命令行 和 Node.js API 一起使用,不能与 PostCSS 插件一起使用。
处理器可以启用 stylelint 校验,但不会自动修复,且不支持对非样式文件中的 CSS 进行校验。
processors 的值是一个定位符的数组。与 extends 上面一样,定位器可以是 npm 模块名称、绝对路径或相对于调用配置文件的路径。
ignoreFiles: 提供 glob 或 glob 数组以忽略特定文件。
glob 是用于匹配符合指定模式的文件集合的一种语言, 类似于正则表达式, 但更加简单。
请注意,这不是忽略大量文件的有效方法。 如果要有效地忽略大量文件,请使用 .stylelintignore 或调整文件 glob。
如果 globs 是绝对路径,则它们按原样使用。如果它们是相对路径,则相对于它们进行分析:
configBasedir
(Node.js API 传参中);配置的文件路径,如果配置是 stylelint 查找加载的文件的话;
或
process.cwd()
。
默认情况下,忽略所有
node_modules
和bower_components
。如果设置了ignoreFiles
,则将覆盖默认值。ignoreFiles
属性从继承配置中删除:只有根级配置可以忽略文件。**defaultSeverity:**未指定严重性的所有规则的默认严重性级别,可用值是:warning|error。
忽略代码
在文件中以注释形式,指定忽略的代码:
.stylelintignore
您可以使用 .stylelintignore
文件(或指向另一个忽略模式文件)来忽略特定文件。在检查文件系统之前,这些文件将从文件 glob 中排除,因此它是忽略大量文件的有效方法。
.stylelintignore
文件中的模式必须与 .gitignore
语法匹配。(在幕后,node-ignore
解析您的模式)这意味着您的 .stylelintignore
中的模式总是相对于 process.cwd()
进行分析。
stylelint 将在 process.cwd()
中查找.stylelintignore
文件。您还可以使用--ignore-path
(在CLI中)和 ignorePath
(在JS中)选项指定忽略模式文件的路径(绝对或相对于process.cwd()
)。
Prettier 的中文意思是“漂亮的、机灵的”,也是一个流行的代码格式化工具的名称。它在整个代码库中强制执行一致的代码风格(不会影响 AST),它能够解析代码,并使用你自己设定的规则来重新输出规范的代码。
Prettier 具有以下几个有优点:
可配置化;
支持多种语言;
集成多数的编辑器;
简洁的配置项。
到目前为止,采用 Prettier 的最大原因是停止所有正在进行的关于风格的争论。
Prettier 和 Linters 的区别:
Linter (如:ESLint/stylelint) 有两类规则:
**格式规则: ** 例如:max-len、no-mixed-spaces-and-tabs、keyword-spacing、comma-style ...
Prettier 减轻了 Linters 对这类规则的检查!Prettier 将以一致的风格从头开始重新输出整个项目的代码。
代码质量规则: 例如:no-unused-vars、no-extra-bind、no-implicit-globals、prefer-promise-reject-errors ...
Prettier 不会为这些规则做任何事。这些规则是 Linter 提供的最重要的功能,因为它们很可能会捕获您代码中的真正错误!
换句话说:使用 Prettier 格式化代码;使用 Linter 来捕获代码中的错误!
安装及配置
安装:npm i prettier -D
配置: 可以通过以下格式的文件(按优先顺序)配置 Prettier:
package.json
文件中的prettier
字段;.prettierrc: 用 JSON 或 YAML 编写的文件;
.prettierrc.json、.prettierrc.yml、.prettierrc.yaml、.prettierrc.json5
文件;.prettierrc.js、.prettierrc.cjs、prettier.config.js、prettier.config.cjs
导出module.exports
;.prettierrc.toml
文件。
配置文件将从被格式化的文件位置开始解析,并在文件树中搜索,直到找到(或未找到)配置文件。
Prettier 故意不支持任何类型的全局配置。这是为了确保当一个项目被复制到另一台计算机时,Prettier 的行为保持不变。否则,Prettier 将无法保证团队中的每个人都获得相同的一致结果。
使用方式
命令行: 在命令行使用 prettier
命令:
--write|-w: prettier 默认是在终端输出格式化后的文件。使用
--write
参数,将重写所有已处理的文件。 (注意:这会覆盖您的文件!)--check|-c: 检查文件是否已格式化。(注意:只检查,并不会对文件格式化!)
--find-config-path: 返回上次格式化该文件使用的配置文件的路径。
--config: 指定配置文件。
--ignore-path: 指定要忽略文件的配置文件。
--list-different|-l: 返回格式化文件会改动的文件名列表。
--no-config: 不要寻找配置文件。将使用默认设置。
--config-precedence: 枚举值,默认 cli。指定 cli 配置选项的优先级。
cli-override:CLI 选项优先于配置文件。
file-override: 配置文件优先于 CLI 选项。
prefer-file: 有配置文件,将忽略其他 CLI 选项;未找到配置文件,CLI 选项将正常使用。此选项增加了对编辑器集成的支持,当用户定义其配置,希望尊重项目特定配置。
--no-editorconfig: 解析配置文件时,忽略
.editorconfig
文件。--with-node-modules: Prettier 默认是忽略
node_modules
目录中的文件。该参数表示退出此行为。--loglevel: 枚举值,默认 log 。更改 CLI 的日志记录级别。值:error、warn、log (默认)、debug、silent。
Node应用程序接口: Prettier 提供了 APIS,允许你以编程方式运行 Prettier。
浏览器: 在 HTML 中引入 prettier.js
,在浏览器中调用 API。 此版本不依赖于 Node.js。它只格式化代码,不支持配置文件、忽略文件、CLI 使用或插件的自动加载。
Git Hooks: 可以将 Prettier 与预提交工具一起使用,即在 git add
提交之前重新格式化并标记为 “暂存” 文件。(详见下文)
与编辑器集成: Prettier 可以在多个编辑器中以插件的形式使用。如:VS Code、Vim、Sublime Text、WebStorm、Atom等。
以 VS code 为例,配置文件在保存时自动格式化文件:
安装
Prettier - Code formatter
;添加配置文件
prettier.config.js
;在
文件 -> 首选项 -> 设置 -> 文本编辑器 -> 格式化
中勾选Format On Save
;重启 VS code 。之后,在你每次保存文件时,prettier 会自动格式化文件。
printWidth: 数值,默认80。每行的最大字符长度。注意:printWidth 不是硬性的允许行长度上限,它只是说明您希望的每行的字符长度,与 Eslint 中的 max-len 不一样。比如:行中语句是一个长字符,printWidth 不会强制它换行
tabWidth: 数值,默认2。指定每个缩进符的空格数。
useTabs: 布尔值,默认值 false。指定缩进是否用 tab 符。
semi: 布尔值,默认值 true。在语句末尾输出分号。
singleQuote | jsxSingleQuote: 布尔值,默认值 false。指定是否使用单引号代替双引号。
JSX 会忽略
singleQuote
选项,指定要 JSX 中是否使用单引号代替双引号请使用jsxSingleQuote
选项。如果引号的数量超过另一个引号,则较少使用的引号将用于格式化字符串。示例:
quoteProps | jsxSingleQuote: 枚举值,默认值
as-needed
。指定对象中的属性的引号如何改动。as-needed:仅在需要时在对象属性周围添加引号。
consistent:如果对象中至少有一个属性需要引用,请引用所有属性。
preserve:尊重对象属性中引号的输入使用,即不改动属性的引号。
trailingComma: 枚举值,默认值
es5
。指定在多行逗号分隔的句法结构中如何输出尾随逗号。es5:在 ES5 中有效的尾随逗号(对象、数组等),TypeScript 中的类型参数中没有尾随逗号。
none:没有尾随逗号。
all:尽可能尾随逗号(包括函数参数和调用)。
bracketSpacing: 布尔值,默认值 true。表示对象的括号之间是否留空格。
bracketSameLine: 布尔值,默认值 false。指定是否将 HTML(HTML、JSX、Vue、Angular)多行的元素的结束符
>
放在同一行(不适用于自动关闭元素)。arrowParens: 枚举值,默认值
always
。指定箭头函数只有一个参数时,是否包含括号。always:始终包括括号。例子:
(x) => x
。avoid:尽可能省略括号。例子:
x => x
。
rangeStart | rangeEnd: 数值,
rangeStart
默认值 0,rangeEnd
默认值一Infinity
。这两个选项用来表示仅格式化文件的一部分,rangeStart
表示字符开始的位置,rangeEnd
表示字符结束的位置。parser: 指定要使用的解析器。没有默认值,Prettier 会自动从输入文件路径推断解析器,因此您不必更改此设置。点击查看 所有有效的解析器。
filepath: 字符串。指定要格式化的文件。此选项仅在 CLI 和 API 中有用,在配置文件中使用它没有意义。
requirePragma: 布尔值,默认 false。仅格式化文件顶部包含特殊注释的文件,即 执行 prettier 命令格式化多个文件时,只格式化顶部带以下注释的文件。
或者
insertPragma: 布尔值,默认 false。 指定是否对已使用 Prettier 命令格式化的文件,在顶部插入一个特殊
@format
标记。与requirePragma
同时使用时,require-pragma
具有优先权,insert-pragma
会被忽略。proseWrap: 枚举值,默认值
preserve
。默认情况下,Prettier 将按 markdown 文本原来的样子进行换行,因为某些服务的渲染器对换行符比较敏感。在某些情况下,您可能希望改用编辑器自己的换行,您可以选择never
。always:如果文本超过 printWidth,则将其换行。
never:不换行。
preserve:按原样换行。
htmlWhitespaceSensitivity: 枚举值,默认值
css
。为 HTML、Vue、Angular 和 Handlebars 指定全局空白敏感度。css:尊重 CSS
display
属性的默认值。在 Handlebars 使用strict
。strict:所有标签周围的空白(或没有空白)被认为是重要的。
ignore:所有标签周围的空白(或没有空白)被认为是无关紧要的。
vueIndentScriptAndStyle: 布尔值,默认值 false。是否缩进Vue 文件中的代码
<script>
和<style>
标签。endOfLine: 枚举值,默认值
lf
。指定换行符。由于历史原因,文本文件中存在两种常见的行尾形式,即 (
LF
)和\r
(回车+CRLF
)。前者在 Linux 和 macOS 上很常见,而后者在 Windows 上很普遍。lf:仅换行 ( ),常见于 Linux 和 macOS 以及 git 存储库内。
crlf:回车符 + 换行符 (
\r
),在 Windows 上很常见。cr:仅回车符 ( ),很少使用。
auto:维护现有的换行符。
**embeddedLanguageFormatting:**枚举值,默认值
auto
。控制 Prettier 是否格式化文件中嵌入的引用代码。auto:如果 Prettier 可以自动识别嵌入代码,请对其进行格式化。
off:永远不要自动格式化嵌入的代码。
overrides: 重写对某些文件扩展名、文件夹和特定文件的 prettier 配置。
共享配置: 共享 Prettier 配置很简单,只需发布一个导出配置对象的模块,然后在
package.json
或者配置文件中导入即可。
在文件中以注释形式,忽略代码:
新创建 .prettierignore
文件,去忽略某些文件和文件夹。
EditorConfig 帮助跨不同编辑器和 IDE 从事同一项目的多个开发人员维护一致的编码风格。 EditorConfig 项目包括一个用于定义编码样式的文件格式(.editorconfig)和一组文本编辑器插件,这些插件使编辑器能够读取文件格式并遵循所定义的样式。
有些编辑器默认支持 editorConfig,如 webstorm;而有些编辑器则需要安装 editorConfig 插件,如ATOM、Sublime、VS Code等。
当打开一个文件时,EditorConfig 插件会在打开文件的目录和其每一级父目录查找 .editorconfig
文件,直到有一个配置文件 root=true。
EditorConfig 的配置文件是从上往下读取的,并且最近的 EditorConfig 配置文件会被最先读取。匹配 EditorConfig 配置文件中的配置项会按照读取顺序被应用,所以最近的配置文件中的配置项拥有优先权。
如果 .editorconfig
文件没有进行某些配置,则使用编辑器默认的设置。
配置说明
.editorconfig
需要是 UTF-8 字符集编码的,以 CRLF 或 LF 行分隔符,斜杆(/)被用作为一个路径分隔符,井号(#)或分号(;)被用作于注释,注释需要与注释符号写在同一行。
.editorconfig
文件中,所有的属性和值都是忽略大小写的,解析时它们都是小写的。注意:部分名称是文件路径的,是区分大小写。
示例:
请注意,并非每个插件都支持所有属性。
indent_style: 指定以 tab 符,还是空格缩进。值:tab | space。
indent_size: 指定缩进 tab 符的列数或者空格的宽度。当设置为 tab 时,
tab_width
将使用(如果指定)的值。tab_width: 指定 tab 符的列数的整数。这个默认为
indent_size
的值,indent_size
通常不需要指定。end_of_line: 指定换行符。值:lf | cr | crlf。
charset: 指定编码字符集。值:latin1 | utf-8 | utf-8-bom | utf-16be | utf-16le。
trim_trailing_whitespace: 指定是否删除换行符之前的任何空白字符。值:true | false。
insert_final_newline: 指定是否在文件保存时以换行符结尾。值:true | false。
root: 指定是否停止对
.editorconfig
文件的搜索。该属性应置于文件顶部,在任何其他属性之上。值:true。
一般情况下,如果没有指定属性,将使用编辑器默认设置的值。对于任何属性,值为 unset
是为了移除该属性的影响,即使它之前已经设置过。
与编辑器集成
要将 EditorConfig 与编辑器或 IDE一起使用, 必需安装对应的 EditorConfig 插件或扩展。。
以 VS code 为例:安装 EditorConfig for VS Code
插件,再配置 .editorconfig
文件。
注意: 需要先安装 EditorConfig
包。如:npm install editorconfig -g
。
注意: VS code 的 Prettier 和 EditorConfig 插件有冲突。如果你安装过 Prettier 插件,后面又安装了 EditorConfig。这时,你调用 Format Document
命令或者保存文件,EditorConfig 可能不会自动格式化文件。
EditorConfig 格式化无效,有两个可能的原因:
编辑器指定的默认格式化程序是 Prettier(或其他程序)。我们可以修改默认的格式化程序:
Ctrl + Shift + p
打开命令面板,输入setting
,点击Perferences: Open Settings(JSON)
,打开setting
文件,设置"editor.defaultFormatter": "EditorConfig.EditorConfig"
。格式化程序不能格式化当前文件。报错: 扩展 ”EditorConfig for VS Code“ 配置为格式化程序,但不能格式化 'JavaScript' -文件。
解决方法一:为特定的格式指定更改格式化文档方式,方法如上,参数如下方。
解决方法二:在文档中
右键 -> 使用...格式化文档
,可以点击【格式化程序】格式化当前文件,也可以选择 【配置默认格式化程序...】为当前格式指定默认格式化程序。
以上两种方法,本质上都是修改 setting
文件,配置参数如下:
如何避免 Linters、Prettier、EditorConfig 冲突?
Linters、Prettier、EditorConfig 通过在项目中统一约定配置,可以在代码开发过程中就检查、约束、美化代码,统一编码风格;这样可以省去很多的沟通成本,提前暴露代码缺陷,减少后期二次维护代码的风险。
这三者可以一起在项目中使用,它们的关注点各有不同:
EditorConfig: 跨编辑器和 IDE 编写代码,保持一致的简单编码风格;
Prettier: 只专注于代码格式化,并不具备检查语法等功能;
Linters: 代码质量检测、编码风格约束等,并且会提示或自动修复(部分)不符合风格规范的代码。
三者有部分规范属性是重复的,比如:代码缩进风格,EditorConfig 配置中指定 indent_style = space, indent_size = 4
,Prettier 配置中指定 tabWidth: 2, useTabs: false
, Eslinte 配置中指定 rules 字段中 "indent": ["error", 4]
。这三种配置都是指定代码缩进的规范,其指定值不一样时,不可避免的会发生冲突。
在这之前,我一直有个疑问:即然 Linters 可以约束和规范代码,为什么还要用 Prettier 和 EditorConfig 呢?
目前我总结,可能是以下原因:
Prettier 可以针对各种流行语言,Linters 是针对特定的某种语言,比如:Eslint 是针对 JavaScript。
Prettier、EditorConfig 安装、配置比较简单,运行速度也较快,并且能较好的与编辑器或 IDE 集成。
Prettier、EditorConfig 可以提供一些 Liners 没有的规范。比如:EditorConfig 的
charset
属性。
那么我们该如何避免冲突?
方法一:专事专办、各司其职
让不同的插件做自己专注的事,避免重复配置同一规范。
与编辑器或 IDE 相关的所有配置(结尾行、缩进风格、缩进大小等等)应该由 EditorConfig 来处理;
和代码格式相关的一切事物应该由 Prettier 处理;
剩下的,代码质量相关的,则由 Linters 负责。
这样,Linters 做为我们的代码质量检测器,Prettier 充当代码格式化工具,而 EditorConfig 将为每个人提供正确的编辑器配置。
方法二:目标一致、同进同退
将这三个插件的指定同一规范的配置的值设置为等价的。比如:缩进风格,统一2个空格:
方法三:协商合作、互谦互让
为插件的配置约定不同优先级,或者约定覆盖规则。
Prettier 的最新版本通过解析
.editorconfig
文件来确定要使用的配置选项。也就是说,Prettier 会解析 EditorConfig 的配置。如果 Prettier 没有该配置,将采用 EditorConfig 的配置;如果有,则采用 Prettier 的配置。Prettier 配置优先于 EditorConfig。Linters 集成 Prettier,禁用冲突的规则。
比如:Eslint 提供插件将 Prettier 作为 Eslint 规则来运行,如:
eslint-plugin-prettier
。我们通过extends
字段来扩展该插件,然后在rules
字段中指定关闭或启用某个 Prettier 规则。再比如:Eslint 提一个
eslint-plugin-prettier
扩展,禁用所有与格式化相关的 ESLint 规则。"plugins": ["prettier"]: 注册插件;
"extends": ["prettier"]: 启用
eslint-config-prettier
配置,关闭与 ESLint 冲突的规则;"prettier/prettier": "error": 启用
eslint-plugin-prettier
提供的规则。
注意:
extends
字段中,后面引入的插件会覆盖前面的插件。
Git Hook 集成格式化工具
在我们提交代码时,使用格式化程序,帮助我们检查代码并自动修复错误,在修复不了的时候,报错给我们。这样,可以确保提交到仓库的代码是风格一致的。
Git Hook
Git 能在特定的重要动作发生时触发自定义脚本。 有两组这样的钩子:客户端的和服务器端的。 客户端钩子由诸如提交和合并这样的操作所调用,而服务器端钩子作用于诸如接收被推送的提交这样的联网操作。
钩子都被存储在 Git 目录下的 hooks 子目录中。 也即绝大部分项目中的 .git/hooks 。 当你用 git init 初始化一个新版本库时,Git 默认会在这个目录中放置一些示例脚本。这些脚本除了本身可以被调用外,它们还透露了被触发时所传入的参数。 所有的示例都是 shell 脚本,其中一些还混杂了 Perl 代码,不过,任何正确命名的可执行脚本都可以正常使用 —— 你可以用 Ruby 或 Python,或任何你熟悉的语言编写它们。 这些示例的名字都是以 .sample 结尾,如果你想启用它们,得先移除这个后缀。
把一个正确命名(不带扩展名)且可执行的文件放入 .git 目录下的 hooks 子目录中,即可激活该钩子脚本。 这样一来,它就能被 Git 调用。
客户端钩子分为很多种:提交工作流钩子、电子邮件工作流钩子和其它钩子。
提交工作流钩子:
pre-commit: 钩子在
git commit
前运行。 它用于检查即将提交的快照:检查是否有所遗漏、核查代码。 如果该钩子以非零值退出,Git 将放弃此次提交,不过你可以用 git commit --no-verify 来绕过这个环节。 你可以利用该钩子,来检查代码风格是否一致(运行类似 lint 的程序)、尾随空白字符是否存在(自带的钩子就是这么做的),或新方法的文档是否适当。prepare-commit-msg: 钩子在启动提交信息编辑器之前,默认信息被创建之后运行。
commit-msg: 钩子接收一个参数,此参数即上文提到的,存有当前提交信息的临时文件的路径。 如果该钩子脚本以非零值退出,Git 将放弃提交,因此,可以用来在提交通过前验证项目状态或提交信息。
post-commit: 钩子在整个提交过程完成后运行。 它不接收任何参数,但你可以很容易地通过运行 git log -1 HEAD 来获得最后一次的提交信息。
除了客户端钩子,作为系统管理员,你还可以使用若干服务器端的钩子对项目强制执行各种类型的策略。 这些钩子脚本在推送到服务器之前和之后运行。 推送到服务器前运行的钩子可以在任何时候以非零值退出,拒绝推送并给客户端返回错误消息,还可以依你所想设置足够复杂的推送策略。
pre-receive: 处理来自客户端的推送操作时,最先被调用的脚本是 pre-receive。 它从标准输入获取一系列被推送的引用。如果它以非零值退出,所有的推送内容都不会被接受。 你可以用这个钩子阻止对引用进行非快进(non-fast-forward)的更新,或者对该推送所修改的所有引用和文件进行访问控制。
update: update 脚本和 pre-receive 脚本十分类似,不同之处在于它会为每一个准备更新的分支各运行一次。 假如推送者同时向多个分支推送内容,pre-receive 只运行一次,相比之下 update 则会为每一个被推送的分支各运行一次。 它不会从标准输入读取内容,而是接受三个参数:引用的名字(分支),推送前的引用指向的内容的 SHA-1 值,以及用户准备推送的内容的 SHA-1 值。 如果 update 脚本以非零值退出,只有相应的那一个引用会被拒绝;其余的依然会被更新。
post-receive: post-receive 挂钩在整个过程完结以后运行,可以用来更新其他系统服务或者通知用户。
在项目的 .git/hooks
目录中,有一些 .sample
结尾的钩子示例脚本,如果想启用对应的钩子,只需手动删除后缀,即可。
注: 删除某一个 hook 的后缀 .sample
即可启用该 hook 脚本,默认是不启用的。
但是,我们一般不去改动 .git/hooks
里面的文件,因为我们使用 husky 插件。husky 在安装过程中会在 .git/hooks
文件夹中生成一系列的 git hook 脚本。
安装: npm i husky -D
注意 Husky 版本问题: husky@6.0.0 做了破坏性的变更,之前版本的设置方式已经失效。
根据官方说法,之前 husky 的工作方式是:安装时,创建所有类型的 Git hooks。这样做的好处是,无论用户设置什么类型的 hook,husky 都能确保其正常运行,其缺点也明显,即使用户没有设置任何 hook,husky 也向 Git 中添加了所有类型的 Git hook。
那有没有可能让 husky 只添加某一个 hook呢?husky 的作者尝试过解决这个问题,但是失败了。其根本原因是:husky 需要在两个地方进行配置才能完成一个完整的 hook 功能。一是 package.json
配置 git hook 所要执行的真正命令,一是在 .git/hooks
目录下,配置相对应的 hook。作者没有找到一个可靠的方法,同步这两个地方的配置。
新版本的工作原理: 新版的 husky 使用了从 git 2.9 开始引入的一个新功能 core.hooksPath
。core.hooksPath
可以让你指定 git hooks 所在的目录而不是使用默认的 .git/hooks/
。这样 husky 可以使用 husky install
将 git hooks
的目录指定为 .husky/
,然后使用 husky add
命令向 .husky/
中添加 hook。通过这种方式我们就可以只添加我们需要的 git hook
,而且所有的脚本都保存在了一个地方(.husky/
目录下)因此也就不存在同步文件的问题了。
新版本(6.0.0后)实践:
安装:
npm i husky -D
在
package.json
中添加 prepare 脚本:prepare 脚本会在
npm install
(不带参数)之后自动执行。也就是,执行npm install
安装完项目依赖后,会执行husky install
命令该。命令会创建在根目录下创建.husky/
目录并指定该目录为 git hooks 所在的目录。当然,也可以直接在命令行中执行
husky install
,创建.husky
目录。添加 Git hooks:
在
./husky
目录下,打开pre-commit
文件,可查看其中配置:
之后,执行 git commit
命令的,会调用钩子执行 "echo 'Create Git Hooks Success!'"
。
husky 的配置可以使用 .huskyrc、.huskyrc.json、.huskyrc.js、husky.config.js
文件。
lint-staged 是一个在 git 暂存文件上(也就是被 git add 的文件)运行已配置的 linter(或其他)任务。lint-staged 总是将所有暂存文件的列表传递给任务。简单来说,就是当我们运行 eslint
或 stylelint
命令时,只会检查我们通过 git add
添加到暂存区的文件,可以避免我们每次检查都把整个项目的代码都检查一遍。
安装: npm i lint-staged -D
配置: 在 package.json
文件中配置:
这里 lint-staged 的配置,前面一条是:在 git 的待提交的文件中,在 src、package 目录下的所有 .js
.vue
都要执行三条命令。前两条是 eslint 命令和 prettier 命令,后一条是将处理过的代码重新 add 到 git 中。
配置完成后,执行 git add .
向暂存区提交文件,再在命令行中执行 lint-staged
,即可执行以上配置的命令。
其他 lint-staged 配置方式:
package.json
的 lint-staged 字段;.lintstagedrc: JSON 或 YML 格式的文件;
lint-staged.config.js: JS 格式的文件。
使用 –config
或 -c
标识传递配置文件。
husky + lint-staged
执行 husky add
命令,添加 pre-commit
钩子,执行 "lint-staged"
,形成一个自动化工具链:
如此,在 commit 之前,将暂存区的内容做一次代码检查和代码美化,然后再添加到暂存区;然后再 commit,完美!!
参考链接
最后更新于