According to the SSR hydration docs:
In development mode, Vue will assert the client-side generated virtual DOM tree matches the DOM structure rendered from the server. If there is a mismatch, it will bail hydration, discard existing DOM and render from scratch. In production mode, this assertion is disabled for maximum performance.
How would one know if hydration succeeded/failed? If "this assertion is disabled" in production, does that mean Vue defaults to discarding the DOM, or does Vue assume the server sent the proper markup? I would imagine a failed hydration would be something that would be nice to capture (eg. via Raven.captureException()) so it can be tracked / fixed.
If there is indeed a "hydration mode", can that exposed as a global Vue.mode === 'hydration' (or Vue.hydrationMode === true if there are multiple "modes" that Vue can run in simultaneously)? Can a boolean/exception be exposed to let the developer know hydration succeeded?
data-server-rendered attribute.Sorry to reopen, but your answer doesn't address the primary concern (thanks for responding though!).
What happens if (in prod mode) Vue cannot hydrate? Does the app become static at that point?
@bjunc it can't happen because prod mode only strips away warnings, all behavior logic remains exactly the same. If it works in dev, it will work in prod.
I believe we have a good business case for SSR of WYSIWYG content. The big reason I am pursuing SSR, is for the SEO; which we're currently not getting with valuable user-generated content. So, I can't just trust that it works in dev. I want to make sure that a content admin doesn't brick the app by saving improper HTML in production (despite checks we might put in place).
I don't want to go off-topic, but if there is a better way to address the SEO aspect of dynamic content, maybe this a moot topic.
So you are allowing users to save arbitrary HTML, or just that you worry there could be potential XSS?
If you use v-html to display user-generated content, Vue won't attempt to diff/hydrate anything inside that node, so it can't lead to hydration failures.
Otherwise, pure VDOM-based hydration can only possibly fail when there is a bug in Vue.
Finally, hydration failures in prod will also cause Vue to throw away existing DOM and render afresh, so it won't "brick" the app.
Well, we take proactive measures, but I also want to have reactive measures. So no, not "arbitrary" HTML, but I'd feel better if I had redundancy checks on both the server and the client.
That's really great to hear about v-html though. I think that ultimately addresses the concern.
Also good to hear about the refresh, although it would defeat the point of the SEO; which is why I figured catching an exception could help us pinpoint the pages with the issues.
I think I'm good knowing v-html isn't part of the diff/hydration process. Thanks for the back-and-forth.
@yyx990803
it can't happen because prod mode only strips away warnings, all behavior logic remains exactly the same. If it works in dev, it will work in prod.
Well, it did actually happen! Here it is https://github.com/iloginow/vue-base-template and it actually seems very hard to debug)
This actually reared its head again for me. The user entered bad markup (no closing tag) into a WYSIWYG. This not only caused the page not to render server-side, but client-side render failed as well. Having a way of catching hydration failure would at least give me a way of knowing that certain pages are failing due to user generated content.
@bjunc
I also need SSR for SEO, and will be displaying HTML from WordPress content -- so this is a huge concern for me as well.
For your latest issue, was the content inside v-html? Can you share your code as well as what HTML was passed in?
Taking a shot in the dark here, but was your use-case involving wrapping the content inside an anchor tag?
<!-- Tile.vue -->
<template>
<a :href="blogPostLink">
<div v-html="blogPostHTML"></div>
</a>
</template>
<!-- blogPostHTML -->
This is a post. <a href="#test">Edit</a> or delete it.
If blogPostHTML contained any anchor tags, I would get this warning:
[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
Good News
I'm able to work around this by not using the outside anchor tag.
Additionally, I'm actually not able to reproduce the [Vue warn] even if I break the HTML within v-html itself. I even put nested anchor tags in the blog post HTML and it was fine.
@CurtisBelt I don't recall the exact markup that caused the hydration error. In your case, your hydration issue may simply be to nesting a div (block element) in an anchor. See this Stack Overflow question.
There are _proactive_ workarounds (validating WYSIWYG, which you probably should be doing anyway, etc.), but I still don't know why we can't get a _reactive_ exception to be thrown when hydration fails.
@bjunc Ah, yes I know how nested block in anchor is invalid - what I meant to highlight is how it only broke hydration when the template HTML + blogPostHTML causes invalid HTML together. But not if only blogPostHTML had invalid code. If I put the same invalid HTML inside blogPostHTML, it doesn't break hydration anymore. I also tried omitting closing tags, seemed to be OK.
See below -- that renders without warning, even though it's the same violation.
Hope that makes sense. Maybe this isn't really helping you I'm sorry, I'm just unable to break it inside of v-html alone, so I thought maybe your component HTML could have a similar issue.
<!-- Tile.vue -->
<template>
<div>
<div v-html="blogPostHTML"></div>
</div>
</template>
<!-- blogPostHTML -->
<a href="#test">This is a post. <a href="#test">Edit</a> or delete it.</a>
However if you find an example that breaks v-html please let me know, I intend to monitor this topic as much as possible before I launch my client with this in a few months.
Hi everyone,
Sorry to bother again, but IMO, there still is something unclear about this one.
Quoting @yyx990803:
— It will always attempt to hydrate when the root node has data-server-rendered attribute.
— In dev mode, if it failed to hydrate there will be a warning. If nothing happens, it worked.
— In prod mode, it assumes the markup is correct.
But, in prod, if the markup is not correct, what will happen?
After testing it, if the markup is not correct, the existing DOM is discarded and replaced with the vue app. Exactly like in dev (but, without any warning).
Is this the desired behaviour?
Thanks a lot.
@yamsellem that is correct. In the future we may improve it so that instead of discarding everything, it patches the existing DOM to match desired shape.