SEO в Angular без рендеринга на стороне сервера

SEO в Angular без рендеринга на стороне сервера

От создателя: понимаете ли вы, что Гугл Search поддерживает сканирование JavaScript с мая 2019 года? Это значит, что рендеринг на стороне сервера больше не единственный метод сделать лучше SEO.

Введение: Angular и SEO

Традиционная неувязка одностраничных приложений и поисковых машин

Одностраничные приложения (SPA) имеют лишь одну главную страничку, index.html, которая получает обновления DOM при помощи JavaScript.

До недавнешнего времени у поисковых машин были трудности с пуском таковых приложений. У всех современных JavaScript-фреймворков был суровый недочет исходя из убеждений SEO.

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

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

Решением была гибридизация. Приложения, которые отчасти загружали контент при помощи рендеринга на стороне сервера, сохраняя при всем этом некие достоинства фреймворков JavaScript.

Текущее состояние поиска Гугл

Гугл Dev Summit 2020 отдал разрабам много нужных советов. Я отыскал вдохновение для данной статьи в этом видео, где юрист разрабов Гугл Мартин Сплитт проливает свет на данную тему. В итоге:

READ
Сколько требуется времени для возвращения сайта в поисковый индекс Google

Может ли Гугл обнаруживать конфигурации в приложениях Javascript?

Разрабам главных javascript-фреймворков, таковых как Angular, React либо Vue, не стоит волноваться. С мая 2019 года Гугл Search поддерживает Javascript.

Полезны ли заголовок и мета-описание для SEO?

… Они могут косвенно воздействовать на SEO через показатель кликабельности

Управление по внедрению

Интегрированные инструменты Angular: DOCUMENT, Meta & Title

Мы можем получить доступ к DOCUMENT для редактирования его Title и Meta при помощи инструментов, предоставленных в @angular/common и @angular/platform-browser.

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

JavaScript

12345678910111213141516171819202122232425262728293031323334import { DOCUMENT } from ‘@angular/common’;import { Inject, Injectable } from ‘@angular/core’;import { Meta, Title } from ‘@angular/platform-browser’; @Injectable({  providedIn: ‘root’})export class SEOService {   constructor(    @Inject(DOCUMENT) private dom,    private titleSvc: Title,    private metaSvc: Meta,  ) { }    updateTitle(title: string){    this.titleSvc.setTitle(title)  }   updateDescription(content: string) {    this.metaSvc.updateTag({ name: ‘description’, content })  }   createCanonicalLink(url: string) {    let link: HTMLLinkElement =      this.dom.createElement(‘link’);     link.setAttribute(‘rel’, ‘canonical’);    link.setAttribute(‘href’, url);    this.dom.head.appendChild(link);  } }

Пример использования: статические метаданные

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

Так как эти характеристики соединены с определенным маршрутом, мы будем употреблять Router для отправки инфы компоненту. Angular Routes дозволяет отправлять любые статические данные, используя данные характеристики.

Добавление метаданных к существующему маршруту

SEO в Angular без рендеринга на стороне сервера

Чтоб все было понятно, сделайте один файл для хранения всех статических метаданных вашего веб-сайта

Опосля определения некого мета статического раздела мы добавляем его в маршрутизатор.

READ
Вот что я не знал о «content»

JavaScript

1234567891011121314151617181920212223const sectionRoutes: Routes = [ {   path: »,   data: sectionsMetadata.homePage,    children: [      {        path: ‘articles’,        data: sectionsMetadata.articles,        loadChildren: () => import(‘./pages/articles/articles.module’).then(m => m.ArticlesModule),      },    ]  },] @NgModule({  declarations: [],  imports: [    CommonModule,    RouterModule.forRoot(sectionRoutes),  ],  exports: [RouterModule]})export class AppRoutingModule { }

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

JavaScript

12345678910111213141516171819202122@Component({  selector: ‘app-articles’,  templateUrl: ‘./articles.component.html’,  styleUrls: [‘./articles.component.scss’],  changeDetection: ChangeDetectionStrategy.OnPush,})export class ArticlesComponent implements OnInit {   readonly articles$ = this.route.data.pipe(pluck(‘articles’))   constructor(    private SEOService: SEOService,    private route: ActivatedRoute,  ) { }   ngOnInit(): void {    const { meta } = this.route.snapshot.data;    this.SEOService.updateTitle(meta.title);    this.SEOService.updateDescription(meta.description);  } }

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

Но… что происходит, когда метаданные поступают из элемента снутри HttpResponse? Когда дело доходит до динамического контента, следует учесть две вещи: навигацию по характеристикам и асинхронные данные.

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

Когда мы перебегаем от одной статьи к иной, используя маршрут с таковыми параметрами, как articles/:id, компонент не создается повторно. Он просто обновляет и повторно показывает контент.

Это значит, что нам необходимо обрабатывать конфигурации через Observables, если мы желаем динамически обновлять метаданные.

Внедрение резолвера для подготовительной подборки асинхронных данных

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

Это можно создать при помощи Angular resolver. Мы делаем HTTP-запрос и ждем ответа, до этого чем запускать навигацию.

JavaScript

12345678910111213@Injectable({   providedIn: ‘root’ })export class ArticleResolver implements Resolve<Article> {   constructor(private articlesService: ArticlesAPIService) {}   resolve(route: ActivatedRouteSnapshot): Observable<Article> {    const id = route.paramMap.get(‘id’);     return this.articlesService.getArticle$(id);  }}

Добавление резольвера в маршрутизатор

JavaScript

12345678910111213141516171819202122232425262728import { Routes, RouterModule } from ‘@angular/router’;import { NgModule } from ‘@angular/core’;import { CommonModule } from ‘@angular/common’; import { ArticleResolver } from ‘./_providers/article.resolver’;import { ArticlesComponent } from ‘./articles/articles.component’; export const articlesRoutes: Routes = [  {    path: »,    component: ArticlesComponent,  },  {    path: ‘:id’,    resolve: { article: ArticleResolver },    loadChildren: () => import(‘./article/article.module’).then(m => m.ArticleModule)  } ] @NgModule({  declarations: [ArticlesComponent],  imports: [    CommonModule,    RouterModule.forChild(articlesRoutes),  ]})export class ArticlesModule { }

Обновление компонента

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

JavaScript

1234567891011121314151617181920212223242526@Component({  selector: ‘app-article’,  templateUrl: ‘./article.component.html’,  styleUrls: [‘./article.component.css’],  changeDetection: ChangeDetectionStrategy.OnPush,})export class ArticleComponent {   readonly article$: Observable<Article> = this.route.data    .pipe(      pluck(‘article’),      tap(article => this.updatePageMeta(article))  );   constructor(    private SEOSvc: SEOService,    private route: ActivatedRoute  ) { }   private updatePageMeta(article: Article) {    this.SEOSvc.updateTitle(article.title);    this.SEOSvc.updateDescription(article.description)  }  }

Как постоянно, спасибо за внимание.

Создатель: Fer Ayguavives

Редакция: Команда webformyself.

Источник

Оценить статью
Блог о самом интересном.