Сайт визитка на Angular. Настройка SEO.

Aleksandr Serenko
F.A.F.N.U.R
Published in
5 min readMar 27, 2022
Сайт визитка на Angular. Настройка SEO

В данной статье настроим SEO (Search Engine Optimization), добавив необходимую конфигурацию, а также указав мета теги и другую вспомогательную информацию.

Angular в базовом состоянии скудно сконфигурирован. В базовое приложение необходимо добавить в приложение:

  • favicon — иконка для закладок, которая в зависимости от типа устройства нормально масштабировалась;
  • webmanifest (browserconfig)— конфигурация сайта для PWA, которая содержит названия и цвета устанавливаемого приложения;
  • robots.txt — политика индексирования в поисковых системах;
  • sitemap.xml — карта сайта;
  • site-image.jpg — картинка, которая будет использоваться при шаринге.

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

Список страниц, на которые необходимо добавить теги:

  • / — главная страница
  • /product/* — страница товара
  • /support — страница службы поддержки
  • /terms — страница условий продажи товаров
  • /cart — корзина
  • /order — страница оформления заказа.

Favicons

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

apps/store/src/assets/images/favicons
├── android-chrome-192x192.png
├── android-chrome-512x512.png
├── apple-touch-icon.png
├── favicon-16x16.png
├── favicon-32x32.png
├── mstile-150x150.png
└── safari-pinned-tab.svg

В index.html добавим в head:

link rel="apple-touch-icon" sizes="180x180" href="/assets/images/favicons/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicons/favicon-16x16.png" />
<link rel="mask-icon" href="/assets/images/favicons/safari-pinned-tab.svg" color="#d01931" />
<meta name="msapplication-TileColor" content="#ffffff" />
<meta name="theme-color" content="#ffffff" />

Webmanifest

Сервисы генерации favicons обычно вместе с файлами иконок, генерируют и файлы манифеста.

Создадим site.webmanifest и browserconfig.xml:

Также подключим в index.html:

<link rel="manifest" href="/site.webmanifest" />

Robots.txt

Определим политику индексирования сайта:

User-agent: *
Disallow: /api/

User-agent: Yandex
Disallow: /api/
Clean-param: bonus&utm_source&utm_medium&utm_campaign&utm_term&utm_content&click_id

Host: https://banshop.fafn.ru
Sitemap: https://banshop.fafn.ru/sitemap.xml

В данном случае:

  • запрещаем индексировать все страницы с префиксом /api/ ;
  • для Yandex еще явно указываем сбор параметров;
  • указываем хост и карту сайта.

Sitemap

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

Используя рекомендации Angular по созданию отдельного модуля для навигации, в качестве даты (“data”) укажем параметры для карты сайта:

В файле libs/cart/page/src/lib/cart-page-routing.module.ts:

Для данного роута была добавлена следующая конфигурация:

sitemap: {
loc: '/cart',
priority: '1.0',
},

В итоге в карте сайта должен появится следующий url:

<url>
<loc>https://banshop.fafn.ru/cart</loc>
<lastmod>2022-03-19</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>

Для того чтобы это произошло, реализуем генератор карты сайта.

Создадим новый файл apps/store/sitemap-generator.ts:

Генератор содержит несколько функций

  • fromDir — читает содержимое директории и ищет файлы по шаблону;
  • parseSitemapConfig — парсит содержимое файла и пытается найти конфигурацию sitemap;
  • getSitemapUrl — генерация пути в sitemap на основании входящего конфига;
  • getServerData — загрузка внешнего файла и генерация url’ов на основе полученных данных;
  • getUrls — функция, которая парсит приложение и библиотеки для конкретного приложения на наличие файлов роутинга;
  • generate — функция, которая запускает генерацию карты сайта.

Так как ts-node нужен tsconfig, создадим конфиг на основе базового tsconfig.base.json, добавив в проект файл tsconfig.sitemap.json:

Из важного, в конфигурации указывается тип модуля — CommonJS, который позволит ts-node корректно обрабатывать импорты и другие сущности.

Для запуска будем использовать следующую команду, которую добавим в package.json:

"generate-sitemap": "ts-node --project=apps/store/tsconfig.sitemap.json apps/store/sitemap-generator.ts"

Для вызова запустим команду:

yarn generate-sitemap

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

Из важного, стоит отметить, что вместе с генерацией карты сайта, генерируется массив страниц для prerender’а:

const routePaths = [...Array.from(routes), '/not-found', '/server-error'].sort().join('\n');
fs.writeFileSync('apps/store/routes.txt', routePaths);

Это позволяет в фазе prerender’а отрисовать все требуемые страницы в приложении. Подробнее об этом будет в следующей статье.

Meta tags

Для мета тегов используется почти аналогичный подход.

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

Реализуется это следующим образом:

Выше описанные интерфейсы позволяют описать конфигурацию мета тегов

  • MetaConfig — базовые мета теги, такие как keys, description и title
  • MetaConfigOg — мета теги схемы OG.

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

export const META_CONFIG_DEFAULT: MetaConfig = {
title: $localize`:Meta default|:Online store Banshop`,
// eslint-disable-next-line max-len
description: $localize`:Meta default|:Banshop sportswear, shoes and accessories. Free delivery in Moscow and all over Russia when paying on the website.`,
keywords: $localize`:Meta default|:sneakers, sports shoes`,
};

export const META_CONFIG_OG_DEFAULT: MetaConfigOg = {
title: META_CONFIG_DEFAULT.title,
description: META_CONFIG_DEFAULT.description,
type: 'website',
image: '/assets/images/site.jpg',
imageType: 'image/jpeg',
imageWidth: '600',
imageHeight: '284',
};

Используя прошлый пример, рассмотрим дату для пути:

const routes: Routes = [
{
path: '',
component: CartPageComponent,
data: {
sitemap: {
loc: '/cart',
priority: '1.0',
},
meta: {
title: $localize`:Cart meta|:Cart | Online store Banshop`,
description: $localize`:Cart meta|:It is very easy to buy on banshop. To place an order, click the order button.`,
keywords: $localize`:Cart meta|:cart, banshop`,
},
} as Partial<RouteData>,
},
];

Как видно, в data есть специальный раздел, который описывает конфигурацию мета тегов для текущей страницы:

meta: {
title: $localize`:Cart meta|:Cart | Online store Banshop`,
description: $localize`:Cart meta|:It is very easy to buy on banshop. To place an order, click the order button.`,
keywords: $localize`:Cart meta|:cart, banshop`,
},

И так как это общий файл, для него создаются собственные переводы при необходимости.

Сервис задания мета тегов достаточно прост:

Сервис получает доступ к заголовку страницы, роутеру, параметрам приложения, а также набору токенов, которые предоставляют собой дефолтные параметры для мета тегов (META_CONFIG, META_CONFIG_OG).

В MetaService реализованы следующие методы:

  • setCanonicalUrl — установление canonical url, который считается основным для множества страниц
  • getCanonicalURL — получение canonical url
  • setMetaProperty — метод, который по ключу создает или обновляет мета тег
  • update — метод, который вызывает обновления коллекции свойств на странице.
update(metaConfig?: Partial<MetaConfig>, metaConfigOg?: Partial<MetaConfigOg>): void {
const config: MetaConfig = { ...this.metaConfig, ...metaConfig };
const configOg: MetaConfigOg = { ...this.metaConfigOg, ...metaConfigOg };
this.setCanonicalUrl(config.url);
this.titleService.setTitle(`${config.title} | ${this.environmentService.environments.brand}`);
this.setMetaProperty('description', config.description);
this.setMetaProperty('keywords', config.keywords);
this.setMetaProperty('og:title', `${configOg.title ?? config.title} | ${this.environmentService.environments.brand}`);
this.setMetaProperty('og:description', configOg.description ?? config.description);
this.setMetaProperty('og:type', configOg.type);
this.setMetaProperty('og:locale', configOg.locale ?? this.localeId);
this.setMetaProperty('og:site_name', configOg.siteName ?? this.environmentService.environments.brand);
this.setMetaProperty('og:image', `${this.environmentService.environments.appHost}${configOg.image}`);
this.setMetaProperty('og:image:type', configOg.imageType);
this.setMetaProperty('og:image:width', configOg.imageWidth);
this.setMetaProperty('og:image:height', configOg.imageHeight);
}

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

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

Так store знает об окончании навигации запуская соответствующий экшен — ROUTER_NAVIGATED, то подписавшись на него, можно вызывать метод обновления:

routerNavigated$ = createEffect(() => {
return this.actions$.pipe(
ofType(ROUTER_NAVIGATED),
fetch({
run: (action: NavigationActon) => {
const {meta,metaOg}= action.payload.routerState?.data ?? {};
this.metaService.update(
{
url: action.payload.routerState.url,
...meta,
},
metaOg
);
},
})
);
});

Подключение модуля MetaStateModule в AppCoreModule позволит динамически менять мета теги у страниц.

Ссылки

Оглавление

Предыдущая статья — Настройка SEO.

Следующая статья — Настройка SSR.

Все исходники находятся на github, в репозитории:

Для того, чтобы посмотреть состояние проекта на момент написания статьи, нужно выбрать соответствующий тег — article.

Подписывайтесь на блог, чтобы не пропустить новые статьи про Angular, и веб-разработку. Medium | Telegram| VK |Tw| Ln

--

--

Aleksandr Serenko
F.A.F.N.U.R

Senior Front-end Developer, Angular evangelist, Nx apologist, NodeJS warlock