Угловой универсальный и серверный рендеринг (шаг за шагом)

  1. Что такое Angular Universal?
  2. Рендеринг угловой на сервере
  3. Классический подход:
  4. Предоставленная сторона сервера:
  5. Статический против Динамического
  6. статический
  7. динамический
  8. Рендеринг во время сборки
  9. Почему вы должны рендерить на сервере?
  10. SEO
  11. Пользовательский опыт
  12. Угловая универсальная: серебряная пуля?
  13. Требуется сервер
  14. Не легко настроить
  15. Угловой универсальный пример [шаг за шагом]
  16. Создание дополнительных модулей
  17. Модуль браузера
  18. Серверный модуль
  19. Создание второго приложения для CLI
  20. Рендеринг на стороне сервера
  21. Настройка сервера динамического рендеринга
  22. Создание сервера Node.js
  23. Настройка статического рендерера
  24. Настроить
  25. Настройка сервера для поддержки отложенной загрузки
  26. API Angular Transfer State (только Angular 5)
  27. Но как мы можем улучшить это?
  28. Реализация API состояния передачи
  29. Использование API Transfer State
  30. Заключение

Вы, вероятно, согласны со мной, когда я говорю:

С Angular Universal нелегко разобраться с первого раза.

Что ж, оказывается, это совсем не сложно!

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

В этом уроке я покажу вам, что такое угловая универсальность и как она работает. Как только мы получим основы, мы погрузимся прямо в код! Превратив базовый проект angular-cli в функциональное универсальное приложение, вы не только увидите, как это делается шаг за шагом. Вы также получите рабочий шаблон для рендеринга на стороне сервера, который вы можете использовать для будущих угловых приключений. Все, что вам нужно, чтобы начать это универсальное угловое руководство.

Итак, давайте погрузимся прямо в! Итак, давайте погрузимся прямо в

Что такое Angular Universal?

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

"Подождите? Почему ты говоришь в прошедшем времени?

Потому что с версии 4.0 angular, angular universal слился в основной каркас. Теперь он поставляется вместе с основными угловыми пакетами. Имена пакетов: платформа-сервер и платформа-браузер.

Angular теперь может работать одинаково на большинстве платформ. Самое главное, он может быть запущен на сервере сейчас. Это обеспечивает целый набор новых возможностей, таких как рендеринг под углом в html на сервере. Но как это вообще работает?

Рендеринг угловой на сервере

По своей сути angular - это просто html-парсер. Когда вы создаете свое угловое приложение, ваши шаблоны анализируются из разметки HTML в код JavaScript. Этот код JavaScript создаст проанализированные HTML-элементы во время выполнения в браузере. Но рендеринг этого HTML теперь требует загрузки полной угловой (основной) инфраструктуры.

Как мы узнали ранее, angular также может работать на серверах node.js. Из-за этого также возможно генерировать этот проанализированный HTML на сервере. В результате получается просто HTML, который сервер затем может отправить клиенту.

Классический подход:

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

Предоставленная сторона сервера:

Когда мы выполняем рендеринг на сервере под углом, все, что нужно для перемещения по проводам, - это сам html. Чтобы дать вам некоторые цифры здесь. HTML-документ для статьи в блоге может быть скачан около 50 КБ. Конечно, не считая изображений. С другой стороны, вам будет нелегко довести угол до 150кб в сжатом виде. И этот номер не содержит содержания самой страницы. Это просто размер угловых файлов JavaScript. Это более чем в три раза больше! Теперь представьте своих мобильных пользователей. Это в три раза больше времени, которое загружает ваше приложение (приблизительно).

Статический против Динамического

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

статический

Первый - тот, который вы видите на картинке выше. Мы отображаем HTML-код нашей страницы / приложения. Этот HTML-код содержит только сам HTML-код и необходимый CSS-код для отображения страницы. В этих данных нет JavaScript. Это может быть хорошо или плохо. Это хорошо, если мы не полагаемся на JavaScript для нашего приложения. Это может иметь место при отображении поста в блоге. Поскольку нам не нужен JavaScript, размер загружаемых данных относительно невелик. Если вы полагаетесь на JavaScript, например, чтобы показать всплывающее окно, которое не может работать, если оно не включено в загруженный файл. Конечно, есть способы обойти это, но это довольно быстро. Узнайте больше об этом в этом статья о типичных ошибках при рендеринге на стороне сервера ,

