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
208.08k stars 33.69k forks source link

Alert (possibly fix) SSR Mismatch in Production #6874

Open Austio opened 7 years ago

Austio commented 7 years ago

What problem does this feature solve?

Currently there is no way to receive alerts (and possibly rerender) in production concerning SSR vs VDom mismatch.

This is critical because different browsers will handle this in unexpected ways. For instance, I just finished trouleshooting an issue that is specific to Windows 10 and IE11 where a rendered vdom tree does not match ssr rendered html and causes a white screen. Chrome and other browsers were able to recover. The mismatch renders fine when navigating to this from an already rendered vue. Just not when the initial rendering happens with a specific page.

Discussion in forum.
https://forum.vuejs.org/t/ssr-render-mismatch-error-emit-in-production/20083

What does the proposed API look like?

I think the bulk of code currently lives here.

https://github.com/vuejs/vue/blob/adff0084e1b7bc4b8ffa2b87390c66afbc435582/src/core/vdom/patch.js#L662

I think during initial ssr render we need more granular flags to opt in to alerts on this behavior. Currently it is only NODE_ENV

Initial (maybe too verbose) thoughts would be. WARN_ON_SSR_MISMATCH RECOVER_ON_SSR_MISMATCH

Then if those are true we can change behavior.

I understand that this is performance critical so am very open to suggestions. I would be willing to implement this myself in a PR.

yyx990803 commented 7 years ago

Please provide a reproduction of failed recovery (white screen) in IE11.

Austio commented 7 years ago

@yyx990803 was able to boil this down on another issue we were running into with Safari 8.1

https://github.com/Austio/vue-hackernews-2.0/pull/1

Austio commented 7 years ago

@yyx990803 , appears this was a bug in safari's sort function and/or type coersion.

// node/chrome/etc returns what you would expect from looking at this
> [null, true, true].sort((a,b) => a < b)
[ true, true, null ]

// safari, does not
> [null, true, true].sort(function(a,b){ return a < b })
[null, true, true] 

Switching to using the -1,0,1 comparitor function renders properly.

Austio commented 7 years ago

Still would like to see if it makes sense to have a way to detect this in production. Would be very helpful, i think I would rather have the development behavior in production for re-rendering if there is invalid markup in order to prevent white screens

Tazer commented 7 years ago

Would be awesome , cause we also have problems sometimes with whitescreeen / node append errors (only in production), so it would be really nice to be able to see WHY in Production.

Austio commented 6 years ago

@yyx990803 bumping on this to get thoughts on this subject or how to approach. Also am happy to make a PR to allow this check to happen while in production. When this has happened to us, it is a hard failure which results in a white screen and no content rendered

Today it was on mobile safari 11 on ios8. When i wrap the span in a no-ssr component (which only renders during mount cycle) everything renders fine.

According to the HTML li spec, it allows flow content inside of it, which are all of the contained nodes https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#Flow_content

  <li
    data-test-location-list-item
  >
    <small class="editlinks" v-if="profileEditable">
      <router-link
        :to="{ name: 'profiles-locations-edit', params: { profileUUID: this.profileUUID, locationUUID: this.id} }"
      >
        <i class="icon-pencil"></i>
      </router-link>
    </small>
    <strong v-if='primary'>Office</strong>
    <vg-no-ssr>
      <span class="br contacts">
        <a
        v-if="hasGoogleMapLink"
        target="_blank"
        :href="googleMapLink">
          {{ address_1 }}<br>
          {{ address_2 }}<br v-if='address_2'>
          {{ city_state_zip_country }}<br>
          <template v-if='phone_number'>
            <span class='clabel'>Phone</span>
            {{ phone_number }}
            <span v-if='phone_number_extension'>x</span>
            {{ phone_number_extension }}
            <br>
          </template>
          <span class='clabel' v-if='fax_number'>Fax</span>
          {{ fax_number }}
        </a>
      </span>
    </vg-no-ssr>
  </li>
Austio commented 5 years ago

@yyx990803 Bump, any thoughts on this. Still happy to make a PR on this if the approach recommended is something that would be ok in light of your view of where SSR and Vue should head.

Ultimate goal: When there is a "White screen" event in production, provide a way for the client to signal that they want a complete re-render instead of hard white screen.

aaronransley commented 4 years ago

Also curious about configuring this behavior in production. It would be ideal to allow the client to rebuild DOM best it can if there is a node mismatch (current dev mode behavior, as far as I know), rather than throwing a hard exception and aborting the render.