Angular, Vue and Ember all use variants of html/mustache with JS and CSS embedded. It would be really awesome to make prettier support it as well. This would allow the project to be the one stop destination for all the front-end related code.
(related to https://github.com/prettier/prettier/issues/1674)
Really wish http://codeguide.co/#html-syntax by @mdo could be enforced, so people can write consistent html:
</li> or </body>).Also, this feels like perfect use case for prettier 😉 :
<foo
class="i have so many classes"
data-really-long-attr="bar"
data-another-long-attr="bar"
></foo>
I don't know specifics for formatting ember/angular, but for Vue SFC, my Vue/VSCode plugin https://github.com/octref/vetur has code that takes each region and send them to respective formatters:
<template>
<!-- send to html formatter -->
</template>
<script lang="ts">
// send to ts formatter
</script>
<style lang="scss">
// send to scss formatter
</style>
Previously I hooked up js-beautify as formatter for script and style regions, but now prettier has TS support so I'm switching over to it for formatting js/ts/css/scss/less.
Once html supports land in prettier, I can make a Vue formatter that takes any Vue file written with html, js/ts, css/less/scss/postcss and outputs consistent code. That is 🔥 🔥 🔥
Will this cover underscore/lodash templates, too? ♥
This would be amazing. Other use case is working in not specifically js related environments such as CMSs that use html styled templates. A tool available to the command line to verify and correct HTML errors could be incredibly useful for processing user input in WYSIWYG HTML fields in CMS fields as well (Unfortunately these still do exist...).
One thing that could help a lot would be a list of acceptable (custom) attributes, though that may beyond the scope of prettier and more appropriate for a linter.
This would allow the project to be the one stop destination for all the front-end related code.
👏👏👏
Just outputting each attribute in a newline would already be amazing for most frameworks like Angular.
@gabrielmaldi yeah exactly, be kinda cool to also hook into the json/js prettifier to also do stuff to the angular 1.X ng-X things.
I ran prettier on 343+ html files and it didn't run in to any exceptions. Spot checking a few of the changes seems to have made reasonable changes. (assuming this is based on the jsx parsing) Should I trust that the changes won't break any code? 😉
Should I trust that the changes won't break any code? 😉
For all the supported languages, we've done extensive testing so it should be a fair assumption. For html, we have done not such thing yet so there's a good chance that it broke something. If you could do a manual review that would be very helpful.
I've spotchecked a few of the files through the diff, and loading some pages and haven't noticed anything breaking, but unfortunately we don't have integration tests for me to run to make sure...
I noticed some extra newlines and I know technically if they were between inline elements that could affect rendering.
Everything SEEEEEMS to be fine, but it's certainly a big risk to take. 🙃
I ran prettier 1.5.3 through 269 HTML files and found a couple of issues:
li element.Example:
+
+
<div class="melilla_step"
ng-class="['melilla_step-' + (mode || 'editable'), { 'melilla_step_product_locked': readonly && mode != 'result', 'disabled': icProductField.isDisabled }]">
<!-- Label above product when loaded -->
- <ng-include src="'directives/icProductField/icProductFieldTitle.html'"></ng-include>
+ <ng-include src="'directives/icProductField/icProductFieldTitle.html'" />
<!-- Product content (loaded) -->
+
<div ng-if="icProductField.model"
class="melilla_step_field_container_content"
ng-class="{ 'melilla_step_field_container_content-fulfilled-on-initial': !readonly }"
select="icProductField.selectProduct()">
+
<ul class="melilla_step_field_container_fulfilled"
ng-class="{ 'melilla_step_required': icProductField.required }">
+
<li class="melilla_step_field_container_product">
<span class="melilla_step_field_container_product_alias">{{ icProductField.model.productAlias }}</span>
</li>
<li class="melilla_step_field_container_product">
- <ng-include src="'directives/icProductField/icProductFieldCurrency.html'"></ng-include>
+ <ng-include src="'directives/icProductField/icProductFieldCurrency.html'" />
+
</li>
<li class="melilla_step_field_container_product">
<span class="melilla_step_field_container_product_number">{{ icProductField.model.productNumber }}</span>
</li>
-
<!-- Display exchange rate conversion -->
+
<li ng-if="icProductField.conversionModel"
class="melilla_step_field_container_product">
- <ng-include src="'directives/icProductField/icProductFieldExchangeRate.html'"></ng-include>
+ <ng-include src="'directives/icProductField/icProductFieldExchangeRate.html'" />
+
</li>
</ul>
</div>
-</div>
+</div>
\ No newline at end of file
Sorry if this is already being looked at in another issue or if I missed something (like formatting goals).
EDIT
I ran prettier again through the same set of already prettified files, and only 13 (out of 269) weren't modified, the rest got "prettified" again.
Example (diff generated by running prettier twice on the same file):
<switch class="melilla_step_switch_control"
is-selected="icSwitch.model"
on-select="toggle()"
- is-disabled="icSwitch.isDisabled" />
-
- <span class="melilla_step_switch_label">{{ getPlaceholderText() }}</span>
+ is-disabled="icSwitch.isDisabled">
+ <span class="melilla_step_switch_label">{{ getPlaceholderText() }}</span>
+ </switch>
</div>
<div ng-class="{ 'melilla_step_locked': mode != 'result' }"
@@ -21,13 +21,13 @@
<div ng-if="!field.model"
class="melilla_step_field_container_confirm_input_value"
- translate="common.no" />
-
-
- <div ng-if="field.model"
- class="melilla_step_field_container_confirm_input_value"
- translate="common.yes" />
+ translate="common.no">
+ <div ng-if="field.model"
+ class="melilla_step_field_container_confirm_input_value"
+ translate="common.yes">
+ </div>
+ </div>
</div>
</div>
</div>
\ No newline at end of file
Thanks
Making empty tags self-closing seems like maybe a feature instead of a bug. But it depends on your framework. Ideal is probably an option, even though we hate options.
My understanding was the the HTML spec for custom elements didn't allow you to create custom self-closing tags and thus many frameworks (like say Angular) don't allow them. Thus I don't think prettier should do this conversion (or if people really want it to it should be an option).
At some point we had to add self-closing tags because without them we had some issues (can't recall exactly what) using AngularJS. I'm in favor of having an opt-in setting for this.
Yeah, angular.js does some funky parsing of the dom tags, and without the closing tags, angular.js just throws a hissy fit.
Personally, we already have the "use semi-colon's or not" option for js, why not have a "closing tags or not" option for html.
Wondering what's the current status on this issue (@azz since it seems you were doing a lot of work for it). From what I gather there is already some support for HTML in 1.5.3, but not without issues as @gabrielmaldi pointed out.
I'm interested in helping moving this forward (or the Vue one https://github.com/prettier/prettier/issues/2097).
I'd appreciate someone giving me a picture as to what has been done, what still needs to be done for release, which issues / part-of-codebase I can start looking into. Thanks!
@vjeux @azz
Hi @octref,
What's done:
Basic HTML support:
parse: https://github.com/prettier/prettier/blob/master/src/parser-parse5.js
print: https://github.com/prettier/prettier/blob/master/src/printer-htmlparser2.js
Basic JS/TS/CSS in HTML support:
multiparser: https://github.com/prettier/prettier/blob/master/src/multiparser.js#L96
What needs to be done:
printJSXElement().Pardon me for asking but could we also validate against / support single file components in https://svelte.technology/
I have no experience with svelte, but if someone wants to build support for it that would be really cool.
Yo guys, you ever heard of https://github.com/reshape/reshape?
Seems pretty solid to me. Same approach as prettier (down to AST -> pretty print). @jescalan did an awesome job there.
Maybe include it instead of reinventing the wheel?
Hi! I wrote reshape, happy to be of assistance in this if I can be. We're using reshape pretty heavily in production and it has been quite stable. Big fan of prettier for javascript and would be honored to be able to contribute in any way.
Hi @jescalan! I had some questions:
How does the reshape AST relate to the parse5 default and htmlparser2 ASTs? Obviously it's been designed to be transformed and reprinted, so that sounds like a perfect match for what we're trying to do here.
How spec-complaint is reshape/parser?
Have you had any experience with integrated parsers like @glimmer/syntax? We'd like to be able to do an initial parse with a full parser and then delegate to an integrated handlebars/mustache/angular/vue/etc parser based on the context of a node. These are often backed by document fragment parsers like simple-html-tokenizer.
Hey @azz!
It's different, but not by much. We strongly considered using htmlparser2 to power the parsing, but it does not include location information with its node, which makes emitting accurate error messages somewhere between difficult and impossible, so we had to drop it. Reshape does use parse5 directly as its parser, but uses its SAX parser transformed into our own AST format in order to support a bit more flexibility that is required in the parsing stage for some things like templating and includes. This leads right into the next point...
Parse5 is extremely spec compliant. To be honest, for reshape's use, this can actually be a negative some of the time. I'd be happy to go into further detail on that if you want later. Parse5 is also very slow. I am toying with the idea of building our own html parser that is a bit looser and therefore allows for situations like embedding template tags into text-only nodes like <title> and <script> -- this is often useful to be able to parse pre-transform, although obviously these nodes need to, and would, come out as text-only. I haven't had time to do so yet, but I do think it would be a benefit to the project, both in terms of speed and flexibility. I wrote my own jade/pug-like whitespace parser which is several times faster than parse5 despite having a much more difficult parsing task calculating the whitespace nesting.
Not at all. I do not use ember in any of my projects, and to be honest I don't really intend to. Most of the deep integrations I have done have been preact, and have gone extremely well, although they might be in an entirely different scope that we're discussing here (reshape ast <> react ast conversions, compiling components to static and rehydrating, etc). I would however be totally happy to learn more about this though, if you'd be willing to go over it with me! Based on what I have seen, there is some great work going on with glimmer, and I'd love to have the opportunity to learn more.
On the topic of self-closing tags: In HTML5 they are actually invalid, unless used for 'void' elements or 'foreign' elements (that being SVG and MathML). This is specified by W3C here.
This in combination with the error handling of standard conform parsers means that the violating tags are treated as normal start-tags and what follows as their content. As there is likely no matching close tag they are then autoclosed at some point. For an example of what that can mean see this fiddle.
This is also why rerunning the html formatting multiple times changes all the files again (as noticed by gabrielmaldi above). Prettier currently outputs self-closing tags which result in a different AST the next time around. It actually changes the semantics of the file.
I am not familiar with the test setup here, but one would need a suite that just verifies that the AST generated by parsing the original file is the same as the AST generated by parsing the generated file. Once that is working we can start figuring out all the gritty details and special template cases of different frameworks.
On the topic of white space: This may be an issue, since there is a style attribute that changes how white space is treated in the display: 'white-space'. This means any change to white space of a text node in a HTML document is potentially breaking and the HTML parser has no way of knowing it. The only ways to handle this I can think of are:
I think numbers 3 and 4 are very much not in the spirit of prettier. In any case, while prettier may change the amount of white space, I think it should not:
These cases can become problematic very quickly, especially when inline elements are involved. Find an example of the subtle but important differences in this fiddle.
@jescalan is there a CLI for Reshape? I'd like to use it in pre-commit hook and reshape my staged files.
@shreyas-a https://github.com/reshape/reshape-cli
Hi, I wrote my own pretty printer for handlebars. It uses the glimmer-vm to parse handlebars into an AST, which is designed to only target HTML that is in the <body>. I'd like to know if the community would like for me to try to make a PR for prettier to support this limited set of handlebars.
I've thought a great deal about the whitespace issues with <pre> and the style attribute associated with it. In handlebars, there is a whitespace control which trims whitespace from the template in-between the whitespace control. This way we could indent as we wanted and the user could put their own whitespace in a string which they're interpolating into the template.
Just one more option to think about!
@azz - thoughts?
Hi, any news?
See #3534
What do you think about this kind of intermediate representation (passed to a JSX+HTML print helper)?
interface Element {
name: Doc
attributes: Attribute[]
children?: Array<Doc|Element>
}
interface Attribute {
name: Doc
value: Doc
}
Example:
<Foo bar={baz}>
<div />
Hello world!
</Foo>
({
name: 'Foo',
attributes: [{
name: 'bar',
value: group([
'{',
indent([softline, 'baz']),
softline,
lineSuffixBoundary,
'}'
])
}],
children: [
{ name: 'div', attributes: [], children: [] },
'Hello',
line,
'world'
]
})
@SimenB when will it be available for the Angular?
No clue, I'm not a part of this project beyond being a user of it :D
Is HTML supposed to work at this point?
I am getting the following error:
index.html
[error] index.html: SyntaxError: Unexpected token (1:2)
[error] > 1 | <!-- htmlhint attr-lowercase: false -->
[error] | ^
[error] 2 | <!DOCTYPE html>
[error] 3 | <html>
[error] 4 |
@ryanpcmcquen No, HTML support is still very experimental.
@j-f1 @vjeux support for Angular inline template also will be?
Time you must wait, as the feature experimental is.
/* eslint yoda: "error" */
@vjeux what about use posthtml? i can do it after finishcss/scss/less basic problem?
How do posthtml and reshape compare?
There’s also rehype.
Is there a work around for using underscore templating with prettier? Saw this mentioned above.
<%= title %>
Gives an 'Unexpected token' error provided by prettier. Not sure how fix error.
@DavidWallJ not at this time. The HTML support is not ready for public use yet.
FYI, Aurelia templates can have non-standard attributes with dots:
Input:
icon.html
<template>
<i class.bind="icon"></i>
</template>
Output:
SyntaxError: Unexpected token on .
Expected response:
No error.
having the same issue as @zakjan but if the parser used is spec compliant this wouldn't be a problem as attributes with dots are valid html
@obedm503 That's because you're parsing the file as JS. In JSX, there cannot be a dot there. It'll work when HTML support is done.
Has anyone started it..? Is there a branch or a way to test the current status?
I think the code lives in master.
In the many comments so far, I saw mentions of the value of Angular support. Along those lines though, there is an important fact to not overlook:
Angular (2+) templates are a very HTML-like language; but they are not exactly HTML. They have different rules around the preservation and meaning of upper/lowercase, and they are consumed by the Angular template compiler, not by the browser. To be maximally useful, Prettier would have support for this HTML like language specifically, in addition to HTML itself.
Just for you to notice, that in Angular aria attributes needs to be binding with a dot access, because they are not properties.
<component>
<i [attr.aria-label]="icon"></i>
</component>
👋 Greetings from the Polymer / Web components world
Polymer 2 templates are written in HTML (not HTML templates in JS, real honest-to-goodness HTML) So this would be super useful for a lot of polymer code bases. Polymer binding expressions use a syntax like:
<my-element
one-way="[[hostPropToChild]]"
two-way="{{hostFromChild}}"
computed="[[computeProp(observedHostProp, otherDependency)]]"
attribute$="[[prop]]"
></my-element>
lit-html and co templates would also benefit from this parsing, as mentioned in https://github.com/prettier/prettier/issues/3548, and future versions of polymer (starting with p3) will do html-in-js, but will still use std html.
Thank you for considering our use cases.
I think we would have to change the compiler to support any html, but as long as it’s html inside of a body tag, it should be fine. Currently I’m a bit too busy to spend the required time to create a patch to support other html like variants, but definitely it’s something worth opening a PR for.
Hi, any news?
@listepo-alterpost try to find time on this in this month, btw you can help us with this
@evilebottnawi how can we help you? 😃
@StefanFeederle yes, prettier https://github.com/prettier/prettier/blob/master/src/language-html/printer-htmlparser2.js, tests https://github.com/prettier/prettier/tree/master/tests/html_basics, just send PR with tests and pretty output
Any news on this issue? I played with most of the HTML beautifiers (posthtml-beautify, reshape, js-beautify, pretty, rehype) and none of them leaves me satisfied on complex AngularJS template files :disappointed:
No significant progress to report
Feedback welcome https://github.com/prettier/prettier/pull/4753
I created a very simple HTML formatter available on npm and as a VS Code Extension if anyone is interested. I made it because I couldn't find a formatter that worked well with Handlebars. It does not make any assumptions about content except for dealing with self-closing tags (to avoid indenting after them) and pre, script and style (to prevent formatting them).
Opened #5259 to address this issue, feedbacks welcome.
I hate to be a stickler because this is a really impressive amount of work but it still doesn't support handlebars / mustache.
I think that was requested in the PR thread, but seems to be a lot of work. I think is because of hard would be to tokenized just { and }, but I ain't sure. @ikatyang provides more inside in the pr.
@robert-j-webb Can you open another issue for handlebars? Thanks!
@michaeljota Yeah, it's https://github.com/prettier/prettier/pull/5259#issuecomment-434168717.
I actually just opened https://github.com/prettier/prettier/issues/5340
@aboyton did no one else from prettier team read your comment? I just updated to prettier 1.15.2 and I get this when I format our angular.js templates:

this totally breaks our angular.js app.
Guess it's back to the old 1.14.x version for us.
Can't you make the conversion to self-closing tags configurable?
@capaj Could you open a new issue if that's a real problem?
@lipis opened as https://github.com/prettier/prettier/issues/5436 but now that I think about it-it may be just a misunderstanding stemming from the fact that angular.js has almost the same name as angular yet they are both very different frameworks. Also prettier only supports angular, not angular.js so it's not a bug. It's more like documentation addition request.
Thank you @capaj, I'll lock this conversation to avoid further comments. If there is anything wrong please file new issues instead.
To clarify, we won't change normal tags into self-closing tags in HTML, we only apply this kind of tag transformation in JSX, which is valid. Please make sure you're using --parser html.
A common mistake is that people are using top-level parser: "babylon", which treats everything as JavaScript (JSX), see here for more info.
Most helpful comment
Really wish http://codeguide.co/#html-syntax by @mdo could be enforced, so people can write consistent html:
</li>or</body>).Also, this feels like perfect use case for prettier 😉 :
I don't know specifics for formatting ember/angular, but for Vue SFC, my Vue/VSCode plugin https://github.com/octref/vetur has code that takes each region and send them to respective formatters:
Previously I hooked up js-beautify as formatter for
scriptandstyleregions, but now prettier has TS support so I'm switching over to it for formatting js/ts/css/scss/less.Once html supports land in prettier, I can make a Vue formatter that takes any Vue file written with html, js/ts, css/less/scss/postcss and outputs consistent code. That is 🔥 🔥 🔥