динамический

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

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

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

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

Рендеринг во время сборки

Другим возможным решением может быть рендеринг статического HTML во время сборки. При этом, однако, вам придется пересобирать каждый раз, когда меняется ваш динамический контент. Этот метод избавляет вас от настройки производственного сервера. С другой стороны. этот метод может очень быстро запутаться. Я бы порекомендовал его, только если у вас нет динамического контента, или он почти никогда не меняется. Другим возможным решением может быть рендеринг статического HTML во время сборки

Почему вы должны рендерить на сервере?

На данный момент, вы можете подумать:

«Почему мы вообще думаем обо всем этом?»

Оказывается, рендеринг под углом на сервере приносит большие преимущества. Вот некоторые из них:

SEO

«Поисковая оптимизация» , Поскольку угловые приложения в большой степени зависят от JavaScript, большинство поисковых систем испытывают проблемы с очисткой содержимого приложения. На самом деле, большинство поисковых систем даже не выполняют JavaScript. В этом случае мы представили бы им пустую страницу. Ой! Чтобы предотвратить это, мы можем визуализировать наше приложение на сервере и отправить обратно обработанный HTML. В результате получается простой HTML, теперь сканер может правильно проиндексировать нашу страницу.

Поисковые системы - не единственные, которые бунтуют, когда видят JavaScript. Большинство скребков контента сайтов социальных сетей также игнорируют JavaScript. Поэтому, когда мы публикуем ссылку на нашу страницу, мы не получим милую маленькую карточку с нашей страницей. Опять же, у них нет проблем с обработкой HTML. Примерами сайтов социальных сетей, которые используют скребки контента, являются Facebook, Twitter, Reddit и многие другие.

Пользовательский опыт

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

Угловая универсальная: серебряная пуля?

Хотя рендеринг на стороне сервера (angular 4 universal) имеет много преимуществ, он также имеет свои недостатки. Вот некоторые из них:

Требуется сервер

Как уже предполагает рендеринг на стороне сервера имен, веб-сервер необходим для предварительного рендеринга страниц. В то время как обычные угловые приложения содержат только статические файлы, при рендеринге на стороне сервера нам нужно вычислять HTML во время выполнения. Так почему же это недостаток? Ну, хотя хостинг не стоит миру, он обычно не бесплатный / дешевый. Не упоминать административные усилия для поддержки сервера. С другой стороны, со статическими файлами вы можете получить статический хостинг файлов бесплатно или очень дешево. Кроме того, эти услуги обычно очень хорошо масштабируются, без каких-либо усилий на вашей стороне.

Не легко настроить

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

Угловой универсальный пример [шаг за шагом]

В следующих главах мы создадим базовое угловое приложение, используя angular-cli.

После этого мы собираемся подготовить его для рендеринга на стороне сервера. Мы также собираемся внедрить необходимый сервер в node.js.

Итак, давайте создадим новое приложение, используя angular-cli:

нг новый рендеринг на стороне сервера

Сгенерированное приложение будет основой для наших следующих шагов.

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

Кроме того, некоторые функции просто не нужно отображать на сервере. Какой смысл иметь, например, Google Analytics на сервере?

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

Итак, начнем!

Создание дополнительных модулей

Для начала нам нужно создать два дополнительных модуля в каталоге приложений. Рядом с app.module.ts создайте файл с именем browser.app.module.ts и файл с именем server.app.module.ts. Если вы хотите узнать больше о модулях, проверьте это статья об угловых модулях !

Модуль браузера

Модуль приложения для браузера очень прост. Все, что нам нужно сделать, это вызвать BrowserModule.withServerTransition. Этот метод сообщает angular, что мы используем рендеринг на стороне сервера и что представление необходимо поменять местами после загрузки полной структуры. Этот метод ожидает объект с ключом с именем appId. Вы можете ввести любую строку здесь. Просто убедитесь, что строка в нашем модуле приложения браузера совпадает со строкой в ​​модуле приложения сервера.

