跳至主内容区

Prettier 1.16:HTML 改进与更完善的 CRLF 处理

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

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

本次版本更新改进了 HTML 格式化功能,包含更完善的 CRLF 处理机制、新语法特性以及多个错误修复。

重要更新

HTML

保留外围换行符 (#5596 by @ikatyang)

此前 Prettier 总是将未超过 printWidth 的元素压缩为单行,但这不适用于作为 if-else 逻辑块或包含多项目的元素。为解决此问题,我们将为所有元素保留外围换行符,因为无法可靠判断这些元素的用途场景。

<!-- Input -->
<div class="list">
<div class="item">Jan</div>
</div>
<a v-if="i !== -1" href="#" @click.prevent="select(i)">
{{ i }}
</a>
<span v-else>
<slot name="ellipsis">&hellip;</slot>
</span>

<!-- Output (Prettier 1.15) -->
<div class="list"><div class="item">Jan</div></div>
<a v-if="i !== -1" href="#" @click.prevent="select(i)"> {{ i }} </a>
<span v-else> <slot name="ellipsis">&hellip;</slot> </span>

<!-- Output (Prettier 1.16) -->
<div class="list">
<div class="item">Jan</div>
</div>
<a v-if="i !== -1" href="#" @click.prevent="select(i)">
{{ i }}
</a>
<span v-else>
<slot name="ellipsis">&hellip;</slot>
</span>

通用改进

更完善的 CRLF 处理 (#5494 by @ikatyang)

您可能注意到某些仅在 Windows 系统出现的异常格式化问题。这些问题多由 CR-LF 换行符处理不当导致。本次更新通过规范化格式化前后的换行符处理机制,成功解决了这些问题。

JavaScript

优化 React Hooks 使用模式 (#5608 by @j-f1)

// Input
function helloWorld() {
useEffect(() => {
// do something
}, [props.value])
}

// Output (Prettier 1.15)
function helloWorld() {
useEffect(
() => {
// do something
},
[props.value]
);
}

// Output (Prettier 1.16)
function helloWorld() {
useEffect(() => {
// do something
}, [props.value]);
}

babylon 解析器更名为 babel (#5647 by @wuweiweiwu)

Babel 7 将其解析器 babylon 更名为 @babel/parser。为减少混淆,我们也将 babylon 解析器更名为 babel

babylon 解析器名称现已废弃,但仍可继续使用。

若需因此调整配置,请阅读[关于 parser 选项的文档]特别是底部的注意事项。

Flow

新增 babel-flow 解析器 (#5685 by @ikatyang)

babelflow 解析器默认均支持 Flow 语法,但在少数边界情况下 Flow 语法存在歧义。默认情况下,Babel 的 Flow 解析器会将歧义代码解析为常规 JS,而原生 Flow 解析器会将其解析为 Flow 语法。为解决此问题,我们新增了 babel-flow 解析器选项:使用 Babel 解析器,但在歧义场景下优先采用 Flow 语法。

// Input
const Theme = React.createContext<"light" | "dark">("light");

// Output (Prettier 1.15, --parser babylon)
const Theme = (React.createContext < "light") | ("dark" > "light");

// Output (Prettier 1.16, --parser babel-flow)
const Theme = React.createContext<"light" | "dark">("light");

CLI

新增 --check 标志 (#5629 by @kachkaev)

prettier CLI 命令传递 --list-different 参数时,若有文件未通过 Prettier 格式化,Prettier 会返回错误代码。该机制效果良好,但仅输出未规范化的文件列表而不提供其他信息。这对新贡献者和普通用户不够友好,因此我们新增了 --check 选项来生成更人性化的输出。

# Prettier 1.15
$ prettier *.js --list-different
unformatted.js

# Prettier 1.16
$ prettier *.js --check
Checking formatting...
unformatted.js
Code style issues found in the above file(s). Forgot to run Prettier?

其他变更

通用改进

修复范围格式化导致的意外格式变更 (#5632 by @lhchavez)

// Input
something("something", () => {
const something = {
something: [
{
long1: "longlonglonglonglonglonglonglonglonglonglonglong",
long2: "longlonglonglonglonglonglonglonglonglonglonglong",
}
]
};
});

// Output (Prettier 1.15, --range-start 100 --range-end 120)
something("something", () => {
const something = { something: [{ long1: "longlonglonglonglonglonglonglonglonglonglonglong", long2: "longlonglonglonglonglonglonglonglonglonglonglong" }] };
});

// Output (Prettier 1.16, --range-start 100 --range-end 120)
something("something", () => {
const something = {
something: [
{
long1: "longlonglonglonglonglonglonglonglonglonglonglong",
long2: "longlonglonglonglonglonglonglonglonglonglonglong",
}
]
};
});

API

允许在格式化选项的 plugins 字段传递插件实例 (#5763 by @Kingwl)

此前格式化选项的 plugins 字段意外禁止传递插件实例(本应允许)。我们已在 Prettier 1.16 中修复此问题。

const prettier = require("prettier");
const fooPlugin = require("./path/to/foo-plugin");
const formatted = prettier.format("foo-code", {
plugins: [fooPlugin],
parser: "foo-parser",
});
// Prettier 1.15: Error
// Prettier 1.16: No error

Standalone

在独立包中移除动态 require() 调用(由 @j-f1 提交的 #5612

此前,为浏览器环境设计的 standalone.js 文件中存在动态 require() 调用。虽然实际未被执行,但会导致 webpack 等工具发出警告。我们在 Prettier 1.16 中调整了构建脚本,移除了独立包中的这个 require() 调用。

TypeScript

正确处理 TSX 中的 //(由 @JamesHenry 提交的 #5728

此前在 TypeScript 中将 // 作为 JSX 元素的子元素会导致错误(因其被解释为注释)。Prettier 1.16 已修复此问题。

// Input
const link = <a href="example.com">http://example.com</a>

// Output (Prettier 1.15)
// Error: Comment location overlaps with node location

// Output (Prettier 1.16)
const link = <a href="example.com">http://example.com</a>;

移除类型注解周围冗余的括号(由 @flurmbo 提交的 #5724

// Input
class Foo {
bar: (() => boolean);
}

// Output (Prettier 1.15)
class Foo {
bar: (() => boolean);
}

// Output (Prettier 1.16)
class Foo {
bar: () => boolean;
}

JavaScript

不再将 something.connect() 视为函数组合(由 @makepost 提交的 #5739

此前为优化 Redux 格式化引入了针对 connect() 调用的特殊格式,但许多其他场景中名为 connect 的函数不应采用此格式。考虑到大多数情况涉及 connect 方法,我们不再将 foo.connect() 调用视为函数组合。

// Input
app.connect("activate", async () => {
await data.load();
win.show_all();
});
const ConnectedComponent = connect(
bar,
baz
)(foo);

// Output (Prettier 1.15)
app.connect(
"activate",
async () => {
await data.load();
win.show_all();
}
);
const ConnectedComponent = connect(
bar,
baz
)(foo);

// Output (Prettier 1.16)
app.connect("activate", async () => {
await data.load();
win.show_all();
});
const ConnectedComponent = connect(
bar,
baz
)(foo);

支持类私有方法(由 @existentialism 提交的 #5637

// Input
class Hello {
#world() {}
}

// Output (Prettier 1.15)
// SyntaxError

// Output (Prettier 1.16)
class Hello {
#world() {}
}

修正根模板中表达式的缩进(由 @ikatyang 提交的 #5607

// Input
if (a) {
return `
hello
${foo({
bar,
baz
})}
world
`;
}

// Output (Prettier 1.15)
if (a) {
return `
hello
${foo({
bar,
baz
})}
world
`;
}

// Output (Prettier 1.16)
if (a) {
return `
hello
${foo({
bar,
baz
})}
world
`;
}

移除 HTML 模板字面量中不必要的换行(由 @ikatyang 提交的 #5771

// Input
function HelloWorld() {
return html`
<h3>Bar List</h3>
${bars.map(bar => html`
<p>${bar}</p>
`)}
`;
}

// Output (Prettier 1.15)
function HelloWorld() {
return html`
<h3>Bar List</h3>
${
bars.map(
bar => html`
<p>${bar}</p>
`
)
}
`;
}

// Output (Prettier 1.16)
function HelloWorld() {
return html`
<h3>Bar List</h3>
${bars.map(
bar => html`
<p>${bar}</p>
`
)}
`;
}

TypeScript/Flow

正确识别 /* HTML */ 模板(由 @ikatyang 提交的 #5658

我们在 Prettier 1.15 中通过 /* HTML */ 伪标签添加了对 HTML 模板字面量格式化的支持,但因存在缺陷,该功能仅适用于 JavaScript 代码。Prettier 1.16 已修复此问题。

CSS

修复因注释导致的列表输出错误(由 @jsnajdr 提交的 #5710

// Input
$my-list2:
a // a
b
c;

// Output (Prettier 1.15)
$my-list2: a// a
bc;

// Output (Prettier 1.16)
$my-list2: a // a
b c;

正确处理反斜杠(由 @sh7dm 提交的 #5597

// Input
.figcaption {
.margin-top-1\/2;
.large\:none;
}

// Output (Prettier 1.15)
.figcaption {
.margin-top-1\ / 2;
.large\: none;
}

// Output (Prettier 1.16)
.figcaption {
.margin-top-1\/2;
.large\: none;
}

MDX

正确处理行内 HTML(由 @ikatyang 提交的 #5704

<!-- Input -->
| Column 1 | Column 2 |
|---|---|
| Text | <Hello>Text</Hello> |

<!-- Output (Prettier 1.15) -->
<!-- SyntaxError -->

<!-- Output (Prettier 1.16) -->
| Column 1 | Column 2 |
| -------- | ------------------- |
| Text | <Hello>Text</Hello> |

HTML

格式化 type="application/ld+json" 的脚本(由 @ikatyang 提交的 #5642

<!-- Input -->
<script type="application/ld+json">
{ "json":true }
</script>

<!-- Output (Prettier 1.15) -->
<script type="application/ld+json">
{ "json":true }
</script>

<!-- Output (Prettier 1.16) -->
<script type="application/ld+json">
{ "json": true }
</script>

.mjml 文件视为 HTML(由 @n1ru4l 提交的 #5505

MJML 是使用 HTML 相同语法的标记语言。我们已将 .mjml 文件扩展名添加到识别为 HTML 的扩展名列表中,因此 Prettier 会对其进行格式化。

智能处理属性引号(由 @ikatyang 提交的 #5590

此前 HTML 属性值周围的引号始终使用双引号。为提高可读性,现在会采用所需转义字符更少的引号类型(与其他字符串处理逻辑一致)。

<!-- Input -->
<div x='123"456'></div>
<div x="123'456"></div>

<!-- Output (Prettier 1.15) -->
<div x="123&quot;456"></div>
<div x="123'456"></div>

<!-- Output (Prettier 1.16) -->
<div x='123"456'></div>
<div x="123'456"></div>

Vue

标签名称区分大小写(由 @ikatyang 提交的 #5606

此前我们在解析过程中会在查询标签定义前强制小写标签名,导致 <Input> 组件被误识别为原生 <input> 标签。当遇到 </Input> 闭合标签时会产生语法错误——因为 <input> 是空元素,而空元素不能包含闭合标签。该问题已在 1.16 版本修复。

<!-- Input -->
<template>
<Input></Input>
</template>

<!-- Output (Prettier 1.15) -->
<!-- SyntaxError -->

<!-- Output (Prettier 1.16) -->
<template>
<Input></Input>
</template>

Vue/Angular

通过添加括号避免插值中出现意外的 }} (#5657 by @ikatyang)

插值语法中禁止使用 }} 字符组合,因为它会被识别为插值结束符。Prettier 1.15 有时会输出违反此规则的代码。Prettier 1.16 现已通过添加括号来防止插值中出现 }}

<!-- Input -->
<p>{{ foo({ bar: {} }) }}</p>

<!-- First Output (Prettier 1.15, --no-bracket-spacing) -->
<p>{{ foo({bar: {}}) }}</p>

<!-- Second Output (Prettier 1.15, --no-bracket-spacing) -->
<!-- SyntaxError -->

<!-- Output (Prettier 1.16, --no-bracket-spacing) -->
<p>{{ foo({bar: ({})}) }}</p>