Русский
Русский
English
Статистика
Реклама

Перевод Что такое рендеринг на стороне сервера и нужен ли он мне?

Привет, Хабр!

В новом году начнем общение с вами с затравочной статьи о серверном рендеринге (server-side rendering). В случае вашей заинтересованности возможна более свежая публикация о Nuxt.js и дальнейшая издательская работа в этом направлении


С появлением современных фреймворков и библиотек для JavaScript, которые предназначены, прежде всего, для создания интерактивных веб-страниц и одностраничных приложений, сильно изменился весь процесс показа страниц пользователю.

До пришествия приложений, полностью генерируемых на JS в браузере, HTML-разметка выдавалась клиенту в ответ на HTTP-вызов. Это могло происходить путем возврата статического HTML-файла с контентом, либо путем обработки отклика при помощи какого-либо серверного языка (PHP, Python или Java), причем, более динамическим образом.

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

Типичный отклик, отправляемый сервером на запрос к сайту, написанному на React, будет выглядеть примерно так:

<!DOCTYPE html><html lang="en">  <head>    <meta charset="utf-8">    <link rel="shortcut icon" href="http://personeltest.ru/aways/habr.com/favicon.ico">    <title>React App</title>  </head>  <body>    <div id="root"></div>    <script src="http://personeltest.ru/aways/habr.com/app.js"></script>  </body></html>


Выбрав этот отклик, наш браузер также выберет пакет app.js, содержащий наше приложение, и через одну-две секунды полностью отобразит страницу.

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

Почему это проблема?



Хотя такое поведение и не доставит проблем большинству наших пользователей либо при разработке приложения, оно может стать нежелательным, если:

  • Конечный пользователь работает с медленным интернет-соединением, что особенно актуально для мобильных устройств,
  • Конечный пользователь работает с маломощным устройством, например, со смартфоном старого поколения


Если с демографической точки зрения ваша целевая аудитория относится к одной из этих групп, то работать с сайтом будет неудобно в частности, пользователям придется довольно долго ждать, уставившись в надпись Loading (или того хуже в пустой экран).

Ладно, но в демографическом отношении моя целевая аудитория точно не относится ни к одной из этих групп, так стоит ли мне волноваться?

Есть еще две вещи, которые следует учитывать при работе с приложением, рендеринг в котором выполняется на стороне клиента: поисковики и присутствие в социальных сетях.

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

Это означает, что вашему сайту будет очень непросто забраться в топ выдачи любого поисковика кроме Google.

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

Как решить эту проблему



Есть несколько способов ее решения.

A Попробуйте оставить все ключевые страницы вашего сайта статическими



Когда создается сайт-платформа, куда пользователю придется входить под своим логином, а без входа в систему контент посетителю не предоставляется, можно попробовать оставить статическими (написанными на HTML) общедоступные страницы вашего сайта, в частности, индекс, о нас, контакты и не использовать JS при их отображении.

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

B Генерируйте части вашего приложения в виде HTML-страниц в процессе сборки



В проект можно добавить такие библиотеки как react-snapshot; они используются для генерации HTML-копий страниц вашего приложения и для сохранения их в специально предназначенном каталоге. Затем этот каталог развертывается наряду с пакетом JS. Таким образом, HTML будет подаваться с сервера вместе с откликом, и ваш сайт увидят в том числе те пользователи, у которых отключен JavaScript, а также заметят поисковики и т.д.

Как правило, сконфигурировать react-snapshot не составляет труда: достаточно добавить библиотеку в ваш проект и изменить сборочный скрипт следующим образом:

"build": "webpack && react-snapshot --build-dir static"

Недостаток такого решения заключается в следующем: весь контент, который мы хотим сгенерировать, должен быть доступен во время сборки мы не можем обратиться к каким-либо API, чтобы получить его, мы также не можем заранее сгенерировать контент, зависящий от данных, предоставляемых пользователем (например, от URL).

C Создать на JS приложение, использующее серверный рендеринг



Один из важнейших выигрышных моментов у современного поколения приложений на JS заключается в том, что их можно запускать как на клиенте (в браузере), так и на сервере. Так удается генерировать HTML для страниц, являющихся более динамичными, таких, чей контент в период сборки еще не известен. Подобные приложения часто называют изоморфными или универсальными.

Два наиболее популярных решения, обеспечивающих серверный рендеринг для React:



Создайте собственную реализацию SSR



Важно: если вы собираетесь попробовать самостоятельно создать собственную реализацию SSR для приложений на React, то должны будете обеспечить работу node-бэкенда для вашего сервера. Вы не сможете развернуть это решение на статическом хосте, как в случае со страницами github.

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

Давайте создадим входную точку:

// index.jsimport React from 'react';import { render } from 'react-dom';import App from './App.js';render(<App />, document.getElementById('root'));


И компонент-приложение (App):

// App.jsimport React from 'react';const App = () => {  return (    <div>      Welcome to SSR powered React application!    </div>  );}


А также оболочку, чтобы загрузить наше приложение:

// index.html<!doctype html><html>  <head>    <meta charset="utf-8" />  </head>  <body>    <div id="root"></div>    <script src="http://personeltest.ru/aways/habr.com/bundle.js"></script>  </body></html>


