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

since v2.3.0, in some specific cases, two consecutive comment vnodes will be merged into one text vnode. #5592

Closed
maggiehe opened this issue May 3, 2017 · 5 comments

Comments

@maggiehe
Copy link
Contributor

maggiehe commented May 3, 2017

Version

2.3.0

Reproduction link

https://jsfiddle.net/maggiehe/xovqtqd8/

Steps to reproduce

Use the following template with this.currentIndex = 1, then check this._vnode.

<div><div>foo</div><div v-for="i in 3" v-if="i===currentIndex" :key="i">{{i}}</div></div>

What is expected?

The template's childNodes will be compiled into: ["Element", "Element", "Comment", "Comment"]

What is actually happening?

Vue(>=2.3.0) compiles the template's childNodes into [ "Element", "Element", "Text" ], while Vue@2.2.6 performs correctly.


The bug will lead to this error: The client-side rendered virtual DOM tree is not matching server-rendered content.

@maggiehe maggiehe changed the title since v2.3.0, in some specific cases, two comment vnodes were merged into one text vnode. since v2.3.0, in some specific cases, two consecutive comment vnodes will be merged into one text vnode. May 3, 2017
@TheDutchCoder
Copy link

I think this is Vue's internal way of tracking things in v-for loops. 'Skipped' elements seem to be stored as empty text nodes, probably for faster processing once they're needed.

You can see how the skipped items all get rendered as empty text nodes here: https://jsfiddle.net/xovqtqd8/7/

Vue seems to be "smart" about simply not processing items further down the list that don't fall in between the condition, although I'm not sure if that's intentional or not.

Someone on the core team might be able to shine more light on this, but to me it doesn't seem like a bug, but an internal way of tracking vnodes.

@blake-newman
Copy link
Member

blake-newman commented May 3, 2017

I think there could be an issue with Vue internally since 2.3, as I can also report that I see text nodes.

The closest thing I can put it to is SVG's a simple component containing an svg seems to cause extra vnodes around the svg. Which is particularly problematic for SSR, as hydration will fail.

FYI, I believe that the text nodes should be comment nodes thus not handling correctly is SSR. Unfortunately @yyx990803 is on holiday at the moment so confirming if this is an intentional change will be difficult. I hope to track this further tomorrow.

If this is a bug we will get a patch out ASAP. Will do a get biscet tomorrow to find the true cause, however will need to create a small repro with tests to track a failure. Will update as soon as I can.

@maggiehe
Copy link
Contributor Author

maggiehe commented May 3, 2017

@TheDutchCoder
SSR will be problematic.
The server side will generate only two real dom nodes: <div></div><div></div> , which doesn't match the virtual dom in client side: [Element, Element, EmptyText]. This will result in a hydration failure:(

@maggiehe
Copy link
Contributor Author

maggiehe commented May 3, 2017

@blake-newman , I didn't use SVG.
I think my problem may have been introduced in this commit #c5808dc. c.text was optimized to isDef(c.text), so empty comment vnode (node.text==="") could also create a text vnode.
And I tried to launch a pull request #5593. I'm not sure if it's the author's intention, hope it will be helpful for you to track the problem.

@Leopoldthecoder
Copy link

Leopoldthecoder commented May 7, 2017

Same issue here: ElemeFE/element#4622
image

The extra VNode (last one) is a text. I checked the built file of element-ui and found this:

// in the render function
return _c('div', {
  class: [...]
}, [
  ..., // some other VNodes
  (_vm.validating) ? _c('i', {
    staticClass: "el-input__icon el-icon-loading"
  }) : _vm._e(),
  (_vm.$slots.append) ? _c('div', {
    staticClass: "el-input-group__append"
  }, [_vm._t("append")], 2) : _vm._e()
])

The bug comes up when _vm.validating and _vm.$slots.append are both false. In other words,

two consecutive comment vnodes will be merged into one text vnode

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants