angular / angular

Deliver web apps with confidence πŸš€
https://angular.dev
MIT License
95.71k stars 25.26k forks source link

Whitespaces are not trimmed in Text Node with `preserveWhitespaces: false` #37635

Open JounQin opened 4 years ago

JounQin commented 4 years ago

🐞 bug report

Affected Package

The issue is caused by package @angular/compiler

Is this a regression?

Yes, the previous version in which this bug was not present was: .... No idea ### Description A clear and concise description of the problem... https://github.com/angular/angular/blob/d1ea1f4c7f3358b730b0d94e65b00bc28cae279c/packages/compiler/src/ml_parser/html_whitespaces.ts#L78 ```html

{{ 'text' }}

{{ 'text' }}

{{ 'text' }}



There is no way to `trim` the text.

## πŸ”¬ Minimal Reproduction
<!--
Please create and share minimal reproduction of the issue starting with this template: https://stackblitz.com/fork/angular-ivy
-->
<!-- ✍️--> https://stackblitz.com/edit/angular-ivy-pkkssb

<!--
If StackBlitz is not suitable for reproduction of your issue, please create a minimal GitHub repository with the reproduction of the issue.
A good way to make a minimal reproduction is to create a new app via `ng new repro-app` and add the minimum possible code to show the problem.
Share the link to the repo below along with step-by-step instructions to reproduce the problem, as well as expected and actual behavior.

Issues that don't have enough info and can't be reproduced will be closed.

You can read more about issue submission guidelines here: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-submitting-an-issue
-->

## 🌍  Your Environment

**Angular Version:**
<pre><code>
<!-- run `ng version` and paste output below -->
<!-- ✍️-->
Angular CLI: 9.1.1
Node: 12.18.0
OS: darwin x64

Angular: 9.1.2
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.901.1
@angular-devkit/build-angular     0.901.1
@angular-devkit/build-optimizer   0.901.1
@angular-devkit/build-webpack     0.901.1
@angular-devkit/core              9.1.1
@angular-devkit/schematics        9.1.1
@angular/cdk                      9.2.1
@angular/cli                      9.1.1
@angular/flex-layout              9.0.0-beta.29
@ngtools/webpack                  9.1.1
@schematics/angular               9.1.1
@schematics/update                0.901.1
rxjs                              6.5.5
typescript                        3.8.3
webpack                           4.42.0
</code></pre>

**Anything else relevant?**
<!-- ✍️Is this a browser specific issue? If so, please specify the browser and version. -->

<!-- ✍️Do any of these matter: operating system, IDE, package manager, HTTP server, ...? If so, please mention it below. -->
JoostK commented 4 years ago

This is on purpose, actually. Whitespace is significant in HTML but collapsed to a single whitespace Because of this, the following is equivalent when rendered:

<strong>Bold</strong> text
<strong>Bold</strong>        text
<strong>Bold</strong>
text

However, the following would not be:

<strong>Bold</strong>text

as it would join the two words together.

pkozlowski-opensource commented 4 years ago

Yep, this is working as designed and we've got tests to prove it: https://github.com/angular/angular/blob/1197965e69d658c92422d49b1f2a1ba90498af67/packages/compiler/test/ml_parser/html_whitespaces_spec.ts#L62-L65

I can see how one would argue for the behaviour specified by @JounQin though. At the same time @JoostK point is super-valid here (although we've got the described problem already with <span>two</span> <span>words</span>

petebacondarwin commented 4 years ago

Also this approach is pretty standard across the industry. For example paste the example given into http://minifycode.com/html-minifier or https://htmlcompressor.com/compressor/

JounQin commented 4 years ago

@petebacondarwin How about html-minifier-terser https://danielruf.github.io/html-minifier-terser which is used by html-loader?

image

petebacondarwin commented 4 years ago

Two things to note with that tool:

  1. It has a "conservative collapse" option which is the same as our collapsing strategy.
  2. It tries to be intelligent in cases where there might be a problem:
Screenshot 2020-06-18 at 10 39 40

As @pkozlowski-opensource mentioned, there is room for discussion here but I don't think this would be a high priority for us.

dgardner-nv commented 2 years ago

Just wrap the interpolation in ng-container and it won't apply the white spaces around it.

<div>
    <ng-container>{{ value }}</ng-container>
</div>

I would argue that this is more of a problem than stated. Consider multi-line text that's been wrapped. Since an unnecessary white space is added before the interpolated text, it appears that the text is indented by one space on the first line. It also creates issues around spacing because you have to account for an extra white space before and after the interpolated text. If I want a space, I'll add a space. Don't need it added automatically for me.

JoostK commented 2 years ago

Just wrap the interpolation in ng-container and it won't apply the white spaces around it.

<div>
    <ng-container>{{ value }}</ng-container>
</div>

I would argue that this is more of a problem than stated. Consider multi-line text that's been wrapped. Since an unnecessary white space is added before the interpolated text, it appears that the text is indented by one space on the first line. It also creates issues around spacing because you have to account for an extra white space before and after the interpolated text. If I want a space, I'll add a space. Don't need it added automatically for me.

@dgardner-nv Angular does not introduce spaces into templates. It only removes non-significant whitespace. It may be that you're using a formatter that introduces whitespace, but if this affects the rendered output then that's a bug in your formatter.

pchabros commented 1 month ago

To overcome this issue you can set htmlWhitespaceSensitivity to "strict" in Prettier config. Then this:

<span>Very very very very very long text</span>

will be formatted into this:

<span
  >Very very very very very long text</span
>

instead of this:

<span>
  Very very very very very long text
</span>