src / app / browser.app.module.ts import {AppModule} из './app.module' import {BrowserModule} из '@ angular / platform-browser' import {NgModule} из '@ angular / core' import {AppComponent } из './app.component' @ NgModule ({объявлений: [], импорт: [BrowserModule. withServerTransition ({appId: 'my-app-id',}), AppModule,], поставщики: [], начальная загрузка: [AppComponent],}) класс BrowserAppModule {}

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

Серверный модуль

На данный момент наш серверный модуль выглядит в основном так же, как модуль браузера. Разница лишь в том, что нам нужно импортировать угловой модуль с именем ServerModule. Этот модуль не установлен angular-cli. Чтобы установить его, используйте одну из следующих команд:

yarn add @ angular / platform-server npm install @ angular / platform-server - сохранить импорт {AppModule} из './app.module'; импортировать {BrowserModule} из '@ angular / platform-browser'; импортировать {NgModule} из '@ angular / core'; // Установлен отдельный импорт {ServerModule} из '@ angular / platform-server'; import {AppComponent} из './app.component'; @NgModule ({объявлений: [], импорт: [// Убедитесь, что строка соответствует BrowserModule.withServerTransition ({appId: 'my-app-id'}), ServerModule, AppModule], поставщики: [], начальная загрузка: [AppComponent ]}) class ServerAppModule {}

Создание второй точки входа Обычно наше угловое приложение имеет только одну точку входа. То есть там, где вызывается метод начальной загрузки. В проекте cli этот вызов находится в файле main.ts в каталоге src. Мы можем оставить этот файл как есть. Это будет отправной точкой для нашей версии браузера.

Чтобы создать точку входа для нашей версии сервера, просто создайте другой файл прямо рядом с main.ts. Давайте назовем это server.main.ts. Содержание этого файла действительно просто. Просто экспортируйте наш серверный модуль туда.

экспортировать {ServerAppModule} из './app/server.app.module'

Рассказывая угловому компилятору о наших модулях ввода, чтобы это работало, мы также должны сообщить угловому компилятору, какими являются наши модули ввода. Для этого нам понадобятся два отдельных файла tsconfig.json, которые находятся в каталоге приложения src. По умолчанию cli генерирует здесь файл с именем tsconfig.app.json. Просто переименуйте его в tsconfig.browser.json. Просто чтобы прояснить ситуацию. Кроме того, создайте еще один файл с именем tsconfig.server.json.

Бот-файлы действительно просты. Вот как они выглядят:

src / tsconfig.browser.json {"extends": "../tsconfig.json", "angularCompilerOptions": {"entryModule": "./app/browser.app.module#BrowserAppModule"}, "exclude": [ "test.ts", "** / *. spec.ts"]} {"extends": "../tsconfig.json", "angularCompilerOptions": {"entryModule": "./app/server.app. module # ServerAppModule "}," exclude ": []}

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

Создание второго приложения для CLI

Последнее, что нам нужно сделать, это отредактировать angular-cli.json. Нам нужно сообщить CLI обо всех внесенных нами изменениях, чтобы он работал правильно. Кроме того, мы собираемся создать второй профиль для комплекта серверов. Затем cli генерирует этот пакет, содержащий только тот код, который нам требуется на сервере для рендеринга.

Короче говоря, вот как должен выглядеть раздел «apps» в angular-cli.json.

"apps": [{"root": "src", "outDir": "dist", "assets": ["assets", "favicon.ico"], "index": "index.html", "main ":" main.ts "," polyfills ":" polyfills.ts "," test ":" test.ts "," tsconfig ":" tsconfig.browser.json "," testTsconfig ":" tsconfig.spec.json "," prefix ":" app "," styles ": [" styles.css "]," scripts ": []," environmentSource ":" environment / environment.ts "," Environment ": {" dev ": "environment / environment.ts", "prod": "environment / environment.prod.ts"}}, {"root": "src", "outDir": "dist-server", "assets": ["assets "," favicon.ico "]," index ":" index.html "," main ":" server.main.ts "," platform ":" server "," polyfills ":" polyfills.ts "," test ":" test.ts "," tsconfig ":" tsconfig.server.json "," testTsconfig ":" tsconfig.spec.json "," prefix ":" app "," styles ": [" styles.css "]," scripts ": []," environmentSource ":" environment / environment.ts "," environment ": {" dev ":" environment / environment.ts "," prod ":" environment / env ironment.prod.ts "}}],

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

