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.
Highlights
HTML
#5596 by @ikatyang)
Respect surrounding linebreaks (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.
<!-- 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
#5494 by @ikatyang)
Better CRLF handling (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
#5608 by @j-f1)
Improve the pattern used by React hooks (// 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
parser to babel
(#5647 by @wuweiweiwu)
Rename 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.
Flow
babel-flow
parser (#5685 by @ikatyang)
Add 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.
// 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
flag (#5629 by @kachkaev)
Add a 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.
# 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?
Other changes
General
#5632 by @lhchavez)
Fix unexpected formatting caused by range format (// 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
field of format options (#5763 by @Kingwl)
Allow plugin instances to be passed in the 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.
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()
call in the standalone bundle (#5612 by @j-f1)
Remove the dynamic 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
//
in TSX (#5728 by @JamesHenry)
Correctly handle 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.
// 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>;
#5724 by @flurmbo)
Remove redundant parentheses around type annotations (// Input
class Foo {
bar: (() => boolean);
}
// Output (Prettier 1.15)
class Foo {
bar: (() => boolean);
}
// Output (Prettier 1.16)
class Foo {
bar: () => boolean;
}
JavaScript
something.connect()
as functional composition (#5739 by @makepost)
Do not treat 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.
// 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);
#5637 by @existentialism)
Add support for class private methods (// Input
class Hello {
#world() {}
}
// Output (Prettier 1.15)
// SyntaxError
// Output (Prettier 1.16)
class Hello {
#world() {}
}
#5607 by @ikatyang)
Correct indentation for expressions in root template (// 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
`;
}
#5771 by @ikatyang)
Remove unnecessary linebreaks from HTML template literals (// 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 */
templates (#5658 by @ikatyang)
Correctly recognize 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.
CSS
#5710 by @jsnajdr)
Fix broken output for lists caused by comments (// 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;
#5597 by @sh7dm)
Correctly handle backslashes (// 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
#5704 by @ikatyang)
Correctly handle inline html (<!-- 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
#5642 by @ikatyang)
Format script with type "application/ld+json" (<!-- 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
files as HTML (#5505 by @n1ru4l)
Treat 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.
#5590 by @ikatyang)
Smart quote for attributes (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.
<!-- 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
#5606 by @ikatyang)
Tag names are case-sensitive (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.
<!-- Input -->
<template>
<Input></Input>
</template>
<!-- Output (Prettier 1.15) -->
<!-- SyntaxError -->
<!-- Output (Prettier 1.16) -->
<template>
<Input></Input>
</template>
Vue/Angular
}}
in interpolations (#5657 by @ikatyang)
Add parentheses to avoid unexpected }}
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.
<!-- 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>