609 lines
15 KiB
Markdown
609 lines
15 KiB
Markdown
---
|
||
author: Ika (@ikatyang)
|
||
authorURL: https://github.com/ikatyang
|
||
title: "Prettier 1.16: HTML improvements and better CRLF handling"
|
||
---
|
||
|
||
This release improves HTML formatting and contains better CRLF handling, new
|
||
syntax features, and fixes several bugs.
|
||
|
||
<!--truncate-->
|
||
|
||
## Highlights
|
||
|
||
### HTML
|
||
|
||
#### Respect surrounding linebreaks ([#5596] by [@ikatyang])
|
||
|
||
Previously, Prettier always put elements in a single line if they didn’t
|
||
go past the `printWidth`, but this doesn’t work for elements that are used as
|
||
`if`-`else` blocks or are intended to contain several items. To solve this
|
||
problem, we’ll respect surrounding linebreaks for all elements since there is
|
||
no reliable way to determine if they’re being used in these ways.
|
||
|
||
<!-- prettier-ignore -->
|
||
```html
|
||
<!-- 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>
|
||
```
|
||
|
||
### General
|
||
|
||
#### Better CRLF handling ([#5494] by [@ikatyang])
|
||
|
||
You might have noticed a few weird formatting issues that only occurred on Windows.
|
||
Many of these issues were caused by our handling of CR-LF line endings.
|
||
In this release, we were able to resolve these issues by normalizing linebreaks
|
||
both before and after formatting.
|
||
|
||
### JavaScript
|
||
|
||
#### Improve the pattern used by React hooks ([#5608] by [@j-f1])
|
||
|
||
<!-- prettier-ignore -->
|
||
```js
|
||
// 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]);
|
||
}
|
||
```
|
||
|
||
#### Rename `babylon` parser to `babel` ([#5647] by [@wuweiweiwu])
|
||
|
||
Babel’s parser, `babylon`, was renamed to `@babel/parser` in Babel 7. We’ve
|
||
renamed our `babylon` parser to `babel` as well to reduce confusion.
|
||
|
||
The `babylon` parser name is now deprecated but it still works.
|
||
|
||
If you need to change your config due to this change, please take a second to read
|
||
[our docs on the `parser` option], especially the note at the bottom.
|
||
|
||
[our docs on the `parser` option]: https://prettier.io/docs/en/configuration.html#setting-the-parser-docs-en-optionshtml-parser-option
|
||
|
||
### Flow
|
||
|
||
#### Add `babel-flow` parser ([#5685] by [@ikatyang])
|
||
|
||
Both the `babel` and `flow` parsers support Flow syntax by default, but there are a few
|
||
edge cases where Flow syntax is ambiguous. By default, Babel’s Flow parser will parse the
|
||
ambiguous code as regular JS, while the native Flow parser will parse it as Flow syntax.
|
||
To address this issue, we added the `babel-flow` parser option, which uses Babel’s parser,
|
||
but prefers Flow syntax when ambiguities arise.
|
||
|
||
<!-- prettier-ignore -->
|
||
```js
|
||
// 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
|
||
|
||
#### Add a `--check` flag ([#5629] by [@kachkaev])
|
||
|
||
Passing `--list-different` to the `prettier` CLI command will cause Prettier to
|
||
exit with an error code if one or more of the files passed to it has not been
|
||
formatted with Prettier. This works great, but it doesn’t provide any information
|
||
in the output except for the files which aren’t properly formatted. This isn’t
|
||
very friendly for new contributors and users in general, so we added a `--check`
|
||
option that produces more human-friendly output.
|
||
|
||
<code style="display: block; background: #282a36; color: #f1f1f0">
|
||
<span style="color: #686868"># Prettier 1.15</span><br />
|
||
$ <span style="color: #5af78e">prettier</span> <span style="color: #57c7ff">\*.js</span> --list-different<br />
|
||
unformatted.js<br />
|
||
<br />
|
||
<span style="color: #686868"># Prettier 1.16</span><br />
|
||
$ <span style="color: #5af78e">prettier</span> <span style="color: #57c7ff">\*.js</span> --check<br />
|
||
Checking formatting...<br />
|
||
unformatted.js<br />
|
||
Code style issues found in the above file(s). Forgot to run Prettier?<br />
|
||
</code>
|
||
|
||
## Other changes
|
||
|
||
### General
|
||
|
||
#### Fix unexpected formatting caused by range format ([#5632] by [@lhchavez])
|
||
|
||
<!-- prettier-ignore -->
|
||
```js
|
||
// 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
|
||
|
||
#### Allow plugin instances to be passed in the `plugins` field of format options ([#5763] by [@Kingwl])
|
||
|
||
Previously, plugin instances were somehow disallowed to be passed in the
|
||
`plugins` field of format options but it should be allowed. We've fixed this
|
||
issue in Prettier 1.16.
|
||
|
||
```js
|
||
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
|
||
|
||
#### Remove the dynamic `require()` call in the standalone bundle ([#5612] by [@j-f1])
|
||
|
||
Previously, a dynamic `require()` call was present in the `standalone.js` file designed
|
||
for usage in browsers. It was used in a way where it wasn’t actually called, but
|
||
tools like webpack to throw a warning. We adjusted the build script to remove
|
||
this `require()` call in the standalone bundle in Prettier 1.16.
|
||
|
||
### TypeScript
|
||
|
||
#### Correctly handle `//` in TSX ([#5728] by [@JamesHenry])
|
||
|
||
Previously, putting `//` as a child of a JSX element in TypeScript led to an error
|
||
because it was interpreted as a comment. Prettier 1.16 fixes this issue.
|
||
|
||
<!-- prettier-ignore -->
|
||
```js
|
||
// 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>;
|
||
```
|
||
|
||
#### Remove redundant parentheses around type annotations ([#5724] by [@flurmbo])
|
||
|
||
<!-- prettier-ignore -->
|
||
```js
|
||
// Input
|
||
class Foo {
|
||
bar: (() => boolean);
|
||
}
|
||
|
||
// Output (Prettier 1.15)
|
||
class Foo {
|
||
bar: (() => boolean);
|
||
}
|
||
|
||
// Output (Prettier 1.16)
|
||
class Foo {
|
||
bar: () => boolean;
|
||
}
|
||
```
|
||
|
||
### JavaScript
|
||
|
||
#### Do not treat `something.connect()` as functional composition ([#5739] by [@makepost])
|
||
|
||
A special format for `connect()` calls was introduced to improve formatting of Redux
|
||
several versions ago, but there are many other uses for functions named `connect` that
|
||
shouldn’t be formatted that way. Since most of these cases involved a `connect` method,
|
||
we no longer treat `foo.connect()` calls as functional composition.
|
||
|
||
<!-- prettier-ignore -->
|
||
```js
|
||
// 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);
|
||
```
|
||
|
||
#### Add support for class private methods ([#5637] by [@existentialism])
|
||
|
||
```js
|
||
// Input
|
||
class Hello {
|
||
#world() {}
|
||
}
|
||
|
||
// Output (Prettier 1.15)
|
||
// SyntaxError
|
||
|
||
// Output (Prettier 1.16)
|
||
class Hello {
|
||
#world() {}
|
||
}
|
||
```
|
||
|
||
#### Correct indentation for expressions in root template ([#5607] by [@ikatyang])
|
||
|
||
<!-- prettier-ignore -->
|
||
```js
|
||
// 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
|
||
`;
|
||
}
|
||
```
|
||
|
||
#### Remove unnecessary linebreaks from HTML template literals ([#5771] by [@ikatyang])
|
||
|
||
<!-- prettier-ignore -->
|
||
```js
|
||
// 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
|
||
|
||
#### Correctly recognize `/* HTML */` templates ([#5658] by [@ikatyang])
|
||
|
||
We [added support] for HTML template literal formatting using the `/* HTML */` pseudo-tag
|
||
in Prettier 1.15, but due to a bug, it only worked for JavaScript code. We’ve fixed this
|
||
issue in Prettier 1.16.
|
||
|
||
[added support]: https://prettier.io/blog/2018/11/07/1.15.0.html#html-template-literal-in-javascript
|
||
|
||
### CSS
|
||
|
||
#### Fix broken output for lists caused by comments ([#5710] by [@jsnajdr])
|
||
|
||
<!-- prettier-ignore -->
|
||
```scss
|
||
// 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;
|
||
```
|
||
|
||
#### Correctly handle backslashes ([#5597] by [@sh7dm])
|
||
|
||
<!-- prettier-ignore -->
|
||
```less
|
||
// 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
|
||
|
||
#### Correctly handle inline html ([#5704] by [@ikatyang])
|
||
|
||
<!-- prettier-ignore -->
|
||
```md
|
||
<!-- 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
|
||
|
||
#### Format script with type "application/ld+json" ([#5642] by [@ikatyang])
|
||
|
||
<!-- prettier-ignore -->
|
||
```html
|
||
<!-- 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>
|
||
```
|
||
|
||
#### Treat `.mjml` files as HTML ([#5505] by [@n1ru4l])
|
||
|
||
MJML is a markup language that uses the same syntax as HTML. We added the `.mjml`
|
||
file extension to the list of extensions that are recognized as HTML, so Prettier
|
||
will format it.
|
||
|
||
#### Smart quote for attributes ([#5590] by [@ikatyang])
|
||
|
||
Previously, the quotes around HTML attribute values were always printed as double
|
||
quotes. To improve readability, they are now printed as the quote type that results
|
||
in fewer escape characters being required in the string, like we do for other strings.
|
||
|
||
<!-- prettier-ignore -->
|
||
```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
|
||
|
||
#### Tag names are case-sensitive ([#5606] by [@ikatyang])
|
||
|
||
Previously, we lowercased tag names before querying tag definition while
|
||
parsing, which caused `<Input>` component to be recognized as a native `<input>`.
|
||
This would produce a syntax error when `</Input>` was encountered since `<input>`
|
||
is a void element, and void elements can’t have closing elements.
|
||
We’ve fixed this issue in 1.16.
|
||
|
||
<!-- prettier-ignore -->
|
||
```vue
|
||
<!-- Input -->
|
||
<template>
|
||
<Input></Input>
|
||
</template>
|
||
|
||
<!-- Output (Prettier 1.15) -->
|
||
<!-- SyntaxError -->
|
||
|
||
<!-- Output (Prettier 1.16) -->
|
||
<template>
|
||
<Input></Input>
|
||
</template>
|
||
```
|
||
|
||
### Vue/Angular
|
||
|
||
#### Add parentheses to avoid unexpected `}}` in interpolations ([#5657] by [@ikatyang])
|
||
|
||
`}}` is not allowed to be used in a interpolation since it’ll be recognized as the
|
||
end of the interpolation. Prettier 1.15 would sometimes output code that broke this
|
||
rule. Prettier 1.16 now adds parentheses to prevent `}}` from appearing in interpolations.
|
||
|
||
<!-- prettier-ignore -->
|
||
```html
|
||
<!-- 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>
|
||
```
|
||
|
||
[@existentialism]: https://github.com/existentialism
|
||
[@flurmbo]: https://github.com/flurmbo
|
||
[@ikatyang]: https://github.com/ikatyang
|
||
[@j-f1]: https://github.com/j-f1
|
||
[@jameshenry]: https://github.com/JamesHenry
|
||
[@jsnajdr]: https://github.com/jsnajdr
|
||
[@kachkaev]: https://github.com/kachkaev
|
||
[@kingwl]: https://github.com/Kingwl
|
||
[@lhchavez]: https://github.com/lhchavez
|
||
[@makepost]: https://github.com/makepost
|
||
[@n1ru4l]: https://github.com/n1ru4l
|
||
[@sh7dm]: https://github.com/sh7dm
|
||
[@wuweiweiwu]: https://github.com/wuweiweiwu
|
||
[#5494]: https://github.com/prettier/prettier/pull/5494
|
||
[#5505]: https://github.com/prettier/prettier/pull/5505
|
||
[#5590]: https://github.com/prettier/prettier/pull/5590
|
||
[#5596]: https://github.com/prettier/prettier/pull/5596
|
||
[#5597]: https://github.com/prettier/prettier/pull/5597
|
||
[#5606]: https://github.com/prettier/prettier/pull/5606
|
||
[#5607]: https://github.com/prettier/prettier/pull/5607
|
||
[#5608]: https://github.com/prettier/prettier/pull/5608
|
||
[#5612]: https://github.com/prettier/prettier/pull/5612
|
||
[#5629]: https://github.com/prettier/prettier/pull/5629
|
||
[#5632]: https://github.com/prettier/prettier/pull/5632
|
||
[#5637]: https://github.com/prettier/prettier/pull/5637
|
||
[#5642]: https://github.com/prettier/prettier/pull/5642
|
||
[#5647]: https://github.com/prettier/prettier/pull/5647
|
||
[#5657]: https://github.com/prettier/prettier/pull/5657
|
||
[#5658]: https://github.com/prettier/prettier/pull/5658
|
||
[#5685]: https://github.com/prettier/prettier/pull/5685
|
||
[#5704]: https://github.com/prettier/prettier/pull/5704
|
||
[#5710]: https://github.com/prettier/prettier/pull/5710
|
||
[#5724]: https://github.com/prettier/prettier/pull/5724
|
||
[#5728]: https://github.com/prettier/prettier/pull/5728
|
||
[#5739]: https://github.com/prettier/prettier/pull/5739
|
||
[#5763]: https://github.com/prettier/prettier/pull/5763
|
||
[#5771]: https://github.com/prettier/prettier/pull/5771
|