跳至主内容区

Prettier 2.6:新增 singleAttributePerLine 选项及支持最新 JavaScript 特性!

· 1 分钟阅读
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

本次发布引入了新的 singleAttributePerLine 选项。该选项可在 Vue 单文件组件模板、HTML 和 JSX 中实现每行仅输出一个属性。根据我们的选项设计哲学,我们本不愿添加此类选项。然而大量用户需要此功能,且主流风格指南如 Airbnb JavaScript 风格指南Vue 风格指南均推荐每行单属性的代码风格。该功能的拉取请求于 2019 年 10 月提出,其与对应议题均获得了大量用户支持。对我们而言这是艰难的决定,希望新增此选项能在不显著违背原则的前提下惠及众多用户。

我们还通过 Babel 新增了对部分 JavaScript 新语法提案的格式化支持。

致谢我们的赞助商!

今年初的博客文章所述,我们已开始使用赞助资金向维护者支付报酬。衷心感谢所有促成此事的赞助商!特别鸣谢以下捐赠超 1000 美元的企业与个人:

如果您喜欢 Prettier 并希望支持我们的工作,欢迎通过 我们的 OpenCollective 直接赞助,或赞助我们依赖的项目,包括 typescript-eslintremarkBabel

重要更新

TypeScript

支持 TypeScript 4.6 (#12400 by @dependabot)

我们已将解析 TS 代码的 TypeScript 版本更新至 TypeScript 4.6。由于该版本未新增语法特性,我们无需进行其他调整。

HTML

强制单属性换行 (#6644 by @kankje)

新增 singleAttributePerLine 选项,用于指定 Prettier 是否强制在 HTML、Vue 和 JSX 中每行只保留单个属性。

<!-- Input -->
<div data-a="1">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
<div data-a="1" data-b="2" data-c="3">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>

<!-- Prettier 2.5 -->
<div data-a="1">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
<div data-a="1" data-b="2" data-c="3">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>

<!-- Prettier 2.6, with `{"singleAttributePerLine": false}` -->
<div data-a="1">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
<div data-a="1" data-b="2" data-c="3">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>

<!-- Prettier 2.6, with `{"singleAttributePerLine": true}` -->
<div data-a="1">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
<div
data-a="1"
data-b="2"
data-c="3"
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>

其他变更

JavaScript

在 Angular 中将 waitForAsync 识别为测试语句 (#11992 by @HendrikN)

// Input
test("foo bar", waitForAsync(() => {
const foo = "bar";
expect(foo).toEqual("bar")
}));

// Prettier 2.5
test(
"foo bar",
waitForAsync(() => {
const foo = "bar";
expect(foo).toEqual("bar");
})
);

// Prettier 2.6
test("foo bar", waitForAsync(() => {
const foo = "bar";
expect(foo).toEqual("bar");
}));

保留无代码块 if 语句后的行尾注释 (#12017 by @sosukesuzuki)

// Input
if (condition1) expression1; // comment A
else if (condition2) expression2; // comment B
else expression3; // comment C

// Prettier 2.5
if (condition1) expression1;
// comment A
else if (condition2) expression2;
// comment B
else expression3; // comment C

// Prettier 2.6
if (condition1) expression1; // comment A
else if (condition2) expression2; // comment B
else expression3; // comment C

使用 babel-ts 解析器时保留带括号 TS 关键字类型的注释 (#12070 by @sosukesuzuki)

// Input
let foo: (
// comment
never
);

// Prettier 2.5
Error: Comment "comment" was not printed. Please report this error!

// Prettier 2.6
let foo: // comment
never;

保留 continue/break 语句的行尾注释 (#12075 by @sosukesuzuki)

// Input
for (;;) continue // comment
;

// Prettier 2.5
Error: Comment "comment" was not printed. Please report this error!

// Prettier 2.6
for (;;)
continue; // comment

内联 JSX 中的 await 表达式 (#12088 & #12109 by @j-f1)

当参数符合内联条件时,JSX 中的 await 表达式现在会被内联处理。

// Input
{await Promise.all(
someVeryLongExpression
)}

{await (
<div>Lorem ipsum ...</div>
)}


// Prettier 2.5
{
await Promise.all(
someVeryLongExpression
)
}

{
await (
<div>Lorem ipsum ...</div>
)
}


// Prettier 2.6
{await Promise.all(
someVeryLongExpression
)}

{await (
<div>Lorem ipsum ...</div>
)}

新增 acorn 解析器 (#12172 by @fisker)

parser 选项新增值:acorn - 一款轻量快速、基于 JavaScript 的 JavaScript 解析器。

default case 后的注释保留在同一行 (#12177 by @duailibe)

在 switch 语句中,尽可能将紧跟在 default case 后的注释保留在同一行。

// Input
function read_statement() {
switch (peek_keyword()) {
case Keyword.impl: // impl<T> Growling<T> for Wolf {}
return ImplDeclaration.read();

default: // expression;
return ExpressionStatement.read();
}
}

// Prettier 2.5
function read_statement() {
switch (peek_keyword()) {
case Keyword.impl: // impl<T> Growling<T> for Wolf {}
return ImplDeclaration.read();

default:
// expression;
return ExpressionStatement.read();
}
}

// Prettier 2.6
function read_statement() {
switch (peek_keyword()) {
case Keyword.impl: // impl<T> Growling<T> for Wolf {}
return ImplDeclaration.read();

default: // expression;
return ExpressionStatement.read();
}
}

修复抽象方法中参数注释错位问题 (#12185 by @duailibe)

// Input
abstract class Foo {
abstract bar(
/** comment explaining userId param */
userId
)
}

// Prettier 2.5
abstract class Foo {
abstract bar(userId);
/** comment explaining userId param */
}

// Prettier 2.6
abstract class Foo {
abstract bar(
/** comment explaining userId param */
userId
);
}

修复类声明中父类类型转换问题 (#12222 & #12226 by @duailibe)

此修复包含两个独立问题:移动父类前的注释以及避免在父类周围添加多余括号。

// Input
class Foo extends /** @type {Type} */ (Bar) {}

// Prettier 2.5
class Foo /** @type {Type} */ extends ((Bar)) {}

// Prettier 2.6
class Foo extends /** @type {Type} */ (Bar) {}

支持正则表达式中的 Unicode 集合表示法 (#12241 by @fisker)

通过 Babel 7.17.0 现已支持 Unicode 集合表示法 的 Stage 3 提案。

请参阅 Babel v7.17.0 的发布博客文章该提案的 README了解详细信息。在使用 Prettier 格式化此提案语法前,请务必阅读我们关于非标准语法的政策

// Examples

/[\p{Decimal_Number}--[0-9]]/v; // Non-ASCII decimal digits

"Did you see the 👩🏿‍❤️‍💋‍👩🏾 emoji?".match(/\p{RGI_Emoji}/v). // ["👩🏿‍❤️‍💋‍👩🏾"]

/[\r\n\q{\r\n|NEWLINE}]/v; // Matches \r, \n, \r\n or NEWLINE

为带装饰器的 ClassExpression 添加括号 (#12260 by @fisker)

// Input
(@f() class {});

// Prettier 2.5
@f()
class {};

// Prettier 2.5 (Second format)
SyntaxError: A class name is required. (2:7)
1 | @f()
> 2 | class {};
| ^
3 |

// Prettier 2.6
(
@f()
class {}
);

优化 Flow 和 TS 中类型别名注释的打印方式 (#12268 by @duailibe)

在 Flow 中,注释现在将更符合我们在赋值语句(右侧为对象表达式)中的注释打印方式:

// Input
type Props = // comment explaining the props
{
isPlaying: boolean
};

// Prettier 2.5
// comment explaining the props
type Props = {
isPlaying: boolean,
};

// Prettier 2.6
type Props =
// comment explaining the props
{
isPlaying: boolean,
};

此项变更还修复了 TypeScript 中类似位置的注释在二次格式化后会被移动的问题:

// Input
type Props = // comment explaining the props
{
isPlaying: boolean
};

// Prettier 2.5
type Props = { // comment explaining the props
isPlaying: boolean;
};

// Prettier 2.5 (2nd format)
type Props = {
// comment explaining the props
isPlaying: boolean;
};

// Prettier 2.6
type Props =
// comment explaining the props
{
isPlaying: boolean,
};

支持私有字段解构 (#12276 by @sosukesuzuki)

通过 Babel 7.17 现已支持 TC39 第二阶段提案的私有字段解构。在使用 Prettier 格式化此提案语法前,请务必阅读我们关于非标准语法的政策

// Example
class Foo {
constructor() {
console.log(this.#x); // => 1
const { #x: x } = this;
console.log(x); // => 1
}
}

支持装饰器自动访问器语法 (#12299 by @sosukesuzuki)

支持新装饰器提案引入的自动访问器语法。在使用 Prettier 格式化此提案语法前,请务必阅读我们关于非标准语法的政策

// Example
@defineElement("my-class")
class C extends HTMLElement {
@reactive accessor clicked = false;
}

修复赋值语句中 = 符号后行注释导致的幂等问题 (#12349 by @thorn0)

// Input
const kochabCooieGameOnOboleUnweave = // !!!
rhubarbRhubarb(annularCooeedSplicesWalksWayWay);

// Prettier 2.5, first format
const kochabCooieGameOnOboleUnweave = rhubarbRhubarb( // !!!
annularCooeedSplicesWalksWayWay
);

// Prettier 2.5, second format
const kochabCooieGameOnOboleUnweave = rhubarbRhubarb(
// !!!
annularCooeedSplicesWalksWayWay
);

// Prettier 2.6
const kochabCooieGameOnOboleUnweave = // !!!
rhubarbRhubarb(annularCooeedSplicesWalksWayWay);

TypeScript

重构明确赋值断言的打印逻辑 (#12351 by @thorn0)

现在即使明确赋值断言后没有类型注解也会被打印。虽然在 TypeScript 中这是错误语法,但 TS 仍能解析此类文件。

// Input
let a!;

// Prettier 2.5
let a;

// Prettier 2.6
let a!;

为元组类型中的剩余元素添加尾部逗号 (#12390 by @sosukesuzuki)

TypeScript 4.2 起,元组类型中的剩余元素(...T)后允许出现普通元素。为保持一致性并减少未来在末尾元素后添加新元素时的差异,Prettier 现在会为尾部剩余元素添加尾部逗号(启用尾部逗号时)。

// { trailingCommma: "all" }

// Input
type Foo = [
Element,
Element,
Element,
Element,
Element,
Element,
...RestElement,
];


// Prettier 2.5
type Foo = [
Element,
Element,
Element,
Element,
Element,
Element,
...RestElement
];


// Prettier 2.6
type Foo = [
Element,
Element,
Element,
Element,
Element,
Element,
...RestElement,
];

Flow

修复 Flow 类声明中 static 索引器的格式化问题 (#12009 by @gkz)

// Input
declare class A {
static [string]: boolean;
}

// Prettier 2.5
declare class A {
[string]: boolean;
}

// Prettier 2.6
declare class A {
static [string]: boolean;
}

CSS

保留 SCSS 映射中的空行 (#12210 by @duailibe)

此更改同样适用于具有类似语法的一些 PostCSS 功能。

/* Input */
$colours: (
"text": $light-100,

"background-primary": $dark-300,
"background-secondary": $dark-200,
"background-tertiary": $dark-100
);

/* Prettier 2.5 */
$colours: (
"text": $light-100,
"background-primary": $dark-300,
"background-secondary": $dark-200,
"background-tertiary": $dark-100
);

/* Prettier 2.6 */
$colours: (
"text": $light-100,

"background-primary": $dark-300,
"background-secondary": $dark-200,
"background-tertiary": $dark-100
);

修复 postcss 值的小写转换问题 (#12393 by @niklasvatn)

PostCSS 的值可以以数字开头。在下面的示例中,Prettier 会将其解释为一个数字后跟一个单位。

// Input
@value 4XLarge 28/36px;

.test {
font: 4XLarge Helvetica;
}

// Prettier 2.5
@value 4XLarge 28/36px;

.test {
font: 4xlarge Helvetica;
}

// Prettier 2.6
@value 4XLarge 28/36px;

.test {
font: 4XLarge Helvetica;
}

SCSS

修复映射内的注释 (#11920 by @fisker)

// Input
.ag-theme-balham {
@include ag-theme-balham(
(
foreground-color: $custom-foreground-color,
disabled-foreground-color: null, // TODO some comment
)
);
}

// Prettier 2.5
.ag-theme-balham {
@include ag-theme-balham(
(
foreground-color: $custom-foreground-color,
disabled-foreground-color: null,
r: null, // TODO som
)
);
}

// Prettier 2.6
.ag-theme-balham {
@include ag-theme-balham(
(
foreground-color: $custom-foreground-color,
disabled-foreground-color: null,
// TODO some comment
)
);
}

修复名为 selector() 的 mixin 的参数打印问题 (#12213 by @duailibe)

/* Input */
@mixin selector($param: 'value') {
}

/* Prettier 2.5 */
@mixin selector($param: 'value) {
}

/* Prettier 2.6 */
@mixin selector($param: 'value') {
}

Vue

修复无效 v-for 导致的挂起问题 (#12113 by @fisker)

// Input
<template>
<div>
<div v-for=" a in ">aaaaa</div>
</div>
</template>

// Prettier 2.5
// Hangs

// Prettier 2.6
<template>
<div>
<div v-for=" a in ">aaaaa</div>
</div>
</template>;

允许 <template>lang 属性为空 (#12394 by @HallvardMM)

模板标签应允许空字符串 lang="" 或未定义的 lang

<!-- Input -->
<template lang="">
<v-app-bar>
<v-menu offset-y>
<template></template>
</v-menu>
</v-app-bar>
</template>

<template lang>
<v-app-bar>
<v-menu offset-y>
<template></template>
</v-menu>
</v-app-bar>
</template>

<!-- Prettier 2.5 -->
SyntaxError: Unexpected closing tag "v-menu". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags (5:5)
[error] 3 | <v-menu offset-y>
[error] 4 | <template></template>
[error] > 5 | </v-menu>
[error] | ^^^^^^^^^
[error] 6 | </v-app-bar>
[error] 7 | </template>

<!-- Prettier 2.6 -->
<template lang="">
<v-app-bar>
<v-menu offset-y>
<template></template>
</v-menu>
</v-app-bar>
</template>

<template lang>
<v-app-bar>
<v-menu offset-y>
<template></template>
</v-menu>
</v-app-bar>
</template>

Ember / Handlebars

正确识别 glimmer 移除了哪些反斜杠 (#12302 by @MattTheNub)

这导致 Prettier 在每次格式化文件时都会不必要地添加反斜杠。

{{! Input }}
<p>\</p>
<p>\\</p>
<p>\\\</p>

{{! Prettier 2.5 }}
<p>\\</p>
<p>\\\</p>
<p>\\\\</p>

{{! Prettier 2.6 }}
<p>\</p>
<p>\\</p>
<p>\\\</p>

GraphQL

在 GraphQL 模式定义节点上打印描述 (#11901 by @trevor-scheer)

# Input
"""SchemaDefinition description is lost"""
schema {
query: Query
}

# Prettier 2.5
schema {
query: Query
}

# Prettier 2.6
"""
SchemaDefinition description is lost
"""
schema {
query: Query
}

YAML

修复意外删除以 U+3000 开头的块文字行的问题 (#12305 by @Quramy)

# Input
block_with_ideographic_space: |
 line-content # This line starts with U+3000

# Prettier 2.5
block_with_ideographic_space: |

// Prettier 2.6
block_with_ideographic_space: |
 line-content # This line starts with U+3000

CLI

新增 --no-plugin-search 选项以关闭插件自动加载 (#10274 by @fisker)

要关闭插件自动加载,在使用 Prettier CLI 时使用 --no-plugin-search 选项,或在 prettier.format() 的选项中或配置文件中添加 { pluginSearchDirs: false }

// Prettier 2.5
$ prettier . --plugin-search-dir=a-dir-without-plugins

// Prettier 2.6
$ prettier . --no-plugin-search

.swcrc 推断解析器 (#12320 by @sosukesuzuki)

.swcrc 文件格式化为 JSON 文件。

其他改进

切换到 esbuild (#12055 by @fisker)

我们已将构建流程从 Rollup 切换至 esbuild。esbuild 速度显著提升,大幅优化了我们的开发体验。这是一项内部变更,不应影响用户。如果您在升级后遇到任何问题,请提交 issue