Рендеринг в интернете (Rendering on the Web)
Last updated
Last updated
Одно из основных решений, которые должны принять веб-разработчики, - это где реализовать логику и рендеринг в своих приложениях. Это может быть сложно, так как существует несколько разных способов создания сайта.
Терминология
SSR: рендеринг на стороне сервера - рендеринг клиентского или универсального приложения в HTML на сервере;
CSR: рендеринг на стороне клиента - рендеринг приложения в браузере, обычно с использованием DOM;
Регидратация (Rehydration): «загрузка» представлений JavaScript на клиенте так, чтобы они повторно использовали дерево DOM и данные HTML, представленные сервером;
Предварительный рендеринг (Prerendering): запуск приложения на стороне клиента во время сборки для захвата его исходного состояния в виде статического HTML;
TTFB: время до первого байта - рассматривается как время между нажатием на ссылку и первым поступающим контентом;
FP: First Paint - первый раз, когда любой пиксель становится видимым для пользователя;
FCP: First Contentful Paint - время, когда запрашиваемый контент (тело статьи и т. д.) Становится видимым;
TTI: Time To Interactive - время, когда страница становится интерактивной (события подключены и т. д.).
Серверный рендеринг
Серверный рендеринг генерирует полный HTML для страницы на сервере в ответ на навигацию. Это позволяет избежать дополнительных циклов обработки данных и шаблонов на клиенте, поскольку они обрабатываются до того, как браузер получает ответ.
Серверный рендеринг обычно производит быструю First Paint и First Contentful Paint. Выполнение логики страницы и рендеринга на сервере позволяет избежать отправки большого количества JavaScript клиенту, что помогает быстро достичь Time to Interactive. Это имеет смысл, поскольку при серверном рендеринге вы просто отправляете текст и ссылки в браузер пользователя. Этот подход может хорошо работать для широкого спектра устройств и условий сети, и открывает интересные оптимизации браузера, такие как потоковый анализ документов.
При использовании серверного рендеринга пользователи вряд ли будут ждать, пока обработается привязанный к процессору JavaScript, прежде чем они смогут использовать ваш сайт. Даже когда нельзя избежать стороннего JS, использование серверного рендеринга для сокращения собственных затрат на JS может дать вам больше « бюджета » на все остальное. Однако у этого подхода есть один главный недостаток: генерация страниц на сервере требует времени, что часто может привести к более долгому времени до первого байта.
Достаточно ли серверного рендеринга для вашего приложения, во многом зависит от него самого. Существует давняя дискуссия о правильном применении серверного рендеринга по сравнению с рендерингом на стороне клиента, но важно помнить, что вы можете использовать серверный рендеринг для одних страниц, а не для других нет. Некоторые сайты успешно применяют гибридные методы рендеринга. Сервер Netflix отображает свои относительно статичные целевые страницы, предварительно выбирая JS для страниц с интенсивным взаимодействием, предоставляя этим более тяжелым страницам, отображаемым клиентом, более высокую вероятность быстрой загрузки.
Многие современные фреймворки, библиотеки и архитектуры позволяют отображать одно и то же приложение как на клиенте, так и на сервере. Эти методы могут использоваться для серверного рендеринга, однако важно отметить, что архитектуры, в которых рендеринг происходит как на сервере, так и на клиенте, представляют собой собственный класс решений с очень разными характеристиками производительности и компромиссами. Пользователи React могут использовать renderToString() или решения, построенные на его основе, такие как Next.js, для серверного рендеринга. Пользователи Vue могут взглянуть на руководство по серверному рендерингу Vue или Nuxt. Angular имеет Universal. В большинстве популярных решений используется некоторая форма гидратации, поэтому перед выбором инструмента ознакомьтесь с подходом, который используется.
Статический рендеринг
Статический рендеринг происходит во время сборки и предлагает быстрые First Paint, First Contentful Paint и Time To Interactive - при условии, что количество JS на стороне клиента ограничено. В отличие от серверного рендеринга, ему также удается достичь стабильно быстрого времени до первого байта, поскольку HTML-код для страницы не нужно генерировать на лету. Как правило, статический рендеринг означает создание отдельного HTML-файла для каждого URL-адреса заранее. Поскольку HTML-ответы генерируются заранее, статические рендеры могут быть развернуты на нескольких CDN, чтобы воспользоваться преимуществом пограничного кэширования (edge-caching).
Решения для статического рендеринга бывают всех форм и размеров. Такие инструменты как Gatsby спроектированы так, чтобы разработчики почувствовали что их приложения рендерятся динамически быстрее чем генерируются на этапе сборки. Другие, как Jekyll и Metalsmith принимают их статическую природу, обеспечивая более шаблонный подход.
Одним из недостатков статического рендеринга является то, что отдельные HTML-файлы должны создаваться для каждого возможного URL. Это может быть сложно или даже невозможно, если вы не можете предсказать, какие будут эти URL-адреса раньше времени, или для сайтов с большим количеством уникальных страниц.
Пользователи React могут быть знакомы с Gatsby , статическим экспортом Next.js или Navi - все это делает его удобным для автора с использованием компонентов. Тем не менее, важно понимать разницу между статическим рендерингом и предварительным рендерингом: статические рендеринг страниц являются интерактивными без необходимости выполнения большого количества JS на стороне клиента, тогда как предварительный рендеринг улучшает First Paint или First Contentful Paint одностраничного приложения (SPA), которое необходимо загрузить клиент для того, чтобы страницы были по-настоящему интерактивными.
Если вы не уверены, является ли данное решение статическим или предварительным рендерингом, попробуйте этот тест: отключите JavaScript и загрузите созданные веб-страницы. Для статически визуализированных страниц большая часть функциональности будет по-прежнему существовать без включенного JavaScript. Для предварительно обработанных страниц могут существовать некоторые базовые функции, такие как ссылки, но большая часть страницы будет инертной.
Еще один полезный тест - замедление работы сети с помощью Chrome DevTools и наблюдение за загрузкой JavaScript до того, как страница станет интерактивной. Для предварительного рендеринга обычно требуется больше JavaScript, чтобы стать интерактивным, и этот JavaScript имеет тенденцию быть более сложным, чем подход прогрессивного улучшения, используемый при статическом рендеринге.
Серверный Рендеринг против Статического Рендеринга
Серверный Рендеринг не является серебряной пулей - его динамическая природа может сопровождаться значительными вычислительными накладными расходами. Многие решения для рендеринга серверов не сбрасываются рано, могут задержать TTFB или удвоить отправку данных (например, встроенное состояние, используемое JS на клиенте). В React, функция renderToString() может быть медленной, поскольку она является синхронной и однопоточной. Получение серверным рендерингом «права» может включать в себя нахождение или создание решения для компонентов кэширования , управление потреблением памяти, применение техник мемоизации, и многие другие проблемы. Обычно вы обрабатываете / перестраиваете одно и то же приложение несколько раз - один раз на клиенте и один раз на сервере. Тот факт, что при рендеринге с сервера может появиться что-то раньше, не означает, что у вас меньше работы.
Серверный рендеринг генерирует HTML по требованию для каждого URL, но может быть медленнее, чем просто обслуживание статического рендеринга контента. Если вы можете добавить дополнительную работу, серверный рендеринг + кэширование HTML может значительно сократить время серверного рендеринга. Преимуществом рендеринга на сервере является возможность извлекать больше «живых» данных и отвечать на более полный набор запросов, чем это возможно при статическом рендеринге. Страницы, требующие персонализации, являются конкретным примером типа запроса, который не будет хорошо работать при статическом рендеринге.
Серверный рендеринг также может представлять интересные решения при построении PWA. Лучше использовать полностраничное сервис-воркер (service-worker) кэширование или просто рендерить отдельные части контента на сервере?
Рендеринг на стороне клиента (CSR)
Рендеринг на стороне клиента (CSR) означает рендеринг страниц непосредственно в браузере с использованием JavaScript. Вся логика, выборка данных, шаблоны и маршрутизация обрабатываются на клиенте, а не на сервере.
Рендеринг на стороне клиента может быть трудно получить и быстро сохранить для мобильных устройств. Он может приблизиться к производительности чисто серверного рендеринга, если выполняет минимальную работу, сохраняя жесткий бюджет JavaScript и предоставляя ценность в минимально возможном количестве RTTs. Критические сценарии и данные могут быть доставлены быстрее, используя HTTP/2 Server Push или <link rel=preload>, что заставляет парсер работать на вас быстрее. Шаблоны, такие как PRPL, стоит оценить, чтобы обеспечить мгновенную начальную и последующую навигацию.
Основным недостатком рендеринга на стороне клиента является то, что количество требуемого JavaScript имеет тенденцию к росту по мере роста приложения. Это становится особенно трудным с добавлением новых библиотек JavaScript, полифилов и стороннего кода, которые конкурируют за вычислительную мощность и часто должны обрабатываться до того, как содержимое страницы может быть отображено. Опыт работы с CSR, основанный на больших пакетах JavaScript, должен учитывать агрессивное разделение кода и обязательно загружать JavaScript - «обслуживайте только то, что вам нужно, когда вам это нужно». Для случаев, когда интерактивность незначительна или отсутствует, рендеринг сервера может представлять собой более масштабируемое решение этих проблем.
Для людей, создающих одностраничное приложение, идентификация основных частей пользовательского интерфейса, используемых большинством страниц, означает, что вы можете применить технику кэширования Application Shell . В сочетании с сервис-воркерами это может значительно улучшить воспринимаемую производительность при повторных посещениях.
Объединение серверного рендеринга и CSR через регидратацию
Этот подход, часто называемый универсальным рендерингом или просто «SSR». Этот подход пытается сгладить углы между рендерингом на стороне клиента и рендерингом сервера, выполняя оба действия. Запросы навигации, такие как полная загрузка или перезагрузка страницы, обрабатываются сервером, который отображает приложение в HTML, затем JavaScript и данные, используемые для визуализации, встраиваются в итоговый документ. При аккуратной реализации это обеспечивает быструю First Contentful Paint точно так же, как серверный рендеринг, а затем «подхватывает», снова выполняя рендеринг на клиенте, используя технику, называемую (ре)гидратация. Это новое решение, но оно может иметь некоторые существенные недостатки производительности.
Основным недостатком SSR с регидратацией является то, что он может оказать существенное негативное влияние на Time To Interactive, даже если он улучшит First Paint. Страницы SSR часто выглядят обманчиво загруженными и интерактивными, но на самом деле не могут реагировать на ввод, пока JS на стороне клиента не будет выполнен и обработчики событий не присоединены. Это может занять несколько секунд или даже минут на мобильном телефоне.
Возможно, вы испытали это сами - в течение некоторого времени после того, как страница, которая выглядит полностью загруженной не реагирует на клики или нажатия. Это быстро расстраивает ... «Почему ничего не происходит? Почему я не могу прокрутить?
Проблема регидратации: одно приложение по цене двух
Проблемы регидратации часто могут быть хуже, чем замедленная интерактивность из-за JS. Чтобы клиентский JavaScript мог точно «подхватить», где сервер остановился, без необходимости повторного запроса всех данных, которые сервер использовал для визуализации своего HTML, текущие SSR решения обычно сериализуют ответ от пользовательского интерфейса. зависимости данных в документе в виде тегов скрипта. Полученный HTML-документ содержит высокий уровень дублирования:
Как вы можете видеть, сервер возвращает описание пользовательского интерфейса приложения в ответ на запрос навигации, но он также возвращает исходные данные, использованные для создания этого пользовательского интерфейса, и полную копию реализации пользовательского интерфейса, которая затем загружается на клиенте. Только после завершения загрузки и выполнения bundle.js этот интерфейс становится интерактивным.
Метрики производительности, собранные с реальных веб-сайтов с использованием регидратации SSR, указывают на то, что его использование не рекомендуется. В конечном счете, причина кроется в пользовательском опыте: в конечном итоге крайне просто оставить пользователей в «странной долине».
Хотя есть надежда на SSR с регидратацией. В краткосрочной перспективе только использование SSR для контента с высокой степенью кэширования может уменьшить задержку TTFB, что дает результаты, аналогичные предварительному рендерингу. Регидратация постепенно, постепенно или частично может стать ключом к повышению эффективности этого метода в будущем.
**Рендеринг потокового сервера и прогрессивная регидратация **(Streaming server rendering and Progressive Rehydration)
За последние несколько лет серверный рендеринг получил ряд разработок.
Рендеринг потокового сервера позволяет отправлять HTML порциями, которые браузер может визуализировать по мере получения. Это может обеспечить быструю First Paint и First Contentful Paint, поскольку разметка поступает к пользователям быстрее. В React потоки, являющиеся асинхронными в renderToNodeStream() - по сравнению с синхронным renderToString - означают, что обратное давление хорошо обрабатывается.
Прогрессивная регидратация также стоит того, чтобы за ней следить, и кое-что, что изучал React. При таком подходе отдельные части приложения, отображаемого на сервере, «загружаются» с течением времени, а не по общему текущему подходу - инициализации всего приложения сразу. Это может помочь уменьшить объем JavaScript, необходимый для того, чтобы сделать страницы интерактивными, поскольку обновление на стороне клиента низкоприоритетных частей страницы может быть отложено для предотвращения блокировки основного потока. Это также может помочь избежать одной из самых распространенных ошибок регидратации в SSR, когда дерево DOM, отображаемое сервером, разрушается, а затем немедленно перестраивается - чаще всего потому, что при первоначальной синхронной визуализации на стороне клиента требуются не совсем готовые данные, возможно, ожидающие разрешения Promise.
Частичная регидратация
Частичная регидратация оказалась трудно осуществимой. Этот подход является продолжением идеи прогрессивной регидратации, где анализируются отдельные части (компоненты/виды/деревья), которые должны быть постепенно регидратированы, и идентифицируются те, у которых мало интерактивности или нет реактивности. Для каждой из этих в основном статических частей соответствующий код JavaScript затем преобразуется в инертные ссылки и декоративную функциональность, сокращая их площадь на стороне клиента почти до нуля. Подход частичной гидратации имеет свои проблемы и недостатки. Это создает некоторые интересные проблемы для кэширования, и навигация на стороне клиента означает, что мы не можем предполагать, что серверный HTML-код для инертных частей приложения будет доступен без полной загрузки страницы.
Трисоморфный рендеринг (Trisomorphic Rendering)
Если сервис-воркеры являются подходящим вариантом для вас, «трисоморфный» рендеринг также может представлять интерес. Это метод, при котором вы можете использовать потоковый рендеринг сервера для начальной/не-JS-навигации, а затем попросить сервис-воркер на себя рендеринг HTML для навигации после его установки. Это может поддерживать кэшированные компоненты и шаблоны в актуальном состоянии и обеспечивает навигацию в стиле SPA для отображения новых представлений в одном сеансе. Этот подход работает лучше всего, когда вы можете совместно использовать один и тот же код шаблонов и маршрутизации между сервером, клиентской страницей и сервис-воркером.
SEO соображения
Команды часто учитывают влияние SEO при выборе стратегии рендеринга в сети. Рендеринг сервера часто выбирается для обеспечения «полного вида», который сканеры могут легко интерпретировать. Сканеры могут понимать JavaScript, но часто есть ограничения, о которых стоит знать, как они рендерится. Рендеринг на стороне клиента может работать, но часто не без дополнительного тестирования и работы. В последнее время динамический рендеринг также стал вариантом, заслуживающим внимания, если ваша архитектура сильно зависит от клиентского JavaScript.
В случае сомнений инструмент Mobile Friendly Test неоценим для проверки того, что выбранный вами подход делает то, на что вы надеетесь. Он показывает визуальный предварительный просмотр того, как какая-либо страница отображается сканеру Google, найденный сериализованный контент HTML (после выполнения JavaScript) и любые ошибки, обнаруженные во время рендеринга.
Вот удобная инфографика, показывающая спектр сервер-клиент:
Как работает рендеринг в браузере
Из полученного от сервера HTML-документа формируется DOM (Document Object Model).
Загружаются и распознаются стили, формируется CSSOM (CSS Object Model).
На основе DOM и CSSOM формируется дерево рендеринга, или render tree - набор объектов рендеринга (Webkit использует термин «renderer», или «render object», а Gecko - «frame»). Render tree дублирует структуру DOM, но сюда не попадают невидимые элементы (например - <head>, или элементы со стилем display:none;). Также, каждая строка текста представлена в дереве рендеринга как отдельный renderer. Каждый объект рендеринга содержит соответствующий ему объект DOM (или блок текста), и рассчитанный для этого объекта стиль. Проще говоря, render tree описывает визуальное представление DOM.
Для каждого элемента render tree рассчитывается положение на странице - происходит layout. Браузеры используют поточный метод (flow), при котором в большинстве случаев достаточно одного прохода для размещения всех элементов (для таблиц проходов требуется больше).
Наконец, происходит отрисовка всего этого добра в браузере - painting.
В процессе взаимодействия пользователя со страницей, а также выполнения скриптов, она меняется, что требует повторного выполнения некоторых из вышеперечисленных операций.
Адаптивный и отзывчивый веб-дизайн (Adaptive vs. Responsive)
Чтобы онлайн ресурс корректно отображался на компьютере и мобильных устройствах, при создании сайта или интернет-магазина рекомендуется использовать адаптивный дизайн. Такой тип верстки позволяет варьировать размеры и отображение интерфейса ресурса в зависимости от типа устройства, с помощью которого пользователь зашел в Интернет.
Responsive Design (RWD) - отзывчивый дизайн - проектирование сайта с определенными значениями свойств, например, гибкая сетка макета, которые позволяют одному макету работать на разных устройствах;
Помимо своей изменяющейся структуры, у респонсив дизайна есть несколько других преимуществ:
Одинаковый внешний вид ресурса в разных браузерах и на различных платформах Наличие у сайта одинакового URL, что способствует SEO-оптимизации Разработчикам необходимо обслуживать лишь один сайт, что позволяет сократить время, затрачиваемое на дизайн и контент
И хотя положительные стороны респонсивного дизайна очевидны, у этого метода существует ряд недостатков. Самым большим из них является скорость загрузки, которая значительно снижается из-за высокого разрешения изображений и других визуальных элементов, необходимых для оформления внешнего вида ресурса.
Adaptive Design (AWD) - адаптивный дизайн, или динамический показ - проектирование сайта с условиями, которые изменяются в зависимости от устройства, базируясь на нескольких макетах фиксированной ширины.
Для создания отзывчивых макетов используются медиазапросы и относительные размеры элементов сетки, заданные с помощью %. В адаптивном дизайне серверные скрипты сначала определяют тип устройства, с помощью которого пользователь пытается получить доступ к сайту (настольный ПК, телефон или планшет), затем загружает именно ту версию страницы, которая наиболее оптимизирована для него. Для элементов сетки задаются фиксированные в пикселях (px) размеры.
Источники:
Доп. материал: