vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
208k stars 33.69k forks source link

Trailing whitespaces are trimmed from the end of inline <strong> element when page is being parsed by Vue #11122

Open kfirba opened 4 years ago

kfirba commented 4 years ago

Version

2.6.10

Reproduction link

https://jsfiddle.net/kfirba2/us5h04f7/5/

Steps to reproduce

  1. Have a wrapper for Vue
  2. Inside that wrapper, insert an inline element such as <strong> and leave trailing whitespace at the end of it:
    <div id="#app">
    This is <strong>BOLD </strong>text
    </div>
  3. After the page is parsed with Vue (and Vue has generated a Virtual DOM for the page), the words "BOLD" and "text" will be glued together (the whitespace after the word "BOLD" and before the enclosing tag of <strong> is removed.

What is expected?

It is expected that the whitespace will remain in its place and not trimmed.

What is actually happening?

The trailing whitespace is trimmed.

despreston commented 4 years ago

I think https://github.com/vuejs/vue/pull/11065 pr will fix this.

kfirba commented 4 years ago

@despreston I’m not sure it’s going to solve it. The PR focuses on the template compiler if I’m not mistaken. The issue here is the DOM that Vue mounts on and parses into virtual DOM on the fly

Justineo commented 4 years ago

Hi. What's your use case of using

<strong>BOLD </strong>text

instead of this?

<strong>BOLD</strong> text
kfirba commented 4 years ago

@Justineo Hey,

You are absolutely right that it is not natural, however, our website is Vue powered and some of the website's content is UGC. Users are using some sort of a WYSIWYG and never write HTML. Because of that reason, we, nor them, have any good control of the generated HTML. We tried solving that in some ways but it looks like we couldn't achieve a satisfiable solution.

Justineo commented 4 years ago

I assume you won't need Vue to parse and compile the UGC code. You can try put a v-pre directive on the wrapper element around your UGC so that Vue will skip that part.

kfirba commented 4 years ago

@Justineo I wasn't aware of the v-pre directive so thanks for that.

However, it is not entirely true. The way we have it working is that the user (who is not always a "random" user, but may be an editor) has a WYSIWYG where he can also "inject" custom elements which are Vue elements, such as Lead Forms. So the UGC content has Vue elements within it For example:

<div id="#app">
  <p>Text Text Text....</p>
  <lead-form></lead-form>
  <p>...</p>
  <another-element></another-element>
  ...
</div>
kfirba commented 4 years ago

@Justineo Hey, is there anything new with that?

s-gbz commented 4 years ago

Correct me if I'm wrong, but isn't skipping whitespaces default behaviour in HTML? You usually have to insert whitespaces manualy as &nbsp;.

Garito commented 4 years ago

Sometimes you will need something like since webpack (if I recall correctly) removes all spaces

kfirba commented 4 years ago

@s-gbz only subsequent spaces. Multiple spaces are “collapsed” into 1 space visually. In the source code you will find all of the spaces.

This is obviously a bug. Webpack has nothing do to with it as we are talking about Vue mounting on an existing DOM which has never gone any compilation/transpiration step (rendered with PHP)

abrahamguo commented 4 years ago

Is this something I can look into? @kfirba I agree, this seems like a bug.

abrahamguo commented 4 years ago

After investigating this issue, I can see that it is caused by this function:

function trimEndingWhitespace (el) {
    // remove trailing whitespace node
    if (!inPre) {
        var lastNode;
        while (
            (lastNode = el.children[el.children.length - 1]) &&
            lastNode.type === 3 &&
            lastNode.text === ' '
        ) {
            el.children.pop();
        }
    }
}

which removes ending whitespace. Does anyone know the reasoning behind this function?

kfirba commented 4 years ago

@abrahamguo anything new regarding this issue?

abrahamguo commented 4 years ago

Nope. I found the code for it in the core but I need the advice of people more knowledgeable than me to advise the purpose of this code. Otherwise, you could maybe dig through the history to find why this code was added.

galaxy-s10 commented 4 years ago

@s-gbz only subsequent spaces. Multiple spaces are “collapsed” into 1 space visually. In the source code you will find all of the spaces.

This is obviously a bug. Webpack has nothing do to with it as we are talking about Vue mounting on an existing DOM which has never gone any compilation/transpiration step (rendered with PHP)

Is this something I can look into? @kfirba I agree, this seems like a bug.

Version

2.6.10

Reproduction link

https://jsfiddle.net/kfirba2/us5h04f7/5/

Steps to reproduce

  1. Have a wrapper for Vue
  2. Inside that wrapper, insert an inline element such as <strong> and leave trailing whitespace at the end of it:
<div id="#app">
  This is <strong>BOLD </strong>text
</div>
  1. After the page is parsed with Vue (and Vue has generated a Virtual DOM for the page), the words "BOLD" and "text" will be glued together (the whitespace after the word "BOLD" and before the enclosing tag of <strong> is removed.

What is expected?

It is expected that the whitespace will remain in its place and not trimmed.

What is actually happening?

The trailing whitespace is trimmed.

我认为#11065 pr将解决此问题。

我认为#11065 pr将解决此问题。

cccccccccc

galaxy-s10 commented 4 years ago

Version

2.6.10

Reproduction link

https://jsfiddle.net/kfirba2/us5h04f7/5/

Steps to reproduce

  1. Have a wrapper for Vue
  2. Inside that wrapper, insert an inline element such as <strong> and leave trailing whitespace at the end of it:
<div id="#app">
  This is <strong>BOLD </strong>text
</div>
  1. After the page is parsed with Vue (and Vue has generated a Virtual DOM for the page), the words "BOLD" and "text" will be glued together (the whitespace after the word "BOLD" and before the enclosing tag of <strong> is removed.

What is expected?

It is expected that the whitespace will remain in its place and not trimmed.

What is actually happening?

The trailing whitespace is trimmed.

test

galaxy-s10 commented 4 years ago

@despreston I’m not sure it’s going to solve it. The PR focuses on the template compiler if I’m not mistaken. The issue here is the DOM that Vue mounts on and parses into virtual DOM on the fly

test

weblogjacob commented 4 years ago

What is the status of this ticket? I have exactly the same problem with some UGC.

<p>This is a<em> </em>paragraph</p>

will be compiled to

<p>This is a<em></em>paragraph</p>

Not the result I am hoping for. The v-pre directive does nothing and the whitespace compiler option does not have any effect.

kirya-dev commented 3 years ago

Going 2021 years... Without changes?

ggedde commented 1 week ago

Same issue with vue v3.5.12 using CDN https://unpkg.com/vue@3/dist/vue.esm-browser.js However, it is also removing new lines.

So this:

<div class="modal" :class="{open: open}" @click="open = false">
    <article class="mw-400" @click.stop>
        <p>Modal</p>
        <button @click="open = false">
            Close Modal
        </button>
    </article>
</div>

is becoming:

<div class="modal" :class="{open: open}" @click="open = false"><article class="mw-400" @click.stop><p>Modal</p><button @click="open = false"> Close Modal </button></article></div>

Oddly it is keeping whitespace around the button text, but removing it elsewhere.

I did find that you can do app.config.compilerOptions.whitespace = 'preserve'; but this only works on single nodes and not the entire app container.

The only reason this is an issue for me is that I have a Copy HTML tool that users can copy the html code. But because of this it removes the whitespace before they can copy the code with proper indentation.

Is there a way to disable this. Otherwise, am I stuck with having to add some custom indentation code when they copy the code.