Создайте оптимизированное для SEO приложение Angular и разверните его на бессерверной платформе.

Вы можете создавать одностраничные приложения (SPA), оптимизированные для поисковых систем (SEO), с помощью Angular Universal, технологии, которая запускает ваше приложение Angular на сервере. Кроме того, вы можете снизить стоимость запуска этих приложений с помощью AWS Lambda, платформы бессерверных вычислений, управляемой событиями, предоставляемой как часть Amazon Web Services (AWS). В этом разделе показано, как создавать и развертывать проекты Angular Universal на AWS Lambda с помощью Serverless Framework, интерфейса командной строки с открытым исходным кодом для создания и развертывания бессерверных приложений.

В этой статье мы:

  • Создайте приложение Angular, которое содержит два маршрута и выполняет вызовы внешнего API.
  • Добавить рендеринг на стороне сервера для SEO
  • Настроить конфигурацию фреймворка Serverless Framework
  • Разверните приложение на AWS Lambda

Для выполнения этих задач вам необходимо создать учетную запись AWS и установить следующее:

Для настройки интерфейса командной строки AWS вам потребуется следующее из вашей учетной записи AWS:

  • Идентификатор ключа доступа
  • Секретный ключ
  • Регион по умолчанию

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

Если вы не хотите использовать свой идентификатор пользователя root для этого проекта, вы можете настроить роль и политику IAM для API для вызова функций Lambda. Этот процесс состоит из нескольких этапов и не рекомендуется, если вы новичок в AWS.

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

Настройте проект Angular и запустите Hello World!

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

ng new angularSeo --style css --routing false
cd angularSeo

Внесем несколько небольших изменений в созданный проект. Во-первых, давайте добавим стиль к <app-root> в src/index.html файле. Замените существующий код следующим:

Затем замените существующее содержимое src/app/app.component.html на:

<h1>Hello World!</h1>

Наконец, добавьте в src/styles.css следующее:

Обратите внимание, что в приведенном выше примере мы используем мой любимый модный фон:

Загрузите его и поместите в src/assets/img каталог.

Давайте запустим приложение, набрав:

ng serve

После открытия в вашем браузере вы должны увидеть:

Вы можете найти весь код до этого момента в репозитории GitHub, который вы можете клонировать:

git clone -b tutorial1_step1 https://github.com/maciejtreder/angular-seo.git angularSeo
cd angularSeo/
npm install
ng serve

Компоненты, маршрутизация и сервисы

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

ng g c first
ng g c second
ng g c menu
ng g s echo

Хорошо, у нас много файлов. Начнем с src/app/first/first.component.ts; это будет действительно просто. Замените содержимое по умолчанию следующим:

import { Component } from '@angular/core';
@Component({
   template: '<h1>Hello World!</h1>'
})
export class FirstComponent {}

Отредактируйте второй компонент src/app/second/second.component.ts, который немного сложнее:

Примечание. Ваша среда разработки или линтер могут вызвать makeCall() . Не беспокойтесь об этом: мы решим эту проблему ниже, когда создадим службу.

Здесь мы ввели несколько механизмов. Во-первых, это использование внешнего шаблона и внешнего стиля (templateUrl и stylesUrls). Angular дает нам возможность создавать шаблоны HTML и таблицы стилей CSS вне класса компонента.

Вот как должен выглядеть шаблон для второго компонента src/app/second/second.component.html:

<h1>Second component</h1>
<h2>This component injects EchoService</h2>
Response is: <span>{{response | async | json}}</span>

И таблица стилей src/app/second/second.component.css должна выглядеть так:

span {
   color: purple;
   display: block;
   background: #ccc;
   padding: 5px;
}

Еще один механизм, который мы представили в этом компоненте, - это внедрение зависимостей. Если вы внимательно посмотрите на конструктор в second.component.ts, вы увидите параметр типа EchoService. Angular попытается инициализировать и передать объект типа EchoService нашему классу SecondComponent при его инициализации. Внедрение зависимостей - это метод, используемый для реализации архитектурной парадигмы, известной как инверсия управления (IoC).

Мы также ввели в шаблон Observable тип и async канал. Вы знакомы с Promises? Observable - это еще один шаг вперед. Этот асинхронный тип испускает значения, переданные ему другими функциями. Вы можете использовать его столько раз, сколько захотите, подписаться на нескольких слушателей и т. Д. (Сопоставление, фильтрация, переход к другому наблюдаемому и т. Д.). Подробнее об этом вы можете прочитать на странице RxJS GitHub.

