[Из песочницы] Vue.js SSR & мобильный Safari: неочевидная проблема со слишком умным ПО

habr.png

На днях столкнулись с такой проблемой. Сгенерированный на стороне сервера код отказывался гидратироваться в Safari.

Гидратация относится к процессу на стороне клиента, в течение которого Vue берёт статический HTML, отправленный сервером, и превращает его в динамический DOM, который может реагировать на изменения данных на стороне клиента. Подробнее тут.

«Прод» просто падал, а dev-версия сообщала, что имеются расхождения в dom. А так как dev-версия не падает при попытке гидратации, а только сообщает об этом в консоли, ошибка была неочевидна и пока мы ее нашли, прошло довольно много времени.

Очень интересная стратегия от Vue — подождать продакшена и там упасть!

Полторы сотни компонентов разной сложности задачу не упрощали. В итоге удалось увидеть проблему, найти подходящее устройство и подружить его с консолью разработчика.

В итоге выяснилось, что падает наше приложение при подключении компонента футера. И когда нашли нужную строку, просто не поверили глазам. Ожидали все, что угодно, только не этого.
Оказалось, что когда удаляешь номер телефона, гидратация проходила без проблем. Когда начали копаться, выяснилось, что Safari после получения html-верстки подставлял рядом с телефоном тег a, который вызывал, собственно, приложение набора номера.

Естественно, когда начиналась гидратация, dom-а пришедшей с сервера страницы и вновь построенного виртуального не совпадали. Приложение падало без объявления войны.

Решилась это проблема тоже довольно неожиданно. До сего момента телефон мы вставляли обычным образом:

8 (800) 111 2 333


Решением проблемы стал биндинг v-text:


У меня есть теория на этот счет. Если кто-то сможет подтвердить ее или опровергнуть (предложив новую), буду очень признателен. Как я понимаю, после того, как Safari получил документ, Vue строит виртуальный dom и сравнивает его с этим документом и пока он этот документ гидратирует, Safari занимается своим тёмным делом и меняет телефон на ссылку. Когда доходит дело до этого поля, Vue с помощью v-text снова заменяет содержимое нашего дива на нужное нам. В итоге на момент сравнения dom-а совпадают, полет нормальный.

© Habrahabr.ru