Клиентский пакет:

Серверный комплект:

Корневой каталог ваших приложений теперь должен содержать папку «dist» и «dist-server».

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

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

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

Посмотрите:

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

Настройка сервера динамического рендеринга

Для рендеринга на стороне сервера мы будем использовать внешний пакет, как я упоминал ранее. Этот пакет называется @ Nguniversal / экспресс-двигатель , Чтобы установить его, используйте одну из следующих команд.

@ Nguniversal / экспресс-двигатель

пряжа add @ nguniversal / express-engine npm install @ nguniversal / express-engine --save

Конечно, мы также требуем экспресс сам.

экспресс

пряжа добавить экспресс npm установить экспресс --save

Создание сервера Node.js

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

require ('zone.js / dist / zone-node') const express = require ('express') const ngExpressEngine = require ('@ nguniversal / express-engine / modules / express-engine'). ngExpressEngine const fs = require ('fs')

Далее нам нужно импортировать файл main. {Hash} .bundle.js из нашего каталога dist-server, созданного angular-cli. Но есть проблема: поскольку имя файла содержит хеш файла, имя файла меняется при каждой новой сборке (если что-то меняется). Одним из вариантов решения этой проблемы было бы использование флага «output-hashes none» angular-cli. Таким образом, хэш не добавляется к имени файла.

ng build --prod --app 1 - output-hashes none

Если вы хотите сохранить хеш, вы также можете сделать это:

var files try {files = fs. readdirSync (`$ {process. cwd ()} / dist-server`)} catch (error) {console. ошибка (ошибка)} var mainFiles = files. фильтр (файл => файл. startWith ('main')) var split = mainFiles [0]. split ('.') var hash = '' if (split .length> 3) hash = split [1] + '.' var {ServerAppModuleNgFactory, LAZY_MODULE_MAP,} = require (`./dist-server/main. $ {hash} bundle`)

Затем мы создаем приложение Express, вызывая express ().

После этого создайте и укажите механизм просмотра. Для этого мы используем импортированный и установленный ранее ngExpressEngine.

приложение движок (приложение "html", ngExpressEngine ({bootstrap: ServerAppModuleNgFactory, поставщики: [поставщик],})). приложение set ('view engine', 'html'). set ('views', __dirname)

Мы также должны обслуживать наши статические угловые файлы. Для этого мы добавляем в приложение dist и папку assets.

приложение использовать (express. static (__dirname + '/ assets', {index: false})) приложение. использовать (express. static (__dirname + '/ dist', {index: false}))

Затем нам нужно установить маршрут по умолчанию, который вызывает механизм представления ngExpress.

приложение get ('/ *', (req, res) => {console. time (`GET: $ {req .originalUrl}`) res. render ('./dist/index', {req: req, res: res ,}) console. timeEnd (`GET: $ {req .originalUrl}`)})

Наконец, запустите приложение, позвонив:

приложение слушай (процесс .env .PORT || 8080, () => {})

Настройка статического рендерера

Как мы узнали ранее, при обслуживании статических файлов HTML не содержит ссылок на скрипты для загрузки угловой структуры. Все, что нам нужно сделать, чтобы предотвратить загрузку всего фреймворка, это исключить ссылки на скрипты из нашего index.html. Для этого просто используйте index.html в нашей папке src вместо папки dist, так как она не содержит этих ссылок.

приложение get ('/ *', (req, res) => {console. time (`GET: $ {req .originalUrl}`) res. render ('./src/index', {req: req, res: res ,}) console. timeEnd (`GET: $ {req .originalUrl}`)})

Теперь мы обслуживаем полностью статичные файлы, которые содержат только HTML и соответствующие таблицы стилей. В зависимости от варианта использования ваших приложений может иметь смысл предоставлять эти статические файлы только вашим клиентам. Если ваше приложение не содержит необычных функций JavaScript, например, блог, вы можете значительно повысить производительность. Не обслуживая угловой код JavaScript, вы обычно сохраняете около 100 КБ сжатых данных. Большое приложение может легко пойти выше этого.

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