Канал async в шаблоне second.component.html - это специальный механизм Angular для отображения нашей переменной в шаблоне представления только при ее оценке. Другими словами, значение, помещенное в HTML во время выполнения, отправляется наблюдаемым EchoService.

И последнее, но не менее важное: мы реализовали интерфейс OnInit и ловушку жизненного цикла ngOnInit. Интерфейсы в TypeScript работают так же, как интерфейсы в других языках; если вы его реализуете, вы должны реализовать все объявленные в нем методы. В этом конкретном случае нам нужно реализовать метод ngOnInit(). Этот метод является одним из «крючков жизненного цикла Angular», методов, автоматически вызываемых движком Angular на разных этапах инициализации представления, уничтожения и других событий. Согласно документации Angular:

ngOnInit - Инициализирует директиву / компонент после того, как Angular сначала отобразит свойства с привязкой к данным и задает входные свойства директивы / компонента. Вызывается один раз, после первого ngOnChanges().

Мы внедрили сервис во второй компонент. Теперь мы можем его создать. Замените содержимое по умолчанию src/app/echo.service.ts следующим:

Эта служба содержит только один метод, который отправляет GET-запрос на https://jsonplaceholder.typicode.com/posts/1 URL.

Ok. Эта магия выглядит потрясающе, но вы, вероятно, спрашиваете: «Откуда Angular знает, что вводить, куда вводить и где инициализированы все эти классы?». Это отличные вопросы! Ответ: NgModule, точка входа в наше приложение. Пора взглянуть на то, что внутри него происходит, и импортировать еще один модуль, необходимый для EchoService: HttpClientModule (src/app/app.module.ts):

Что же мы имеем здесь..?

  • Импорт - ссылки на другие NgModules
  • Объявления - список компонентов, используемых в приложении.
  • Bootstrap - имя компонента, который мы хотим загрузить как «основной».
  • Провайдеры - список сервисов, используемых в приложении.

Хорошо, теперь пора объявить маршрутизацию. Начнем с создания модуля маршрутизации:

ng generate module app-routing --flat --module=app

Теперь мы можем добавить наши маршруты в src/app/app-routing.module.ts, экспортировать из него RouterModule и удалить избыточный код (массив declarations и импорт CommonModule):

Мы можем добавить несколько ссылок в файл MenuComponent, src/app/menu/menu.component.ts:

Вы видите связь между routerLink и маршрутами, объявленными в AppModule? Большой! Вот как мы связываем вещи в Angular: routerLink - это встроенная директива Angular, которая принимает path в качестве параметра и сопоставляет его с path, объявленным в RouterModule.forRoot(). Когда есть совпадение, он загружает данный компонент в <router-outlet> компонент, который мы собираемся добавить в src/app/app.component.html прямо сейчас. Замените код из этого файла на:

<app-menu></app-menu><router-outlet></router-outlet>

Наше приложение готово. Время запускать:

ng serve -o

Вот что вы должны увидеть в своем браузере:

Если вы нажмете кнопку «Второй компонент», вы увидите следующее, если все работает правильно:

Весь код до этого момента находится в этом репозитории GitHub, который вы можете клонировать:

git clone -b tutorial1_step2 https://github.com/maciejtreder/angular-seo.git angularSeo
cd angularSeo/
npm install
ng serve -o

Поисковая оптимизация (SEO)

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

Запускаем наше приложение:

ng serve

Взгляните на наш сайт. Вы можете сделать это, проверив источник страницы или выполнив команду curl ниже (если у вас установлен cURL):

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

Могут ли сканеры делать то же самое? GoogleBot может обрабатывать JavaScript, но другие сканеры (например, Facebook, LinkedIn, Twitter, Bing) - нет. Кроме того, веб-сайты, которые «выглядят» как статические и не ожидают от сканера дополнительных ресурсов для их чтения, занимают более высокие позиции в рейтинге поисковых систем из-за их более высокой производительности.

Как мы могли решить эту проблему? Это очень просто! Введите в командной строке следующее:

ng add @ng-toolkit/universal

Что сейчас произошло? @ ng-toolkit обновил наш проект функциональностью Angular Universal, технологией, которая запускает ваше приложение Angular на сервере. У нас есть пара новых файлов.

Изменения были внесены в файл src/app/app.module.ts, который был точкой входа в наше приложение. @ Ng-toolkit удалил атрибут bootstrap из аннотации @NgModule, удалил BrowserModule и добавил NgtUniversalModule и CommonModule в массив импорта.

Где сейчас загружается наше приложение? На самом деле, это зависит от обстоятельств. Если вы ищете начальную загрузку, используемую браузером, мы должны перейти к src/app/app.browser.module.ts, вот где он находится:

