prettier: Linebreaks weirdly in long ES6 template strings with expressions
Prettier 1.8.2 Playground link
# Options (if any):
--print-width=80
Input:
class Quote {
character = {
name: 'Dorian'
}
text = `Yes, ${this.character.name}, you will always be fond of me. I represent to you all the sins you have never had the courage to commit.`
}
Output:
class Quote {
character = {
name: "Dorian"
};
text = `Yes, ${
this.character.name
}, you will always be fond of me. I represent to you all the sins you have never had the courage to commit.`;
}
Expected behavior:
I would prefer a long string to not get split into multiple lines, even if it contains expressions. When there are no expressions, Prettier correctly lets a long string go beyond the print-width
limit.
I can’t decide if this is a bug or a personal preference, but it’s been creating weird hard to read code in our codebase. We can clean most of it up by simplifying our expressions, but there’s only so short we can go.
About this issue
- Original URL
- State: open
- Created 7 years ago
- Reactions: 157
- Comments: 99 (27 by maintainers)
I’d say a lot of people, including myself, could dig an option that reverts to previous behaviour i.e. rule to disable formatting template literals completely e.g. ignoreTemplateLiterals: true.
Does this exist already? Any reason this would be a problem?
Can we just have an option to NOT format template strings?
I think that is a simple solution to something that a lot of people have very different opinions about and is very difficult to put together a good heuristic around
@duailibe: Sure, I’ve got lots of time right now so I’ll make a big list of before/afters.
I went out and took a bunch of template literals from MDN, CSS-Tricks, and the lit-html repo.
It appears to me that the heuristic to use to get the best formatting is:
Playground Link with examples and current output
most of the time I log, I apply format functions to the content:
which ends up as
undesirable, IMO. I’d rather have template literals left untouched. It should probably be an option:
Personally I am of the opinion that a template string, regardless of what’s in there, is a single expression. People putting too much logic in there is an antipattern and almost always leads to a mess.
Discouraging messes is the job of a linter, not a formatter, if I’m not mistaken. Maybe a good way to approach this is to have people vote on whether they perceive complex string templates as one expression or more?
On Wed, Dec 6, 2017 at 6:33 AM Lipis notifications@github.com wrote:
I cannot understand why someone would want a template literal such that
this is unambiguously ridiculous. i am comfortable saying that 99% of devs would never want this in their codebase. set your word wrap on your text editor and call it a day.
Sadly, despite the “great demand” from the community, the PR #12505 isn’t approved. This is still one thing from Prettier that bugs me. Template literals are just that: literals.
If a person doesn’t intend to add a newline in a template literal, then, maybe, it should look like there’s no new line, no? Or maybe at least give us a choice. Forcing to use concatenation instead of template literals for really long string also isn’t always readable.
Despite what you said in the Option Philosophy, I just can hope you’d consider reopening that PR 🙏
OMG, I think many people including me still feel pain from the backtick problem.
Shouldn’t Prettier make code prettier?
I definitely think that template literals should be treated as one holistic expressions and their contents should never be altered.
A travesty of formatting
(Github displaying tabs as 8 spaces is also a travesty)
To be fair, a string like this is already rather bad in terms of readability. Prettier’s template logic certainly makes it worse, but this is not a good starting point either.
Ok thanks I know the options must remain very simple. So then I’d suggest not trying to line-break template literals on their expressions by default. And thanks again for this tool
I think those cases we shouldn’t brake at all…
and consider that a single expression
while this one is not:
Just wanted to chime in here with more support for adding this option.
I am also generally in the camp of less options are better, just give me a reasonable format and don’t make me think about it, which is why I love prettier!
But the line splitting on template literals really drives me nuts. It almost always makes the code harder to read and understand. I would really appreciate an option for this behavior!
@suchipi That’s the same behaviour as when this was posted back in v1.8.2. I’m the same as OP—I pretty much never want template literals to wrap.
I understand the opinionatedness of Prettier, but if the idea is to remove the need to think about the code formatting, then wrapping template literals goes against that. I have to think much harder about this:
than I do about this:
To get around this, I would have to define three extra variables, even if they only get used this one time. That’s not something that will get optimized away in a minifier/webpack.
What determines whether there should be an option for preferences like this?
@j-f1: Unfortunately, and it pains me to say this to that example, yes; I would leave that alone.
The copout answer is because nobody would write something like that, but really, I believe the contents of Template Strings/Literals/Expressions to be intentionally formatted by the author when they’re written.
An ideal answer might be to leave the expression location alone, but format them as if it is a standalone line. This way the contents get formatted and made pretty, but the braces aren’t broken apart.
Maybe an even simpler answer is to not allow line breaks when formatting template expressions.
I would agree… maybe it makes sense to not break them at all…
Hey everyone. Prettier is a great tool, but the template literal formatting issue has just gone from “mild annoyance” to total blocker for me. I’ve created a DSL around tagged template literals (the code below is simplified for readability):
If those
route
entries get long enough, prettier starts to wrap them, and the result is unreadable (again, the code below is simplified to get the point across):Good luck making any sense of that!
I tried to go through this issue and related ones and it seems like the stance of the prettier team is:
Is that an accurate summary? If so, does anyone even have the start of an idea for how (3) would work given the huge variety of use cases with template literals, and especially tagged template literals, which are likely to become more and more common? If not, then would the team be open to revisiting either (1) or (2)?
On a slightly unrelated note, I’ll also mention that there doesn’t seem to be a way to disable prettier on blocks of JS/TS code, so right now, my only options are (a) put
// prettier-ignore
before every singleroute
or (b) don’t use prettier.@thorn0 The tslint rule for prefer template strings marks plain concatenation as undesirable/needs fixing. Until now that rule had worked hand-in-hand nicely with prettier.
It’s only the change in prettier to ignore the printWidth entirely for template strings that now makes it a problem - the template strings used to be readable but now are being formatted in a manner that makes no sense given the content of the template string. Sure, changing them all to simple concatenation now would be more readable than what prettier is creating - but that’s because prettier is ignoring its other settings entirely and mashing everything into a single line regardless of what the final length would be even in situations when doing that is clearly unsuitable.
Please read the issue https://github.com/prettier/prettier/issues/6192 and https://github.com/prettier/prettier/issues/6262 for a decision.
Take a look to this image:
Demo
It’s about separating code and text. And not crossing the line limit. Vertical scrolling during development and reviewing should be avoided. Prettier should format this string like other nodes. For example arrays. If an array fits the line width it is formatted in a single line. When you add a new item which will overflow the line width, it will be formatted in multilines by wrapping each item. This is prettier in my opinion.
But please take a look to the other threads / issue (see links above in this post), before you reject this proposal. This is maybe only solvable by an option to match the different tastes and opinions. But I hope we all agree that my example above (image / demo) like Prettier currently formats the template stings can be very ugly.
Here is a demo I converted the literal template string to a default string. And you see that the behavior is equal like I described. Warum sollte Prettier template strings anders behandeln? This is not prettier.
Here you can see the demo as screenshot. It demonstrates how Prettier formats concatenated strings. Is an expected behavior. Only the template strings are formatted in a different way. Why?
I opened #5979 to introduce the concept of a “simple” template literal that prints with infinite width. The heuristic just covers identifiers and member access expressions to start.
The job of a formatter is to format the code, whether or not it’s a mess, trying its best to output code that looks consistent. I don’t think we should be in charge of encouraging or discouraging any pattern.
Don’t get me wrong, I would love if people wrote code in specific styles… that would make the job of a formatter a whole lot simpler, but that’s not what we’ve noticed out there in codebases, both smaller and bigger ones.
As for the formatting issue, prettier used to not format template literals at all, but people complained code wasn’t getting formatted. Then it started formatting but using
removeLines
to remove breaks which would output${a.b.c.d.e}
in a single line, but would break other more complex cases, with function calls and object expressions inside.I see what we have today as a good compromise but I agree “simple” cases could get better. The whole point is deciding what is simple and have a sane way to format those cases without adding too much complexity to the code.
See #2046, #1893, #1662, #1626, #821, #1183 (and there’s more 😃) for more context on this issue.
In version 3.2.0, Prettier incorporates the heuristic I suggested in my previous comment: it will no longer add linebreaks to interpolations in template literals unless there is already one present. So if you want to keep the whole string on a single line, just write it that way, and Prettier will respect that. (It will still format the interpolations as normal, just effectively with infinite
printWidth
).This won’t make everyone happy, but I hope it’s an improvement for most people in this thread.
@shamilovtim Hey, if you set a high value for your print width my proposal will not annoy you. Now again, I am not sure if you have fully understood my proposal. Ok, maybe you want a small print width for the other stuff to keep it clean, but not for the template string, right? That’s a bit contradictory. But ok, it’s your opinion about this. If you want to fill your full screen, you should write all your code (nodes) in a single line. I’ll suggest
overflow-x: hidden
for VS Code. Hehe. 😉 Keep in mind that maybe you have two code windows side by side. (Also with multiple monitors).Again, an option could be the correct way. To respect the print width or not.
Respect the print width will result in this:
Disabled the option will result this (may cause more vertical overflow / scroll and maybe linter issues.):
(Look at the print width line / ruler.)
Note that Prettier formats a concat string similar as my proposal:
So my proposal is just a request to handle template string like all other nodes like concat string, array, etc. formatted by Prettier. Only the template string steps out of line. Looks like Prettier breaks its rules.
to back up my point that if it’s bad code at 50 characters, it’s bad code at 100 characters. line 7 is a 128 long column all on one line with prettier.
Under your proposal I would get the following result:
or maybe it would break my string somewhere else. either way, it would look like a function parameter and obscure the meaning of my code. you have a setting in your code editor for word wrap if you have a problem with this, which is completely compatible with the way prettier treats this now. i’m not sure why instead you’d prefer your preference to be inserted into my code rather than changing a setting in your editor.
#5979 has been merged! 🙌
There’s more discussion to be had about what constitutes a ‘simple’ template string, but this will solve 80% of the situations outlined in @JonathanWolfe’s original proposed solution
It’s been a month since @JonathanWolfe’s suggestion and a few thumbsups on the post. How do we keep it moving? Someone want to do a PR?
Here’s a heuristic I haven’t seen proposed which I think would make ~everyone happy:
Only add linebreaks to an interpolation if there’s already a linebreak within the interpolation.
This is similar to how an object expression will get put on multiple lines only if it exceeds print width or contains linebreaks, just with an “and” instead of an “or”.
That way if you have a complex interpolation which you want prettier to break up for you, you can put a linebreak in. And if you don’t want it broken up - for example, if you wrote the whole template on one line - then prettier will leave it alone.
Thoughts? I’m happy to try a PR if this sounds good.
I think that printWidth should still be respected for “simple” cases in some circumstances.
We have one template string that is providing an error message with multiple fields that represent a data key, and were using typescript/tslint with ‘prefer template strings’. Previously the template string was separated onto 5 lines, and fairly readable. With prettier 1.19.1 it’s condensed into a single line that is 316 characters long - with a print width of 120 characters. I can understand the argument for exceeding the print width by a moderate amount in order to keep the template string together, but almost tripling the print width is arguably taking that too far.
Can I suggest at least putting in a heuristic where if the printWidth is exceeded by too much - e.g. more than 50% - then even the simple template strings should be wrapped?
vs.
using my theme (shameless plug 🙊)
@hermann-punk Please share the code that is unreadable now. There won’t be an option for this, but we can make it better
People who commented here, can you try out the playground with @jwbay’s changes here (https://deploy-preview-5979--prettier.netlify.com/playground/) and report what are the cases Prettier still doesn’t format correctly?
Thank you in advance for the cooperation
Just ran into this myself today… definitely not the formatting I was looking for!
Since formatting template literals is pretty tricky I second @caub opinion. Perhaps they shouldn’t be formatted at all if they exceed the printWidth?
Sorry, I just meant my previous comment, about having something like a
ignoreTemplateLiterals
config option to avoid formatting them, even if they exceedprintWidth
A PR exploring ways to improve the oh-so-tricky-to-format template literals would certainly be up for discussion 👍
With simple template strings seems now works well, but if template contains function - Prettier breaks it to several string, here is modified previous example: String with template, containing function
Is this fixable with current version using some configuration options, or maybe some workaround exists?
@shamilovtim You ignores the print width. And no one should scroll vertically. I don’t even wish that to my enemies. 😉 Your first screenshot is resized here. 😄
@evilebottnawi Of course. I would do it with pleasure. But this is just yet in the discussion state. And I don’t like rejected pull-requests. 😃 (Waste of work) And currenlty It sounds like rejection. (unjustifiably) It looks more like a bug. But here it is discussed if we should keep this bug. Weird.
And btw. My wanted format behavior was already implemented before. It was removed. We should just revert it or add an option. (see #6262) (I have not yet checked if this is exactly my desired behavior.)
I started using prettier, liked it a lot, and then found all my template expressions broken up into pieces, making them unreadable. There really needs to be an option to disable this.
@opennota A config option is off the table.
@nlenkowski We do want to improve how they’re printed though, see my response below.
@caub I agree. It’s not impossible, it’s just difficult as the printer will occasionally break the nodes inside the expressions (i.e. a very long member chain will naturally break) and we need a way to print them all differently when inside a template expression.
There are ways to achieve that: we could add some
if
s to check if it’s inside a template expression but we’d have to add a lot of those, make sure we covered all possible nodes and new changes to the formatter would also have to take into account how they would print if inside a template expression.My point is, we just haven’t found a solution for this problem yet.
We won’t do that; please read https://prettier.io/docs/en/option-philosophy.html for more info.
I think with template literal, it shouldn’t try to respect
printWidth
at all (leaving it manual), or with a configuration option for this as template literal are more and more importantOther example https://prettier.io/playground/#N4Igxg9gdgLgprEAuc0DOMAEAzCFMC8mABgBZoA2AhgBQAkwAslTKQHQBOEArlACY1SASgC+AGgbNWnHvxppMAKkwBGAAxrRAUglMW7LrwEUlqjdt0QADlTABLGAE8RQ4gG4QYkNZh30yUCoOLgB3AAUghDRkECoANwg7Pk9YjGRsKgo0OC8AIw5bAGs4GABlG3soAHNkGA5uHJA+CDB0zOyvOyhsjhgwgqqAWyo2rMaAKzQADwAhArBisqpBuAAZLrhRju9uGCtdgCYtxpsOHpjcqlzHCmgUqw4umAB1JNZkAA41LweIbOeClYYg84D04psvBw4ABHbh2KH9KhDEZIDJjLzZQZ2Wr1RpoLpVChwACK3Ag8GOXhgV1efHeSAOVIKdgoBIAwhBBsMYlBoBCQNxsgAVK7RVHtOAiERAA
Just adding my name to the people who expect better handling of template literals.
Yeah, put my in the camp of adding configuration for this. I really dislike the way this is handled.
Found this discussion because I would also like to see this option.
my print width for prettier is about 120 (50% of my screen) which i think is very reasonable. and the literal i have there on line 7 only breaks it by about 8 characters. i don’t mind the param being on a separate line, because both params are being treated equally. it’s only once you start treating string literals like params that i have a problem because it’s competing with my params for visual meaning. if my string wrapped i’d say so be it. the whole thing would be green in my screenshot, i wouldn’t be seeing “originalFee” wrapped down in its lexical color two times like it’s a parameter. in my color theme i treat literal syntax highlighting like Monokai does and i’m sure you understand how popular Monokai is with people. this would obfuscate code for thousands of people. if i had to change the syntax highlighting of literals just for prettier i’d say prettier is doing something wrong.
sorry for all the chatter on here.
@shamilovtim Nope, you just don’t understand it. The string you posted will be formatted by my proposal like:
(unless your double space, I corrected.)
Ask before downrate. It’s about breaking on line width limit. But anyway, I have already written it: It looks like this is only solvable by an option so that everyone is satisfied. I cannot understand why someone would want a 1000 and more long string in one line.
btw. your code snippet above is really ugly formatted. (This is just manipulative.)
How about increasing the printWidth while the printer is inside a template string (e.g. printWidth + 40 or some other constant)? This way, really long template strings will still get breaks (which makes sense IMO) but shorter template strings don’t break too easily. Not sure if it’s easier to implement compared to what @duailibe described but it could strike a nice balance between readability and too long lines. Also 80 + 40 = 120 looks like a nice default for something like this.
@nlenkowski This is not an option as we’re not interested in regressing from previous developments. As mentioned before in this very thread, Prettier used to not format the expressions and only started because it was very much requested.
@caub I don’t see your proposal, could you post a link to it?
@lachieh we aren’t satisfied with this output either, but template literal strings have been a somewhat difficult thing to get right. At one point in the past we removed all newlines and it broke some things (like styled-components). I’d be open to changing the current formatting rules to be more inclusive for which things should not break; I don’t think there’s a need for an option here (and I would prefer not having one).
@JonathanWolfe Would you agree that this should not be formatted?
(that’s valid JS)
As we’ll focus the discussion on this issue, I’ll copy my comment from the other thread (cc @lipis):
The thing about template literals is without breaking between
{
and}
we were actually printing:which IMO are strictly worse than what we’re printing right now. Note the
foo.bar
andfoo[bar]
are a group with “break points”, meaning that if they don’t fit in one line, they will break. We’d need to special case printing MemberExpressions when inside a template literal so this wouldn’t happen.The other problem with this is when should and shouldn’t break in those cases:
Until we can find an heurisitic that’s good enough to decide on those cases, it’s better to keep consistent that always breaks.