Все, что я говорю, это то, что вы должны тщательно выбирать свои инструменты

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

Этот пакет называется @ nguniversal / module-map-ngfactory-loader. Что он делает, так это создает карту всех лениво загруженных модулей и их маршрутов.

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

Это может показаться немного сложным, но не волнуйтесь. Тяжелая работа для нас уже проделана.

Все, что нам нужно сделать, это установить этот пакет и добавить несколько строк кода в наше приложение.

Примечание: я предполагаю, что у вас уже есть угловое приложение, которое использует отложенную загрузку. Если вы не знаете, как вы можете использовать ленивую загрузку, вы должны проверить это отличная статья от rangle.io о лениво загружаемых модулях ,

Итак, начнем!

Настроить

Как я уже упоминал ранее, нам нужно установить пакет @ nguniversal / module-map-ngfactory-loader для продолжения. Идите вперед и установите его, используя ваш любимый менеджер пакетов.

пряжа add @ nguniversal / module-map-ngfactory-loader npm install @ nguniversal / module-map-ngfactory-loader --save

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

src / app / server.app.module.ts import {ModuleMapLoaderModule} из '@ nguniversal / module-map-ngfactory-loader'

После этого ваш серверный модуль приложения должен выглядеть примерно так:

src / app / server.app.module.ts import {AppModule} из './app.module' import {BrowserModule} из '@ angular / platform-browser' import {NgModule} из '@ angular / core' import {ServerModule } из '@ angular / platform-server' import {ModuleMapLoaderModule} из '@ nguniversal / module-map-ngfactory-loader' import {AppComponent} из './app.component' @ NgModule ({объявления: [], импорт: [BrowserModule. WithServerTransition ({appId: 'my-app-id',}), ServerModule, AppModule, ModuleMapLoaderModule,], поставщики: [], начальная загрузка: [AppComponent],}) class ServerAppModule {}

Как только это будет сделано, мы теперь должны немного изменить наш сервер.

Настройка сервера для поддержки отложенной загрузки

На стороне сервера нам также необходимо импортировать пакет @ nguniversal / module-map-ngfactory-loader. Точнее, нам нужен метод с именем provideModuleMap (). Чтобы получить этот метод, мы можем просто потребовать его из пакета.

const {provideModuleMap} = require ('@ nguniversal / module-map-ngfactory-loader')

Кроме того, нам нужно импортировать карту модуля, которую создало для нас наше угловое приложение. Для этого нам нужно это из нашего углового комплекта сервера.

const {ServerAppModuleNgFactory, LAZY_MODULE_MAP,} = require (`. / dist-server / main.bundle`)

Примечание: я использовал флаг -output-hashes none для angular-cli при создании этого пакета, чтобы удалить хеш из имени файла.

Далее мы вызываем метод provideModuleMap () и передаем ему карту модулей.

const provider = provideModuleMap (LAZY_MODULE_MAP)

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

приложение engine ('html', ngExpressEngine ({bootstrap: ServerAppModuleNgFactory, провайдеры: [поставщик],}))

Вот и все. Теперь наше угловое универсальное приложение на стороне сервера знает обо всех маршрутах. Ленивый или нет.

Легко не так ли? Теперь, для вашего удобства, вот снова полное приложение server.js. Опять же, используя флаг «output-hashes none» angular-cli следующим образом:

ng build --prod --app 1 - output-hashes none // Angular требует Zone.js require ('zone.js / dist / zone-node'); const express = require ('express'); const ngExpressEngine = require ('@ nguniversal / express-engine'). ngExpressEngine; const {ServerAppModuleNgFactory, LAZY_MODULE_MAP} = require (`. / dist-server / main.bundle`); const app = express (); const {provideModuleMap} = require ('@ nguniversal / module-map-ngfactory-loader'); const provider = provideModuleMap (LAZY_MODULE_MAP); app.engine ('html', ngExpressEngine ({bootstrap: ServerAppModuleNgFactory, поставщики: [поставщик]})); app.set ('view engine', 'html'); app.set ('views', __dirname); app.use (express.static (__dirname + '/ assets', {index: false})); app.use (express.static (__dirname + '/ dist', {index: false})); app.get ('/ *', (req, res) => {console.time (`GET: $ {req.originalUrl}`); res.render ('./ dist / index', {req: req, res: res}); console.timeEnd (`GET: $ {req.originalUrl}`);}); app.listen (process.env.PORT || 8080, () => {});

