Prettier

747 阅读7分钟

关于Prettier

什么是Prettier

Prettierpretty的比较级,直译是更漂亮的意思。它主要用于将文本文件按照一定的规范,在不改变AST(抽象语法树)的前提下进行格式化。它支持包括一下文本格式:

为什么使用

代码规范化这个事情,对团队和协作是是否有意义的,但是建立和统一规范的过程是及其枯燥无味且无意义的(对个人来说)。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
}

另外需要注意的是,在vuets中,{'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
avoidx => 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

是否将scriptstyle中的内容相对这两个标签进行缩进。默认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
}

使用

一般项目中都会配置eslintprettier,相较于两者分开进行校验,合并才是最好的解决方案。

与Linters配合使用

eslint负责根据AST去分析找出不符合规则的代码并报错,但有些规则是与prettier有重合的,这些重合的规则,建议遵循prettier的规则定义。

依赖包说明
eslint-config-prettier关闭eslint中与Prettier有冲突的规则
eslint-plugin-prettier将Prettier作为eslint的规则进行代码的检测,并使用eslint进行格式化
prettier-standardstandard.js的规则作为规范,使用Prettier进行格式化

建议使用前两个依赖包,配合eslint进行代码格式化。

module.exports = {
	extends: ["airbnb-base", "plugin:@typescript-eslint/recommended", "prettier"],
  plugins: ["@typescript-eslint", "prettier"],
}

为了保证遵循Prettier的规则,必须将Prettier放在配置的最后面。

与lint-staged配合使用

如果每次都对项目所有文件执行格式化(npx prettier -w .),太过于浪费时间。真实的开发环境中,至于要对变动的文件进行格式化即可。搭配使用huskylint-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/

有些内容如果不想被格式化,可以在文件中使用注释的方式跳过格式化