На стороне клиента, на стороне сервера и перед предварительным рендерингом для веб-приложений

Опубликовано: 2022-03-11

В последнее время в сообществе фронтенда что-то происходит. Рендеринг на стороне сервера становится все более популярным благодаря React и его встроенной функции гидратации на стороне сервера. Но это не единственное решение, обеспечивающее быстрое взаимодействие с пользователем благодаря сверхбыстрому показателю времени до первого байта (TTFB): предварительный рендеринг также является довольно хорошей стратегией. В чем разница между этими решениями и полностью клиентским приложением?

Клиентское приложение

С тех пор как существуют такие фреймворки, как Angular, Ember.js и Backbone, фронтенд-разработчики склонны рендерить все на стороне клиента. Благодаря Google и его способности «читать» JavaScript, он работает очень хорошо и даже оптимизирован для SEO.

В решении для рендеринга на стороне клиента вы перенаправляете запрос в один HTML-файл, и сервер будет доставлять его без какого-либо контента (или с экраном загрузки), пока вы не получите весь JavaScript и не позволите браузеру скомпилировать все перед рендерингом контента.

При хорошем и надежном интернет-соединении он работает довольно быстро и хорошо. Но это может быть намного лучше, и это не должно быть трудно сделать таким образом. Это то, что мы увидим в следующих разделах.

Рендеринг на стороне сервера (SSR)

Решение SSR — это то, что мы использовали много лет назад, но склонны забывать в пользу решения для рендеринга на стороне клиента.

В старых решениях для рендеринга на стороне сервера вы создавали веб-страницу — например, на PHP — сервер компилировал все, включал данные и доставлял клиенту полностью заполненную HTML-страницу. Это было быстро и эффективно.

Но… каждый раз, когда вы переходили на другой маршрут, серверу приходилось делать всю работу заново: получать файл PHP, компилировать его и доставлять HTML, при этом все CSS и JS задерживали загрузку страницы до нескольких сотен мс или даже целые секунды.

Что, если бы вы могли выполнить загрузку первой страницы с помощью решения SSR, а затем использовать инфраструктуру для динамической маршрутизации с помощью AJAX, извлекая только необходимые данные?

Вот почему SSR набирает все большую популярность в сообществе, потому что React популяризировал эту проблему с помощью простого в использовании решения: метода RenderToString .

Этот новый вид веб-приложений называется универсальным приложением или изоморфным приложением . До сих пор ведутся споры о точном значении этих терминов и отношениях между ними, но многие люди используют их взаимозаменяемо.

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

SSR используется для получения данных и предварительного заполнения страницы пользовательским контентом, используя надежное интернет-соединение сервера. То есть собственное интернет-соединение сервера лучше, чем у пользователя с лжи-фай), поэтому он может выполнять предварительную выборку и объединение данных перед их доставкой пользователю.

С предварительно заполненными данными использование приложения SSR также может решить проблему, которая возникает у клиентских приложений с совместным использованием социальных сетей и системой OpenGraph. Например, если у вас есть только один файл index.html для доставки клиенту, у них будет только один тип метаданных — скорее всего, метаданные вашей домашней страницы. Это не будет контекстуализировано, когда вы хотите поделиться другим маршрутом, поэтому ни один из ваших маршрутов не будет отображаться на других сайтах с их надлежащим пользовательским контентом (описанием и предварительным изображением), которым пользователи хотели бы поделиться со всем миром.

Предварительный рендеринг

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

Я обнаружил это решение с помощью Preact и его собственного интерфейса командной строки, который позволяет вам скомпилировать все предварительно выбранные маршруты, чтобы вы могли хранить полностью заполненный HTML-файл на статическом сервере. Благодаря функции гидратации Preact/React вы можете предоставить пользователю сверхбыстрый опыт без необходимости использования Node.js.

Загвоздка в том, что, поскольку это не SSR, у вас нет пользовательских данных для отображения на этом этапе — это просто статический (и несколько общий) файл, отправляемый непосредственно по первому запросу, как есть. Итак, если у вас есть пользовательские данные, здесь вы можете интегрировать красиво оформленный скелет, чтобы показать пользователю, что его данные поступают, чтобы избежать некоторого разочарования с их стороны:

Использование скелета документа как части индикатора загрузки

Есть еще одна загвоздка: чтобы этот метод работал, вам все равно нужен прокси или что-то еще, чтобы перенаправить пользователя на нужный файл.

Почему?

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

Чтобы решение для предварительного рендеринга работало, вам нужно сообщить прокси-серверу, что для некоторых маршрутов нужны определенные файлы, а не всегда корневой файл index.html .

Например, у вас есть четыре маршрута ( / , /about , /jobs и blog ), и все они имеют разные макеты. Вам нужны четыре разных HTML-файла, чтобы доставить скелет пользователю, который затем позволит React/Preact/etc. увлажнить его данными. Поэтому, если вы перенаправите все эти маршруты в корневой файл index.html , страница будет иметь неприятные, глючные ощущения во время загрузки, из-за чего пользователь будет видеть скелет неправильной страницы, пока она не завершит загрузку и не заменит макет. Например, пользователь может увидеть скелет домашней страницы только с одним столбцом, когда он запросил другую страницу с галереей, похожей на Pinterest.

Решение состоит в том, чтобы сообщить прокси-серверу, что каждому из этих четырех маршрутов нужен определенный файл:

  • https://my-website.com → Перенаправление на корневой файл index.html
  • https://my-website.com/about → Перенаправить на файл /about/index.html
  • https://my-website.com/jobs → Перенаправить на файл /jobs/index.html
  • https://my-website.com/blog → Перенаправить на файл /blog/index.html

Вот почему это решение может быть полезно для небольших приложений — вы видите, как это было бы болезненно, если бы у вас было несколько сотен страниц.

Строго говоря, не обязательно делать это таким образом — вы можете просто использовать статический файл напрямую. Например, https://my-website.com/about/ будет работать без перенаправления, потому что будет автоматически искать index.html внутри своего каталога. Но вам нужен этот прокси, если у вас есть URL-адреса param — https://my-website.com/profile/guillaume нужно будет перенаправить запрос на /profile/index.html со своим собственным макетом, потому что profile/guillaume/index.html не существует и вызовет ошибку 404.

Блок-схема, показывающая, как прокси-сервер влияет на решение для предварительного рендеринга, как описано в предыдущем абзаце.


Короче говоря, есть три основных вида, используемых с описанными выше стратегиями рендеринга: экран загрузки, скелет и полная страница после ее окончательного рендеринга.

Сравнение экрана загрузки, скелета и полностью отрендеренной страницы

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

Метод Посадка (например / ) Статический (например, /about ) Фиксированный динамический (например, /news ) Параметризованный динамический (например /users/:user-id )
Клиент-рендеринг Загрузка → Полная Загрузка → Полная Загрузка → Скелет → Полный Загрузка → Скелет → Полный
Предварительно обработанный Полный Полный Скелет → Полный HTTP 404 (страница не найдена)
Предварительно обработано с помощью прокси Полный Полный Скелет → Полный Скелет → Полный
ССР Полный Полный Полный Полный

Рендеринга только для клиента часто недостаточно

Клиентские приложения — это то, чего нам сейчас следует избегать, потому что мы можем сделать их лучше для пользователя. И сделать лучше в этом случае так же просто, как и решение для предварительного рендеринга. Это определенно улучшение по сравнению с рендерингом только на клиенте, и его проще реализовать, чем приложение, полностью рендеримое на стороне сервера.

SSR/универсальное приложение может быть действительно мощным, если у вас есть большое приложение с большим количеством разных страниц. Это позволяет вашему контенту быть сфокусированным и релевантным при общении с поисковым роботом. Это также верно для роботов поисковых систем, которые теперь учитывают эффективность вашего сайта при его ранжировании.

Следите за дальнейшим руководством, в котором я расскажу о преобразовании SPA в версии с предварительным рендерингом и SSR и сравню их производительность.

Связанный: Обзор популярных генераторов статических сайтов