PORT || 8080, () => {});

API Angular Transfer State (только Angular 5)

Angular 5 добавил API передачи состояния в угловой пакет. Это позволяет нам отправлять информацию с сервера, который представляет наше приложение, клиенту. Почему это полезно?

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

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

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

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

Но это не должно быть все о HTTP-запросах. Может быть, у вас есть серьезные расчеты, чтобы сделать. Не будет ли это пустой тратой, если вам нужно будет рассчитать это дважды?

Но как мы можем улучшить это?

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

Поскольку мы получаем все это в одном HTTP-ответе, мы также сохраняем задержку отправки другого запроса данных.

Реализация API состояния передачи

Добавить API состояния передачи в ваше приложение довольно просто. Все, что нам нужно сделать, это добавить Browser / Server-TranferStateModule в соответствующий модуль, и мы готовы к работе.

Для этого нам нужно добавить BrowserTransferStateModule в BrowserAppModule и ServerTransferStateModule в ServerAppModule.

src / app / browser.app.module.ts import {AppModule} из «./app.module» import {BrowserModule, BrowserTransferStateModule,} из «@ angular / platform-browser» import {NgModule} из «@ angular / core» import {AppComponent} из './app.component' @ NgModule ({объявлений: [], импорт: [BrowserModule. withServerTransition ({appId: 'my-app-id',}), BrowserTransferStateModule, AppModule,], провайдеры: [], начальная загрузка: [AppComponent],}) класс BrowserAppModule {}

И то же самое для сервера ...

src / app / server.app.module.ts import {AppModule} из './app.module' import {BrowserModule} из '@ angular / platform-browser' import {NgModule} из '@ angular / core' import {ServerModule , ServerTransferStateModule,} из '@ angular / platform-server' import {ModuleMapLoaderModule} из '@ nguniversal / module-map-ngfactory-loader' import {AppComponent} из './app.component' @ NgModule ({декларации: [] , импортирует: [BrowserModule. withServerTransition ({appId: 'my-app-id',}), ServerModule, AppModule, ModuleMapLoaderModule, ServerTransferStateModule,], поставщики: [], bootstrap: [AppComponent],}) класс ServerAppModule {}

Использование API Transfer State

Теперь, когда мы все настроили, мы можем использовать API состояния передачи, запрашивая экземпляр службы через внедрение зависимости , Для этого примера мы используем компонент с именем post.component.

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

src / app / post / post.component.ts private isServer: логический; конструктор (личное tstate: TransferState, @ Inject (PLATFORM_ID) platformId) {this. isServer = isPlatformServer (platformId); }

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

Каждое значение может быть доступно через ключ. Чтобы создать, получить или установить значение для контейнера, нам действительно нужен этот ключ. Этот ключ является не просто строкой, к которой мы привыкли в среде JavaScript, а экземпляром класса StateKey.

Чтобы создать такой StateKey, мы можем вызвать метод makeStateKey <> (), предоставляемый платформой.

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

src / app / post / post.component.ts import {TransferState, makeStateKey} из '@ angular / platform-browser' const RESULT_KEY = makeStateKey <string> ('result')

После этого мы можем использовать ключ, чтобы получить значение, если мы находимся в браузере. На сервере мы используем обратный вызов onSerialize (), чтобы вернуть значение для ключа. Таким образом, мы можем установить значение.

src / app / post / post.component.ts ngOnInit () {if (this. tstate. hasKey (RESULT_KEY)) {this. результат = это. состояние get (RESULT_KEY, ''); } еще {это. result = 'Я создан в браузере!' ; } этот . состояние onSerialize (RESULT_KEY, () => {return 'Я создан на сервере!';}); }

