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

Обычное приложение Angular выполняется в браузере, отображая страницы в DOM в ответ на действия пользователя. Angular Universal выполняется на сервере, генерируя статические страницы приложений, которые позже загружаются на клиенте. Это означает, что приложение обычно отображается быстрее, что дает пользователям возможность просмотреть макет приложения, прежде чем он станет полностью интерактивным.

Зачем использовать рендеринг на стороне сервера?

Существует три основных причины для создания универсальной версии вашего приложения.

  • Облегчите работу поисковых роботов с помощью поисковой оптимизации (SEO)
  • Повышение производительности на мобильных устройствах и устройствах с низким энергопотреблением.
  • Быстрое отображение первой страницы с отрисовкой первого содержимого (FCP)

Содействие поисковым роботам (SEO)

Google, Bing, Facebook, Twitter и другие сайты социальных сетей полагаются на Интернет поисковые роботы, чтобы индексировать контент вашего приложения и сделать его доступным для поиска в Интернете. Эти веб-сканеры могут быть не в состоянии перемещаться и индексировать ваше интерактивное приложение Angular, как это может сделать пользователь.

Angular Universal может сгенерировать статическую версию вашего приложения, которая легко доступна для поиска, ссылок и навигации. без JavaScript. Universal также делает доступным предварительный просмотр сайта, поскольку каждый URL-адрес возвращает полностью обработанную страницу.

Повышение производительности на мобильных и маломощных устройствах

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

Быстро показать первую страницу

Быстрое отображение первой страницы может иметь решающее значение для взаимодействия с пользователем. 53% посещений мобильных сайтов прекращаются, если загрузка страниц занимает более 3 секунд. Возможно, вашему приложению придется запускаться быстрее, чтобы привлечь этих пользователей, прежде чем они решат заняться чем-то еще.

С помощью Angular Universal вы можете создавать целевые страницы для приложения, которые выглядят как полное приложение. Страницы представляют собой чистый HTML-код и могут отображаться даже при отключенном JavaScript. Страницы не обрабатывают события браузера, но они поддерживают навигацию по сайту с помощью Router Link.

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

Универсальные веб-серверы

Универсальный веб-сервер отвечает на запросы страницы приложения статическим HTML-кодом, отображаемым универсальным механизмом шаблонов.. Сервер получает и отвечает на HTTP-запросы от клиентов (обычно браузеров) и обслуживает статические ресурсы, такие как скрипты, CSS и изображения. Он может отвечать на запросы данных либо напрямую, либо в качестве прокси для отдельного сервера данных.

Образец веб-сервера для этого руководства основан на популярной платформе Express.

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

Универсальные приложения используют пакет Angular платформа-сервер (в отличие от платформы-браузера), который предоставляет серверные реализации DOM, XMLHttpRequest и другие низкоуровневые функции, которые не зависят от браузера.

Сервер (Node Express) передает клиентские запросы для страниц приложения в NgUniversal ngExpressEngine. Под капотом это вызывает универсальную функцию renderModuleFactory (), обеспечивая при этом кеширование и другие полезные утилиты.

Функция renderModuleFactory () принимает в качестве входных данных HTML-страницу шаблона (обычно index.html), Angular модуль, содержащий компоненты, и маршрут, определяющий, какие компоненты отображать. Маршрут исходит из запроса клиента к серверу.

Результатом каждого запроса является соответствующее представление для запрошенного маршрута. Функция renderModuleFactory () отображает представление в теге шаблона, создавая готовую HTML-страницу для клиента.

Наконец, сервер возвращает обработанную страницу клиенту.

Работа с API браузера

Поскольку универсальное приложение не выполняется в браузере, на сервере могут отсутствовать некоторые API-интерфейсы и возможности браузера.

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

Angular предоставляет некоторые вводимые абстракции над этими объектами, такие как Location или DOCUMENT; он может адекватно заменять эти API. Если Angular не предоставляет этого, можно написать новые абстракции, которые делегируют API-интерфейс браузера в браузере и альтернативную реализацию на сервере (также известную как шимминг).

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