@ Ng-toolkit также создал файл src/app/app.server.module.ts. Это точка входа для кода, который будет выполняться на стороне сервера.

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

(Многоточие («...») в блоке кода указывает на раздел, отредактированный для краткости.)

Как видите, входным файлом для этой сборки является src/main.server.ts, который также был добавлен в наш проект. Посмотрев на этот файл, мы можем определить точку входа, используемую компилятором Angular для создания сборки на стороне сервера:

Вот он: src/app/app.server.module.ts, который представляет собой серверный рендеринг, эквивалентный src/app/app.browser.module.ts, модулю, который загружает приложение для рендеринга в браузере.

Как вы, наверное, заметили, @ng-toolkit также внес изменения в файл package.json. У нас есть пара новых скриптов:

...
"build:server:prod": "ng run angularSeo:server && webpack --config webpack.server.config.js --progress --colors",
"build:browser:prod": "ng build --prod",
"build:prod": "npm run build:server:prod && npm run build:browser:prod", 
"server": "node local.js"
...

Два самых важных находятся в конце списка:

  • build:prod, который запускает компилятор Angular для сборок браузера и сервера, а затем создает файл server.js, используя конфигурацию Webpack, добавленную @ ng-toolkit.
  • server, который используется для запуска Node.js со скомпилированным приложением.

Попробуйте:

npm run build:prod
npm run server

Мы можем попытаться вести себя как сетевой сканер:

curl localhost:8080

Бум! Если мы проверим источник страницы, мы увидим, что было сгенерировано на стороне сервера. Найдите ссылки, созданные для кнопок, показанных ниже:

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

git clone -b tutorial1_step3 https://github.com/maciejtreder/angular-seo.git angularSeo
cd angularSeo/
npm install
npm run build:prod
npm run server

Развертывать!

Потрясающие! Наше приложение полностью разработано и оптимизировано для SEO. Мы готовы к развертыванию на 95%.

Обсудим оставшиеся 5%.

Обычно мы собираем наше приложение и публикуем все, что находится в папке dist, на каком-нибудь хостинге (например, Amazon S3). «Проблема» в том, что мы ввели механизм рендеринга на стороне сервера, для которого требуется, чтобы Node.js работал на сервере. Нужен ли нам дорогостоящий инстанс EC2, работающий 24 часа в сутки?

Неа. Мы собираемся использовать AWS Lambda, среду Function as a Service (FaaS) вместе с Serverless Framework. Снова используя @ ng-toolkit, мы настроим базовую конфигурацию для Serverless Framework.

ng add @ng-toolkit/serverless

Эта команда создает файл serverless.yml, который предоставляет конфигурацию для Serverless Framework, и файл lambda.js, который обеспечивает точку входа для функции AWS Lambda. Он также вносит небольшие изменения в структуру.

Чтобы настроить проект для запуска в регионе AWS по умолчанию, отредактируйте файл serverless.yml и замените значение region: на имя региона AWS по умолчанию. Например, замените eu-central-1 на us-east-2.

У нас также есть новые скрипты в package.json. Воспользуйтесь одним из них:

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

Когда вы нажимаете кнопку «Второй компонент », результат должен выглядеть следующим образом:

В качестве последнего шага проверьте этот URL-адрес с помощью команды curl или проверив источник страницы:

Идеально. Наше приложение размещено в сети.

Вы можете найти весь код до этого момента в репозитории GitHub, который вы можете клонировать:

git clone -b tutorial1_step4 https://github.com/maciejtreder/angular-seo.git angularSeo
cd angularSeo/
npm install
npm run build:serverless:deploy

Резюме

Сегодня мы успешно разработали и развернули приложение Angular на AWS Lambda. Вы узнали, как вводить маршрутизацию, модули и сервисы в Angular, и все это с рендерингом на стороне сервера в целях оптимизации SEO. Эти методы позволяют развернуть приложение Angular в Интернете таким образом, чтобы он был доступен поисковым системам, при этом сводя к минимуму ваши эксплуатационные расходы. Используя AWS Lambda, вы платите только за время вычислений, необходимое для обслуживания запросов посетителей, вместо того, чтобы платить за каждую минуту, когда сервер находится в сети.

Ресурсы

Репозиторий GitHub: https://github.com/maciejtreder/angular-seo/tree/tutorial1_step4

Также посетите: https://github.com/maciejtreder/ng-toolkit, чтобы узнать о дополнительных возможностях Angular и Angular + Serverless Framework.

Вы также можете связаться со мной по адресу: [email protected] или @maciejtreder в GitHub, Twitter, StackOverflow и LinkedIn.