Просто не так ли?

Хотя приведенное выше решение является полностью действительным, оно может быть не самым очевидным решением. Чтобы было более понятно, что выполняется на сервере, мы можем использовать наш флаг isServer и метод set API.

src / app / post / post.component.ts ngOnInit () {if (this. tstate. hasKey (RESULT_KEY)) {this. результат = это. состояние get (RESULT_KEY, ''); } иначе если (это. isServer) {это. состояние set (RESULT_KEY, «Я создан на сервере!»); } еще {это. result = 'Я создан в браузере!' ; }}

Вот и все. Теперь мы знаем, как передать любое значение (я) с сервера рендеринга клиенту! Вот полный PostComponent:

src / app / post / post.component.ts import {Component, OnInit, PLATFORM_ID, Inject} из '@ angular / core' import {TransferState, makeStateKey} из '@ angular / platform-browser' import {isPlatformServer} из '@ angular / common 'const RESULT_KEY = makeStateKey <string> (' result ') @ Component ({selector:' app-post ', templateUrl:' ./post.component.html ', styleUrls: [' ./post.component. css '],}) класс PostComponent реализует OnInit {открытый результат private isServer: логический конструктор (private tstate: TransferState, @ Inject (PLATFORM_ID) platformId) {this. isServer = isPlatformServer (platformId)} ngOnInit () {if (this. tstate. hasKey (RESULT_KEY)) {this. результат = это. состояние get (RESULT_KEY, '')} else if (this. isServer) {this. состояние set (RESULT_KEY, «Я создан на сервере!»)} else {this. result = 'Я создан в браузере!' }}}

Заключение

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

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

Никогда не пропустите пост, подписавшись на меня в твиттере @malcoded ,

Что такое Angular Universal?
Что такое Angular Universal?
Подождите?
Почему ты говоришь в прошедшем времени?
Но как это вообще работает?
Почему вы должны рендерить на сервере?
Угловая универсальная: серебряная пуля?
Так почему же это недостаток?
Какой смысл иметь, например, Google Analytics на сервере?
С другой стороны, если вам все равно не нужен JavaScript, почему вы выбрали JavaScript-фреймворк?
О том, как смешивать свежевыжатые соки
Ни для кого не секрет, что стакан свежевыжатого овощного или фруктового сока, способен придать заряд энергии и бодрости, а также положительным образом отразиться на состоянии здоровья человека. При этом

Полный список кандидатов в президенты страны станет известен к концу января
9 января 2008, 15:53 Текст: editor На будущей неделе закончится срок приема документов для регистрации кандидатов в президенты. На принятие решения по документам у Центризбиркома будет десять дней. НОРИЛЬСК.

ЄДНІСТЬ : У Києві через високий рівень захворюваності на грип та ГРВІ закрили вже 75 шкіл
У Києві призупинено заняття у 75 школах (2127 класів), у яких рівень захворюваності на грип та ГРВІ перевищив 20%. Інформує  «Є!» , з посиланням на УНІАН. Про це наразі повідомив перший заступник

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

Березовый сок можно ли использовать при сахарном диабете
Березовый сок при сахарном диабете — сахарный диабет: все о заболевании и методах лечения Березовый сок с давних времен славится своими целебными свойствами. Дело в том, что в весенний период береза

Свежевыжатые соки. (кому не лень читать)
Вы видели фильм о , которую исследовал японский ученый Имоту Масара? Уникальные опыты показали, что структурированная жидкость может творить чудеса и оздоравливать наши клетки, омолаживая организм

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

Лечение рака по Бройсу и др
Лечение Рака по Бройсу. (Рудольф Бройс) «Совсем недавно китайские медики обнаружили, что у онкобольных количество микроэлементов в печени, в волосах и некоторых других органах резко снижено. Возможно,

С каким соком пить водку?
Ответ: С каким соком пить водку? ВИНОВАТ АНТИАЛКОГОЛЬНЫЙ ФЕРМЕНТ - Владимир Георгиевич, главный вопрос

Сок добрый
Министерство общего и профессионального образования Российской Федерации Санкт-Петербургский Государственный Технологический институт (Технический университет) Факультет Экономики и