Prettier 1.16:HTML 改进与更完善的 CRLF 处理
本页面由 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">…</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">…</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">…</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)
babel 和 flow 解析器默认均支持 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"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>