Как видите, приложение получилось довольно простым. В рамках этой статьи мы не будем пошагово разбирать все шаги, необходимые для генерации правильной сборки webpack+babel.
Если запустить приложение в его текущем состоянии, то на экране появится сообщение-приветствие. Просмотрев исходный код, вы увидите содержимое файла index.html, но приветственного сообщения там не будет. Для решения этой проблемы добавим серверный рендеринг. Для начала добавим 3 пакета:

yarn add express pug babel-node --save-dev

Express это мощный веб-сервер для node, pug движок-шаблонизатор, который можно использовать с express, а babel-node это обертка для node, обеспечивает транспиляцию на лету.

Сначала скопируем наш файл index.html и сохраним его как index.pug:

// index.pug
<!doctype html>
<html>
<head>
<meta charset=utf-8 />
</head>
<body>
<div id=root>!{app}</div>
<script src=bundle.js></script>
</body>
</html>

Как видите, файл практически не изменился, не считая того, что теперь в HTML вставлено !{app}. Это переменная pug, которая впоследствии будет заменена реальным HTML.

Создадим наш сервер:

// server.jsimport React from 'react';import { renderToString } from 'react-dom/server';import express from 'express';import path from 'path';import App from './src/App';const app = express();app.set('view engine', 'pug');app.use('/', express.static(path.join(__dirname, 'dist')));app.get('*', (req, res) => {  const html = renderToString(    <App />  );  res.render(path.join(__dirname, 'src/index.pug'), {    app: html  });});app.listen(3000, () => console.log('listening on port 3000'));


Разберем этот файл по порядку.

import { renderToString } from 'react-dom/server';

Библиотека react-dom содержит отдельный именованный экспорт renderToString, работающий подобно известному нам render, но отображает не DOM, а HTML в виде строки.

const app = express();app.set('view engine', 'pug');app.use('/', express.static(path.join(__dirname, 'dist')));


Мы создаем новый инстанс сервера express и сообщаем ему, что собираемся использовать движок-шаблонизатор pug. В данном случае мы могли бы обойтись обычным считыванием файла и выполнением операции поиск с заменой, но такой подход в самом деле неэффективен и может спровоцировать проблемы из-за множественного доступа к файловой системе, либо проблемы с кэшированием.

В последней строке мы приказываем express искать файл в каталоге dist, и, если запрос (напр. /bundle.js) совпадает с файлом, присутствующем в этом каталоге, то выдать его в ответ.

app.get('*', (req, res) => {});


Теперь мы приказываем express добавить обработчик на каждый несовпавший URL в том числе, на наш несуществующий файл index.html (как вы помните, мы переименовали его в index.pug, и его нет в каталоге dist).

const html = renderToString(  <App />);


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

res.render(path.join(__dirname, 'src/index.pug'), {  app: html});


Теперь, когда у нас есть отображенный HTML, мы приказываем express отобразить в ответ файл index.pug и заменить переменную app тем HTML, что мы получили.

app.listen(3000, () => console.log('listening on port 3000'));

Наконец, мы обеспечиваем запуск сервера и настраиваем его так, чтобы он слушал порт 3000.
Теперь нам осталось всего лишь добавить нужный скрипт в package.json:

"scripts": {  "server": "babel-node server.js"}


Теперь, вызвав yarn run server, мы должны получить подтверждение, что сервер действительно работает. Переходим в браузере по адресу localhost:3000, где мы, опять же, должны увидеть наше приложение. Если мы просмотрим исходный код на данном этапе, то увидим:

<!doctype html><html>  <head>    <meta charset="utf-8" />  </head>  <body>    <div id="root">div data-reactroot="">Welcome to SSR powered React application!</div></div>    <script src="bundle.js"></script>  </body></html>


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

Зачем же нам по-прежнему нужен bundle.js?



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

Это позволит браузерам, умеющим обрабатывать JavaScript, взять работу на себя и далее взаимодействовать с вашей страницей уже на стороне клиента, а тем, что не умеют разбирать JS перейти на страницу с нужным HTML, который возвратил сервер.

О чем необходимо помнить



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

  • Любое состояние, сгенерированное на стороне сервера, не будет передаваться в состояние клиентского приложения. Это означает, что, если ваша серверная часть выберет некоторые данные и использует их для отображения HTML, то эти данные не попадут в this.state, которое увидит браузер
  • componentDidMount не вызывается на сервере это означает, что не будут вызываться никакие операции по выборке данных, которые вы привыкли там размещать. В принципе, это хорошо, поскольку вы должны предоставлять нужные вам данные в виде пропсов. Помните, что отображение нужно отложить (вызвав res.render) до тех пор, пока данные не будут выбраны. Из-за этого посетители могут заметить некоторые задержки в работе сайта
  • если вы собираетесь использовать роутер react (напр. @reach/router или react-router) то должны убедиться, что приложению передается правильный URL, когда оно отображается на сервере. Обязательно почитайте об этом в документации!
Источник: habr.com
К списку статей
Опубликовано: 04.01.2021 10:13:21
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании издательский дом «питер»

Javascript

Программирование

Html

Node.js

Js

Server-side rendering

React

Веб-разработка

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru