Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle whitespaces in templates more wisely #9208

Closed
Justineo opened this issue Dec 16, 2018 · 4 comments

Comments

@Justineo
Copy link
Member

@Justineo Justineo commented Dec 16, 2018

What problem does this feature solve?

Currently we have an boolean option for vue-template-compiler: preserveWhitespace. It either removes all whitespace-only text nodes, or leave them untouched. There were already earlier questions about either behavior: #6200, #7701, #9021, #9127. I think the current behavior is kind of oversimplified to cover actual usage.

When we write a template we tend to leverage line breaks and indents to make it more readable, like:

<div class="item">
  <div class="aside">Aside</div>
  <div class="main">Main</div>
</div>

And if we choose to layout this component with inline formatting context, sometimes we may not want to precisely control the margin between the inner parts with CSS, instead of using the size of a whitespace (which is related to those font-* styles). For similar cases we don't want these whitespace-only text nodes. This leads to preserveWhitespace: false (and it even became the default behavior for Vue CLI 3: vuejs/vue-cli@1864cef).

But when we craft some document/article-like content, this behavior becomes annoying. With preserveWhitespace: false, the following template:

<p>
  Welcome to <b>Vue.js</b> <i>world</i>.
  Have fun!
</p>

Will generate:

<p>
  Welcome to <b>Vue.js</b><i>world</i>.
  Have fun!
</p>

Which looks like:

Welcome to Vue.jsworld. Have fun!

And this is clearly not desired.

What does the proposed API look like?

In short, I suggest we offer a new compiler option, to apply the strategy React uses to handles whitespaces for JSX (source):

JSX removes whitespace at the beginning and ending of a line. It also removes blank lines. New lines adjacent to tags are removed; new lines that occur in the middle of string literals are condensed into a single space.

For examples:

<p>
  Welcome to <b>Vue.js</b> <i>world</i>.
  Have fun!
</p>

The whitespaces between <p> and Welcome are removed but the one between </b> and <i> and the one between . and Have are preserved thus giving us:

<p>Welcome to <b>Vue.js</b> <i>world</i>. Have fun!</p>

This seem to be much more reasonable IMO. And in this mode users will have more flexibility to better serve their different purposes.

In general, the proposal is:

  1. Keep preserveWhitespace but mark it as deprecated.
  2. Offer a new option to specify whether/how to remove whitespaces: removeWhitespace: 'with-line-break' | 'any' | 'none'.
  3. Ignore preserveWhitespace if removeWhitespace is specified.

(Still need more suggestions on specific API.)

@yyx990803

This comment has been minimized.

Copy link
Member

@yyx990803 yyx990803 commented Dec 26, 2018

A summary of what is landed in e1abedb:

  • Introduced a new option whitespace
    • with two valid values: 'preserve' or 'condense'.
    • defaults to 'preserve' (exactly the same default behavior as it is now)
    • ignores preserveWhitespace when a specific value is provided
    • when set to 'condense':
      • A whitespace-only text node between element tags is
        • removed if it contains new lines
        • Otherwise, it is condensed into a single space.
      • Consecutive whitespaces inside a non-whitespace-only text node is condensed into a single space.

In condense mode, the example template

<p>
  Welcome to <b>Vue.js</b> <i>world</i>.
  Have fun!
</p>

will be compiled as:

<p> Welcome to <b>Vue.js</b> <i>world</i>. Have fun! </p>

Essentially, this provides:

  • Removal of useless whitespace vnodes for better performance;
  • Smaller overall output;
  • Ability to intentionally keep inline whitespace between elements for layout purposes.

The reason for not entirely removing leading/ending whitespaces inside an element:

  • The logic is simpler and more consistent (all consecutive whitespace -> single space)
  • IMO makes the following case more reasonable:
<span>foo</span>
<span>
  bar
</span>

Will render as foo bar instead of foobar. This is also consistent with the current behavior.

We will likely use this new condense behavior as the default in 3.0.

@a1p4ca

This comment has been minimized.

Copy link

@a1p4ca a1p4ca commented Jan 15, 2019

I think this new option should also be added to vue-loader.

@yyx990803

This comment has been minimized.

Copy link
Member

@yyx990803 yyx990803 commented Jan 15, 2019

@a1p4ca vue-loader has compilerOptions which just passes through to the template compiler.

f2009 pushed a commit to f2009/vue that referenced this issue Jan 25, 2019
@YLivay

This comment has been minimized.

Copy link

@YLivay YLivay commented Mar 28, 2019

Hey, sorry for bumping a closed topic, but is this meant to also condense whitespace from html entities like &nbsp;?
For example, in this part, the second &nbsp; is not preserved while the first one is:

<span>
	<inline-button text="1" />

	&nbsp;

	<template v-if="someCondition">
		<inline-button text="2" />

		&nbsp;
	</template>

	<inline-button text="3" />
</span>

Resulting in the buttons rendering like: 1 23
I tried making it preserve the   by wrapping it in a span and even doing something silly like:
<span>&nbsp; &nbsp;</span>
which ended up being output as <span></span>.

sodatea added a commit to sodatea/vue-cli that referenced this issue Apr 19, 2019
BREAKING CHANGE:
Detailed explanation: vuejs/vue#9208 (comment)

Take the following template as example:
```
<p>
  Welcome to <b>Vue.js</b> <i>world</i>.
  Have fun!
</p>
```

With `preserveWhitespace: false`, it was compiled as:
```
<p> Welcome to <b>Vue.js</b><i>world</i>. Have fun! </p>
```

With `whitespace: 'condense'`, it is now compiled as:
```
<p> Welcome to <b>Vue.js</b> <i>world</i>. Have fun! </p>
```

Note the **inline whitespace between tags** is preserved.
sodatea added a commit to vuejs/vue-cli that referenced this issue Apr 22, 2019
BREAKING CHANGE:
Detailed explanation: vuejs/vue#9208 (comment)

Take the following template as example:
```
<p>
  Welcome to <b>Vue.js</b> <i>world</i>.
  Have fun!
</p>
```

With `preserveWhitespace: false`, it was compiled as:
```
<p> Welcome to <b>Vue.js</b><i>world</i>. Have fun! </p>
```

With `whitespace: 'condense'`, it is now compiled as:
```
<p> Welcome to <b>Vue.js</b> <i>world</i>. Have fun! </p>
```

Note the **inline whitespace between tags** is preserved.

Closes #1020
sodatea added a commit to vuejs/vue-cli that referenced this issue Apr 30, 2019
BREAKING CHANGE:
Detailed explanation: vuejs/vue#9208 (comment)

Take the following template as example:
```
<p>
  Welcome to <b>Vue.js</b> <i>world</i>.
  Have fun!
</p>
```

With `preserveWhitespace: false`, it was compiled as:
```
<p> Welcome to <b>Vue.js</b><i>world</i>. Have fun! </p>
```

With `whitespace: 'condense'`, it is now compiled as:
```
<p> Welcome to <b>Vue.js</b> <i>world</i>. Have fun! </p>
```

Note the **inline whitespace between tags** is preserved.

Closes #1020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.