关于Prettier
什么是Prettier
Prettier是pretty的比较级,直译是更漂亮的意思。它主要用于将文本文件按照一定的规范,在不改变AST(抽象语法树)的前提下进行格式化。它支持包括一下文本格式:
- JavaScript (including experimental features)
- JSX
- Angular
- Vue
- Flow
- TypeScript
- CSS, Less, and SCSS
- HTML
- Ember/Handlebars
- JSON
- GraphQL
- Markdown, including GFM and MDX
- YAML
为什么使用
代码规范化这个事情,对团队和协作是是否有意义的,但是建立和统一规范的过程是及其枯燥无味且无意义的(对个人来说)。Prettier存在的目的即在于此,减少不必要的讨论,减少代码规范对实际开发的影响,大家遵循Prettier的规范即可。
对于配置的理念
Prettier的初衷是为了终止所有关于代码风格(code style)的讨论。而实现这个初衷,需要一些配置项,去实现这些规则。但是,随着讨论的深入,Prettier发现,如果有太多的规则配置,那么人们会不会对规则(比如那个规则配置是更好的)展开更多的讨论呢?
这显然是违背初衷的。
现有的配置,都是因为这样或那样的原因而存在的,但是以后,Prettier不准备再添加任何的规则配置了。
尽可能因为一些兼容性的问题添加一些配置。因为Prettier团队认为,经过了这么多团队和项目的洗礼,Prettier本身已足够成熟,完成了初衷。
我的想法
我是完全认同Prettier团队的看法的。正如他们所说,关于代码风格的争论本身就是一件无意义且浪费时间的事情,Prettier已经做到中止了其中大部分的讨论,现有的项目结果也是满意的。所以,在当前——关于代码风格的大部分讨论已中止,关于规则配置的讨论还没兴起——停止接收新的规则配置是最好的选择。
规则详细
有些规则与.editorconfig中的某些规则是对应的。
优先级:.prettierrc.js> .editorconfig > prettier默认值。
如有对应的,会在每条规则下面标出。
Print Width
max_line_length=110
指定每行的宽度,单位:字符数。默认值是80。
这不是强制每行最多80,prettier会根据实际的情况决定是否溢出换行。
Tab Width
tab_width indent_size=2
指定每个制表符对应几个空格。默认2。
Tabs
使用制表符代替空格缩进。默认false。
Semicolons
是否在行尾添加分号(;)。默认true。
建议遵循默认,明确标识一行语句的结束。
Quotes
使用单引号代替双引号。默认false。
建议遵循默认。可以减少转义字符的使用,更加的符合规范。详见
Quote Props
是否给对象的属性添加/去掉引号("")。默认按需(as-needed)。
| 可选值 | 释义 |
|---|---|
| as-needed | 按需。只有在需要的时候才使用引号。 |
| consistent | 保持一致。如果一个属性必须使用引号,那个这个对象的所有属性都会使用引号。 |
| preserve | 保持现状。什么都不做。 |
// 源代码
const user = {
"role": "admin",
age: 2,
"are you ok": 0
}
// as-needed
const user = {
// 不是必须的,被移除
role: "admin",
age: 2,
"are you ok": 0
}
// consistent
const user = {
"role": "admin",
"age": 2,
// 必须使用,所有全部属性都加上引号
"are you ok": 0
}
// preserve
// 保持现状
const user = {
"role": "admin",
age: 2,
"are you ok": 0
}
另外需要注意的是,在vue和ts中,{'0': 1}跟{0 : 1}是不同的,所以prettier是不会去掉前者的引号的。
JSX Quotes
在jsx中使用单引号代替双引号。默认false。
Trailing Commas
是否在多行负责结构中,在最后一行使用逗号结尾(,)。默认all。
| 可选值 | 释义 |
|---|---|
| es5 | 只在ES5语法支持的数据结构中使用(如Object)。函数入参中不会使用。 |
| none | 不需要结尾逗号 |
| all | 尽可能的使用结尾逗号 |
// es5
const a = {
b: 1,
c: 2,
}
function send_single_email(
app,
email_id,
email_address,
subject,
html,
reply_to
) {
}
// none
const a = {
b: 1,
c: 2
}
function send_single_email(
app,
email_id,
email_address,
subject,
html,
reply_to
) {
}
// all
const a = {
b: 1,
c: 2,
}
function send_single_email(
app,
email_id,
email_address,
subject,
html,
reply_to,
) {
}
Bracket Spacing
是否需要{、}和内容之间的空格。默认true。
Bracket Line
HTML (HTML, JSX, Vue, Angular) 标签开始标签的结束符号(>),在开始标签有多行的情况下,是否不单独一行展示。默认false。
// 默认。单独一行
<button
className="prettier-class"
id="prettier-id"
onClick={this.handleClick}
>
Click Here
</button>
// true
<button
className="prettier-class"
id="prettier-id"
onClick={this.handleClick}>
Click Here
</button>
Arrow Function Parentheses
箭头函数只有一个参数时,是否使用括号(())包裹。默认always。
| 可选值 | 释义 |
|---|---|
| always | (x) => x |
| avoid | x => x |
Range
设置文件中需要进行格式化的区间。默认0-Infinity。
Parser
指定文件解析器。但Prettier会根据文件类型自动匹配解析器,所以一般无需指定。默认无。
File Path
有些文件没有后缀,可以设置带后缀的路径来让Prettier自动匹配解析器。该规则只在命令行可用。
Require Pragma
只处理带有指定文件头(注释)的文件。默认false。
可以识别的文件头见下:
/**
* @prettier
*/
/**
* @format
*/
Insert Pragma
给指定格式化的文件头部插入注释@format。默认false。
Prose Wrap
markdown文本超出一行是否换行。默认preserve(保持现状)。
| 可选值 | 释义 |
|---|---|
| always | 超出一行最大字符数即换行 |
| never | 不换行 |
| preserve | 保持现状。什么也不做。 |
HTML Whitespace Sensitivity
HTML标签内容里对空格的敏感性。默认值css。
| 可选值 | 释义 |
|---|---|
| css | 保证最终的视觉效果的前提下,对空格进行转换、添加、移除。 |
| strict | 保持所有空格不做改动 |
| ignore | 将所有空格进行转换 |
<!-- 源代码 -->
<div><a href="https://prettier.io/">Prettier is an opinionated code formatter.</a></div>
<!-- css -->
<div>
<a href="https://prettier.io/"
>Prettier is an opinionated code formatter.</a
>
</div>
<!-- strict -->
<div
><a href="https://prettier.io/"
>Prettier is an opinionated code formatter.</a
></div
>
<!-- ignore -->
<div>
<a href="https://prettier.io/">
Prettier is an opinionated code formatter.
</a>
</div>
Vue files script and style tags indentation
是否将script和style中的内容相对这两个标签进行缩进。默认false。
<!-- false -->
<script>
export default {
}
</script>
<style>
.body {
color: red;
}
</style>
<!-- true -->
<script>
export default {
}
</script>
<style>
.body {
color: red;
}
</style>
End of Line
end_of_line=lf
文件最后一行的换行格式。默认lf。
Embedded Language Formatting
是否格式化使用引号包裹的内嵌代码。默认auto。
| 可选值 | 释义 |
|---|---|
| auto | 自动格式化识别出的代码 |
| off | 保持现状。不做改动。 |
Single Attribute Per Line
每个标签的属性都占据一行。默认false。
最终规范
看完规则我们发现,其实prettier为每条规则设置的默认值都是最值得推荐的配置。所以,我们的最终规范就是不设置任何prettier的规则,全部都遵循默认值。
下面列出所有规则的默认值:
module.exports = {
printWidth: 80,
tabWidth: 2,
useTabs: false,
semi: true,
singleQuote: false,
quoteProps: "as-needed",
jsxSingleQuote: false,
trailingComma: "all",
bracketSpacing: true,
bracketSameLine: false,
arrowParens: "always",
requirePragma: false,
insertPragma: false,
proseWrap: "preserve",
htmlWhitespaceSensitivity: "css",
vueIndentScriptAndStyle: false,
endOfLine: "lf",
embeddedLanguageFormatting: "auto",
singleAttributePerLine: false
}
使用
一般项目中都会配置eslint和prettier,相较于两者分开进行校验,合并才是最好的解决方案。
与Linters配合使用
eslint负责根据AST去分析找出不符合规则的代码并报错,但有些规则是与prettier有重合的,这些重合的规则,建议遵循prettier的规则定义。
| 依赖包 | 说明 |
|---|---|
| eslint-config-prettier | 关闭eslint中与Prettier有冲突的规则 |
| eslint-plugin-prettier | 将Prettier作为eslint的规则进行代码的检测,并使用eslint进行格式化 |
| prettier-standard | 将standard.js的规则作为规范,使用Prettier进行格式化 |
建议使用前两个依赖包,配合eslint进行代码格式化。
module.exports = {
extends: ["airbnb-base", "plugin:@typescript-eslint/recommended", "prettier"],
plugins: ["@typescript-eslint", "prettier"],
}
为了保证遵循Prettier的规则,必须将Prettier放在配置的最后面。
与lint-staged配合使用
如果每次都对项目所有文件执行格式化(npx prettier -w .),太过于浪费时间。真实的开发环境中,至于要对变动的文件进行格式化即可。搭配使用husky和lint-staged即可优雅的实现。
pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- lint-staged
.lintstagedrc.cjs
module.exports = {
"**/*.{ts?(x), js?(x), vue, html}": ["eslint --fix --max-warnings 10"],
};
其他
.prettierignore
由于prettier默认忽略版本管理文件夹(.git)和node_modules文件夹,所以下面不再进行设置。
# 编辑器配置文件
.idea/
.vscode/
# 输出目录
dist/
有些内容如果不想被格式化,可以在文件中使用注释的方式跳过格式化。