Использование абсолютных URL-адресов для запросов к серверу

В обычных приложениях Angular запросы отправляются на относительные URL-адреса, такие как api/heroes. В универсальном приложении URL-адреса HTTP должны быть абсолютными (например, https://my-server.com/api/heroes). Это означает, что вам необходимо изменить свои службы, чтобы они выполняли запросы с абсолютными URL-адресами при работе на сервере и с относительными URL-адресами при запуске в браузере..

Одно из решений — предоставить полный URL-адрес вашего приложения на сервере и написать перехватчик, который может получить это значение и добавить его к URL-адресу запроса. Если вы используете ngExpressEngine, как показано в примере в этом руководстве, половина работы уже сделана. Мы предполагаем, что это так, но обеспечить ту же функциональность тривиально.

Начните с создания HttpInterceptor:

  import {Injectable  , Inject, Optional} из '@ angular/core'; импортировать {HttpInterceptor, HttpHandler, HttpRequest, HttpHeaders} из '@ angular/common/http'; импортировать {Request} из 'express'; импортировать {REQUEST} из '@nguniversal /express-engine/tokens '; класс экспорта @ Injectable () UniversalInterceptor реализует HttpInterceptor {constructor (@Optional () @Inject (REQUEST) защищенный запрос: Request) {} перехват (req: HttpRequest, next: HttpHandler) {let serverReq:  HttpRequest = req;  if (this.request) {let newUrl = `$ {this.request.protocol}://$ {this.request.get ('host')}`;  если (! req.url.startsWith ('/')) {newUrl + = '/';  } newUrl + = req.url;  serverReq = req.clone ({url: newUrl});  } return next.handle (serverReq);  }}  

Живая демонстрация:

Это просто фрагмент кода, объясняющий конкретную концепцию, и может не иметь любой вывод

См. Pen HttpInterceptor от w3resource (@ w3resource) на CodePen.

Затем укажите перехватчик в провайдерах для сервера AppModule (app.server.module.ts):

  импортировать {HTTP_INTERCEPTORS} из '@ angular/common/http'; импортировать {UniversalInterceptor} из './universal-interceptor'  ; @NgModule ({... провайдеры: [{provide: HTTP_INTERCEPTORS, useClass: UniversalInterceptor, multi: true}],}) класс экспорта AppServerModule {}  

Интерактивная демонстрация:

Это просто фрагмент кода, объясняющий конкретную концепцию, и может не иметь вывода

См. Pen app.server.module .ts от w3resource (@ w3resource) на CodePen.

Теперь при каждом HTTP-запросе, сделанном на сервере, этот перехватчик срабатывает и заменяет URL-адрес запроса предоставленным абсолютным URL-адресом. в объекте экспресс-запроса.

Универсальный шаблонизатор

Важным элементом в файле server.ts является функция ngExpressEngine ().

  app.engine ('html', ngExpressEngine ({bootstrap: AppServerModuleNgFactory, провайдеры: [provideModuleMap (LAZY_MODULE_MAP)]}));  

Живая демонстрация:

Это просто фрагмент кода, объясняющий конкретную концепцию и не имеющий вывода

См. сервер Pen .ts от w3resource (@ w3resource) на CodePen.

Функция ngExpressEngine () — это оболочка для функции renderModuleFactory () Universal, которая превращает запросы клиента в HTML-страницы, отображаемые на сервере. .

  • Первый параметр — AppServerModule. Это мост между универсальным серверным средством визуализации и приложением Angular.
  • Второй параметр, extraProviders, необязательный. Он позволяет вам указывать поставщиков зависимостей, которые применяются только при работе на этом сервере. Вы можете сделать это, когда вашему приложению нужна информация, которую может определить только текущий запущенный экземпляр сервера. Одним из примеров может быть источник запущенного сервера, который можно использовать для вычисления абсолютных URL-адресов HTTP, если не используется токен запроса, как показано выше.

Функция ngExpressEngine () возвращает обратный вызов Promise который преобразуется в отображаемую страницу. Что делать с этой страницей, зависит от движка. Обратный вызов Promise этого движка возвращает обработанную страницу на веб-сервер, который затем пересылает ее клиенту в ответе HTTP.

Примечание. Эти оболочки помогают скрыть сложность функции renderModuleFactory (). В универсальном репозитории есть больше оболочек для различных серверных технологий.

Фильтрация URL-адресов запросов

ПРИМЕЧАНИЕ: основное поведение описано ниже обрабатывается автоматически при использовании схемы NgUniversal Express, это полезно при попытке понять базовое поведение или воспроизвести его без использования схемы.

Веб-сервер должен отличать запросы страницы приложения от других типов запросов. .

Это не так просто, как перехватить запрос на корневой адрес/. Браузер может запросить один из маршрутов приложения, например/dashboard,/heroes или/detail: 12. Фактически, если бы приложение отображалось только сервером, каждая щелкнутая ссылка на приложение поступала бы на сервер как URL-адрес навигации, предназначенный для маршрутизатора.

К счастью, у маршрутов приложений есть нечто общее: их В URL-адресах отсутствуют расширения файлов. (Запросы данных также не имеют расширений, но их легко распознать, потому что они всегда начинаются с/api.) Все запросы статических ресурсов имеют расширение файла (например, main.js или/node_modules/zone.js/dist/zone.

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

  1. Запрос данных: URL-адрес запроса, который начинается/api.
  2. Навигация по приложению: URL-адрес запроса без расширения файла.
  3. Статический актив: все остальные запросы.

Узел Сервер Express — это конвейер промежуточного программного обеспечения, которое фильтрует и обрабатывает запросы один за другим. Вы настраиваете конвейер сервера Node Express с помощью вызовов app.get (), как этот для запросов данных.

 //TODO: безопасно реализовать запросы данныхapp.get ('/api/*', (req, res) => {res.status (404) .send ('запросы данных не поддерживаются');});   

Live Demo:

Это просто фрагмент кода, объясняющий конкретную концепцию и не имеющий никакого вывода t

См. Pen server.ts (URL-адрес данных) от w3resource (@ w3resource) на CodePen.

Примечание. В этом примере сервера нет t обрабатывать запросы данных.

Модуль обучающего веб-API в памяти, демонстрационный инструмент и инструмент разработки, перехватывает все HTTP-вызовы и имитирует поведение удаленного сервера данных. На практике вы бы удалили этот модуль и зарегистрировали промежуточное программное обеспечение веб-API на сервере.

Следующий код фильтрует URL-адреса запросов без расширений и обрабатывает их как запросы навигации.

 //Все обычные маршруты используют универсальный движокapp.get ('*', (req, res) => {res.render ('index', {req});});  

Живая демонстрация:

Это просто фрагмент кода, объясняющий конкретную концепцию и не имеющий вывода

См. Pen server.ts (навигация) от w3resource (@ w3resource) на CodePen.

Безопасное обслуживание статических файлов

Один app.use () обрабатывает все остальные URL-адреса как запросы статических ресурсов, таких как JavaScript, файлы изображений и стилей.

Чтобы гарантировать, что клиенты могут загружать только те файлы, которые им разрешено просматривать, помещать все клиентские файлы ресурсов в папку/dist и выполнять запросы на файлы только из папки/dist.

Следующий Node Express код маршрутизирует все rem отправляет запросы к/dist и возвращает ошибку 404 — НЕ НАЙДЕН, если файл не найден.

 //Сервер статических файлов из/browserapp.get('*.  * ', express.static (join (DIST_FOLDER,' browser ')));  

Живая демонстрация:

Это просто фрагмент кода, объясняющий конкретную концепцию, и может не иметь вывода

См. Pen server.ts (статические файлы) от w3resource (@ w3resource) на CodePen.

Оцените статью
nanomode.ru
Добавить комментарий