Кутове SEO зроблено правильно з рендеринга на стороні сервера

  1. Навіщо турбуватися про кутовий SEO? Чи не підтримується Google Angular?
  2. Як обробляти питання кутового SEO
  3. Технічний навчальний посібник: Кутовий SEO-дружній приклад з універсальним
  4. Налаштування середовища розробки
  5. 1. Налаштування структури проекту за допомогою Angular CLI
  6. 2. Створення першої кутової складової
  7. 2.1 Складання списку продуктів
  8. 3. Перелік продуктів програми
  9. 4. Додавання маршрутизації до програми Angular
  10. 5. Створення компонента продукту
  11. 6. Інтеграція функціональних можливостей кошика для покупок
  12. 7. Використання Angular Universal для SEO
  13. 7.1 Встановлення кутового універсалу
  14. 7.2 Редагування клієнтської програми
  15. 7.3 Налаштування сервера
  16. 7.4 Створення та запуск програми
  17. GitHub репо & жити демо
  18. Закриття думок

Поспіхом? Перейти до технічний посібник або демо .

Сканування JavaScript і рендеринг Google як і раніше є дещо невизначеною проблемою.

Суперечливі твердження та експерименти знаходяться по всьому Інтернету.

Отже, що це означає?

Як розробник, вам потрібно оптимізувати сайти, побудовані за допомогою популярних JS фреймворків для SEO.

Маючи це на увазі, ось третя частина нашої нинішньої серії JavaScript Frameworks:

  1. Створення попередньо одержаного додатка Vue.js
  2. Застосування React SEO з Next.js .
  3. Тут, я буду вирішувати кутовий SEO.

Точніше кажучи, ми будемо створювати сервісний ретрансляційний SPA за допомогою Universal .

Нижче наведено кроки, які ми будемо використовувати для цього:

  1. Створення проекту Angular.
  2. Створення кутових компонентів.
  3. Увімкнення функцій електронної комерції на нашому SPA.
  4. Використовуючи Universal, щоб зробити наше Angular додаток SEO-дружній

Це повинно бути весело!

Навіщо турбуватися про кутовий SEO? Чи не підтримується Google Angular?

Кутовий є платформою JS з відкритим кодом, розробленою інженерами Google у 2010 році.

Чудово завершити безголовий стек або будь-який інший JAMstack в цьому відношенні. Але вона все ще поділяє спільні питання SEO, відомі рамкам JavaScript.

Односторінкові програми JS додають вміст до сторінок динамічно за допомогою JavaScript. Це не є оптимальним для SEO: сканери, швидше за все, не запускатимуть код JS, таким чином, не стикаючись з фактичним змістом сторінки.

Станом на 2018 рік, слово «Google» може сканувати та відтворювати сторінки, заповнені за допомогою JavaScript, таким чином читаючи їх, як це роблять сучасні браузери. Хоча цитати з гіганта не роблю мене настільки оптимістичним:

"Час змінився. Сьогодні, поки ви не блокуєте Googlebot сканування файлів JavaScript або CSS, ми, як правило, можемо відображати та розуміти ваші веб-сторінки, як сучасні веб-переглядачі."

"Іноді під час рендерінгу речі не ідеально підходять, що може негативно вплинути на результати пошуку для вашого сайту."

"Іноді JavaScript може бути занадто складним або таємним, щоб ми могли його виконати, і в цьому випадку ми не можемо відобразити сторінку повністю і точно."

Хоча Google бореться з рендерингами вашого JS, воно все ще б'є всі інші пошукові або соціальні сканери (Facebook, Twitter, LinkedIn). Оптимізація візуалізації вашого додатка, таким чином, принесе користь вашій діяльності на цих каналах теж!

Це занадто багато неіндексованого вмісту JavaScript, щоб залишити на столі.

Як обробляти питання кутового SEO

Для того, щоб ваш веб-сайт Angular знайшов свій шлях на вершині результатів пошукової системи, вам доведеться вкласти певну роботу.

Отримати як Google

Якщо ви вже маєте загальнодоступну програму Angular, перейдіть до свого Консоль пошуку Google і запустити Отримати як Google на сторінках, які потребують індексування. Вона розповість, які Googlebots можуть або не можуть отримати доступ.

Це дасть вам уявлення про те, які області потребують певної роботи SEO.

Способи зробити це насправді не відрізняються від того, що ми вже бачили з Vue або React, але інструменти роблять.

Попереднє записування

Цей досить простий. JavaScript виводиться в браузері; статичний HTML зберігається і повертається сканерам. Це рішення ідеально підходить для простих програм, які не покладаються на будь-який сервер. Простіше налаштування, ніж рендеринг на стороні сервера, з великими результатами SEO.

Для кутового попереднього відтворення я пропоную розглянути Prerender.io .

Відображення на стороні сервера

Ось що я зроблю тут.

Я буду використовувати SSR Кутовий універсал .

Простіше кажучи, це буде запущено Angular на бекенді, так що, коли буде зроблений запит, вміст буде відображено в DOM для користувача.

Хоча цей метод додає додаткових навантажень на сервер, він може підвищити продуктивність на більш повільних пристроях / підключеннях, оскільки перша сторінка завантажуватиметься швидше, ніж якщо б клієнт мав відтворювати саму сторінку.

У цьому ми вивчили ці два методи Vue.js відео-підручник . Вміст також стосується Angular!

Чи означає, що використання цих методів означає, що ви раптом з'являться на вершині SERP ? Ну, може бути. Швидше за все? Ні. Є багато інших міркувань SEO: великий мобільний UX, HTTPS з'єднання, карта сайту, великий вміст, зворотні посилання тощо. Ця посада перераховує пару порад SEO у своєму висновку!

Технічний навчальний посібник: Кутовий SEO-дружній приклад з універсальним

Передумови

  • Базове розуміння односторінкових додатків (SPA)
  • Базові знання Текстопис [необов'язково]
  • A Обліковий запис Snipcart (назавжди вільний у тестовому режимі)

Налаштування середовища розробки

Інсталюйте кутовий CLI глобально за допомогою наступної команди:

npm install -g @ angular / cli

Я використовую sass у моєму проекті. Якщо ви вирішите це зробити, і не маєте його вже встановлено, добре:

npm install -g sass

1. Налаштування структури проекту за допомогою Angular CLI

Створіть свій проект за допомогою Angular CLI.

ng new my-app --стиль = scss - маршрутизація

Помічено, як я додав аргумент стилю та маршрутизації до команди?

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

Як тільки це буде зроблено, перейдіть до каталогу проекту та подайте проект.

cd my-app ng служити

Тепер проект має бути видимим локально за адресою: http: // localhost: 4200 /

2. Створення першої кутової складової

Як і багато сучасні бібліотеки або фреймворки, Angular використовує компонентну систему.

У Angular кожен компонент, за винятком основного, є каталогом, розташованим у src / app /, що містить три файли: файл TypeScript, файл стилізації та файл HTML.

Оскільки ця демонстрація є простим магазином електронної комерції, я буду використовувати два компоненти. Компонент продуктів буде містити список і посилання на кожну сторінку продукту. А компонент продукту буде відображати всю детальну інформацію про продукт.

Використовуйте вбудовану команду Angular CLI для створення нових компонентів:

ng генерують компонент продуктів ng генерують компонентний продукт

2.1 Складання списку продуктів

Перед редагуванням компонентів потрібно створити структуру даних для продуктів.

Створіть файл product.ts безпосередньо в папці src / app / і надайте йому всі потрібні властивості.

клас експорту Продукт {id: string; name: string; ціна: номер; вага: кількість; опис: рядок; }

Також створюйте макет-продукт у тому ж місці. Цей файл імпортує клас Продукту та експортує масив Product.

Таким чином, ви зможете імпортувати список продуктів у будь-який компонент.

імпортувати {Product} з "./product"; export const ПРОДУКЦІЯ: Продукт [] = [{id: "ac-1", назва: "Central Air Conditioner", ціна: 5000.00, вага: 900000, опис: "Тримайте весь офіс прохолодним з цим центральним кондиціонером". }, {id: "ac-2", ім'я: "Window Air Conditioner", ціна: 300.00, вага: 175000, опис: "Ідеальний для охолодження кімнати або невеликої квартири". }, {id: "ac-3", ім'я: "A fan", ціна: 10.00, вага: 2000, опис: "Недорогий, але ефективний спосіб зупинити своїх колег від скарги на спеку". },]

3. Перелік продуктів програми

Гаразд, продукт успішно знущався! Тепер давайте перерахуємо наші продукти на домашній сторінці. Для цього відкрийте product.component.ts і додайте:

import {Component, OnInit} з '@ angular / core'; імпортувати {PRODUCTS} з "../mocked-products"; @Component ({selector: 'app-products', templateUrl: './products.component.html', styleUrls: ['./products.component.scss']}) клас експорту ПродуктиКомпонент реалізує OnInit {products = PRODUCTS; constructor () {} ngOnInit () {}}

Як бачите, кожна компонента Angular імпортує клас Component з бібліотеки Angular core. @Component ({}) є функцією декоратора, яка позначає клас як компонент Angular і надає більшість його метаданих.

Значення пари ключів селектора - це тег XML, який можна включити до шаблонів для відображення цього компонента.

Зробіть це зараз, видаливши все, що згенеровано в шаблоні головної програми (app.component.html), і додайте відповідний тег:

<app-products> </app-products>

Як тільки це буде зроблено, якщо ви відвідаєте веб-сайт, ви повинні бути привітані з:

Тепер давайте змінюємо файл products.component.html, щоб перелічити продукти з використанням директиви ретранслятора Angular * ngFor і ручки ({{}}) для прив'язки даних вашого класу до шаблону.

<h2> Продукти </h2> <ul * ngFor = "нехай продукт продуктів"> <li> {{product.name}} </li> </ul>

4. Додавання маршрутизації до програми Angular

Давайте перетворимо цей магазин на одну сторінку, використовуючи вбудовану маршрутизацію Angular.

Оскільки при створенні проекту додано аргумент --routing, можна перейти безпосередньо до app-routing.module.ts і перефактувати його в наступний код:

імпортувати {NgModule} з '@ angular / core'; імпортувати {маршрути, RouterModule} з '@ angular / router'; імпортувати {ProductComponent} з "./product/product.component"; імпортувати {ProductsComponent} з "./products/products.component"; const-маршрути: Routes = [{path: '', компонент: ProductsComponent}, {path: 'product /: id', компонент: ProductComponent}]; @NgModule ({import: [RouterModule.forRoot (routes)], експортує: [RouterModule]}) клас експорту AppRoutingModule {}

Цей модуль імпортує продукти та компоненти продукту, і будує масив маршрутів, що пов'язують кожен шлях з компонентом.

Можна побачити, що я додав заповнювач: id, який зможе отримати компонент продукту для відображення потрібного продукту.

Також важливо ініціалізувати маршрутизатор, додавши RouterModule.forRoot (маршрут) в імпорт модуля.

Після цього можна замінити тег компонента в шаблоні програми (app.component.html) тегом <router-outlet>:

<router-outlet> </router-outlet>

Тег маршрутизатора-виходу надасть перегляд для відповідного шляху, вказаного в масиві маршрутів. У цьому випадку кореневий каталог відображатиме компонент Продукти.

Тепер ви можете додати routerLink = 'relativePath' замість будь-якого атрибута href = 'path' у тегах <a>. Наприклад, ви можете оновлювати файл products.component.html з таким прикладом:

<h2> Продукти </h2> <ul * ngFor = "нехай продукт продуктів"> <li> <a routerLink="/product/{{product.id}}"> {{product.name}} </ a > </li> </ul>

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

5. Створення компонента продукту

Тепер давайте створимо компонент деталей продукту. У файлі TypeScript, product.component.ts додайте наступний код:

import {Component, OnInit} з '@ angular / core'; імпортувати {ActivatedRoute} з '@ angular / router'; імпортувати {Location} з '@ angular / common'; імпортувати {PRODUCTS} з "../mocked-products"; імпортувати {Product} з '../product'; @Component ({selector: 'app-product', templateUrl: './product.component.html', styleUrls: ['./product.component.scss']}) клас експорту ProductComponent реалізує OnInit {products = PRODUCTS; url: String; продукт: продукт; конструктор (приватний маршрут: ActivatedRoute, приватне розташування: Location) {const id = this.route.snapshot.paramMap.get ('id'); this.product = this.findProductById (id); this.url = `https://snipcart-angular-universal.herokuapp.com/$ {this.location.path ()}`; } ngOnInit () {} findProductById (productId: string): Продукт {повернути this.products.find (продукт => product.id === productId); }}

Вище, я імпортував ActivatedRoute і Location з Angular. Це дозволить вам отримати productId з URL і отримати поточний шлях безпосередньо в конструкторі.

Ми також імпортували наш макет з насмішеними продуктами, отримували поточний продукт за допомогою ідентифікатора з маршруту, використовуючи find (), і префікс URL з походженням запитів сервера.

Тепер давайте оновимо шаблон компонента (product.component.html), щоб відобразити необхідну інформацію і створити сумісну кнопку Визначення продукту Snipcart .

<div class = "product"> <img src = "../ assets / images / {{product.id}}. svg" alt = "{{product.name}}"> <h2> {{product.name }} </h2> <p> {{product.description}} </p> <button class = "snipcart-add-item" [attr.data-item-id] = "product.id" [attr.data -item-name] = "назва продукту" [attr.data-item-url] = "url" [attr.data-item-price] = "product.price" [attr.data-item-weight] = " product.weight "[attr.data-item-description] =" product.description "> Купити ({{product.price}} $) </button> </div>

Зверніть увагу, як я не використовував фігурні дужки для прив'язки даних до атрибутів HTML?

Для властивостей, а не атрибутів, можна використовувати лише фігурні дужки. Таким чином, ви повинні використовувати синтаксис прив'язки атрибута Angular, як показано в наведеному вище коді.

6. Інтеграція функціональних можливостей кошика для покупок

Тепер давайте інтегруємо Snipcart, додавши необхідні сценарії з нашим API ключем до файлу index.html, який є головним нашим головним додатком.

Таким чином, вона зможе взаємодіяти з усіма вашими поглядами.

<! doctype html> <html lang = "uk"> <head> <meta charset = "utf-8"> <title> Угловий Snipcart </title> <база даних href = "/"> <meta name = "viewport" content = "width = device-width, initial-scale = 1"> <link rel = "icon" type = "image / x-icon" href = "favicon.ico"> </head> <body> <app- root> </app-root> </body> <script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"> </script> <сценарій src = "https://cdn.snipcart.com/scripts/2.0/snipcart.js" data-api-key = "MzMxN2Y0ODMtOWNhMy00YzUzLWFiNTYtZjMwZTRkZDcxYzM4" id = "snipcart"> </script> <link href = "https: // cdn .snipcart.com / themes / 2.0 / base / snipcart.min.css "rel =" stylesheet "type =" text / css "/> </html>

У демо-версії, я також редагував кілька шаблонів, щоб допомогти стилю кожного компонента.

Я залишу цю частину до вас, оскільки це не є основним напрямком керівництва.

7. Використання Angular Universal для SEO

Нарешті, давайте зробимо наше додаток SEO дружним за допомогою SSR.

У цій демонстрації я скористаюся Node.js Express сервер. Майте на увазі, що можна додати Angular Universal на будь-який сервер, якщо він може взаємодіяти з функцією Angular's renderModuleFactory, але конфігурація, швидше за все, буде відрізнятися від тієї, що показана на цій посаді.

7.1 Встановлення кутового універсалу

Щоб розпочати роботу, давайте додамо необхідні інструменти до вашого середовища розробки:

npm install --save @ angular / платформа-сервер @ nguniversal / module-map-ngfactory-loader ts-loader @ nguniversal / express-engine

7.2 Редагування клієнтської програми

Тепер, коли у нас є всі необхідні інструменти, давайте відредагуємо код на стороні клієнта, щоб дозволити перехід між сторінкою візуалізації на сервері та додатком на стороні клієнта. У app.module.ts замінити імпорт BrowserModule в декораторі @NgModule () наступним кодом:

BrowserModule.withServerTransition ({appId: 'my-app'}),

Оскільки програма вбудована в серверний код і код клієнта, вам знадобляться два шляхи виводу. Почнемо з вказівки шляху виводу для браузера. Для цього відредагуйте outputPath в angular.json.

"architect": {"build": {"builder": "@ angular-devkit / build-angular: browser", "options": {"outputPath": "dist / browser", ...

7.3 Налаштування сервера

Тепер, коли ви зробили необхідну модифікацію в клієнті, давайте відредагуємо код для сервера.

Створіть app.server.module.ts у каталозі src / app.

імпортувати {NgModule} з '@ angular / core'; імпортувати {ServerModule} з '@ angular / platform-server'; імпортувати {ModuleMapLoaderModule} з '@ nguniversal / module-map-ngfactory-loader'; імпортувати {AppModule} з "./app.module"; імпортувати {AppComponent} з "./app.component"; @NgModule ({імпортується: [AppModule, ServerModule, ModuleMapLoaderModule], початкова завантаження: [AppComponent],}) клас експорту AppServerModule {}

Створіть файл main.server.ts у каталозі src /, який експортує AppServerModule, який буде діяти як точка входу вашого сервера.

експортувати {AppServerModule} з "./app/app.server.module";

Також створіть файл server.ts у кореневому каталозі програми. Цей файл містить код сервера Express. Він прослухає вхідний запит, подасть запитаний актив і виведе HTML-сторінки за допомогою виклику renderModuleFactory (обгорнутий ngExpressEngine).

// Це важливі і необхідні, перш ніж все інше імпортувати "zone.js / dist / zone-node"; імпортувати "reflection-metadata"; імпортувати {enableProdMode} з "@ angular / core"; імпортувати * як експрес від "express"; імпортувати з 'шляху'; // Швидше сервер видає режим W / Prod (режим dev не потрібний) enableProdMode (); // Експрес-сервер const app = express (); const PORT = process.env.PORT || 4000; const DIST_FOLDER = join (process.cwd (), 'dist'); // * ПРИМІТКА :: залиште це як require (), оскільки цей файл будується динамічно з webpack const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require ('./ dist / server / main'); // Експрес-імпорт двигуна {ngExpressEngine} з '@ nguniversal / express-engine'; // Імпортуємо карту модуля для ледачого завантаження імпорту {provideModuleMap} з '@ nguniversal / module-map-ngfactory-loader'; app.engine ('html', ngExpressEngine ({bootstrap: AppServerModuleNgFactory, провайдери: [provideModuleMap (LAZY_MODULE_MAP)]}))); app.set ('view engine', 'html'); app.set ("перегляди", приєднатися (DIST_FOLDER, 'browser')); // TODO: безпечно реалізовує запити app.get ('/ api / *', (req, res) => {res.status (404) .send ('запити даних не підтримуються');}); // Сервер статичних файлів з / browser app.get ('*. *', Express.static (join (DIST_FOLDER, 'browser'))); // Всі регулярні маршрути використовують універсальний движок app.get ('*', (req, res) => {res.render ('index', {req});}); / / Запуск app.listen сервера вузлів (PORT, () => {console.log (`Сервер вузла прослуховує http: // localhost: $ {PORT} ');});

Тепер, коли ви налаштували сервер, потрібно додати й оновити файли конфігурації. Створіть файл tsconfig.server.json у каталозі src.

{"extends": "../tsconfig.json", "compilerOptions": {"outDir": "../out-tsc/app", "baseUrl": "./", "module": "commonjs" , "types": []}, "виключити": ["test.ts", "** / *. spec.ts"], "angularCompilerOptions": {"entryModule": "app / app.server.module # AppServerModule "}}

Налаштуйте файл webpack.server.config.js у кореневому каталозі програми з таким кодом:

const path = require ('path'); const webpack = require ('webpack'); module.exports = {entry: {server: './server.ts'}, вирішити: {розширення: ['.js', '.ts']}, ціль: 'вузол', режим: 'немає', / / це гарантує, що ми включимо node_modules та інші зовнішні бібліотеки сторонніх розробників: [/ node_modules /], вивід: {path: path.join (__dirname, 'dist'), ім'я файлу: '[name] .js'}, модуль: { Правила: [{test: / \ _s$/, loader: 'ts-loader'}]}, плагіни: [// Тимчасове виправлення для проблеми: https://github.com/angular/angular/issues/11580 / / для 'WARNING Критична залежність: запит на залежність є виразом' new webpack.ContextReplacementPlugin (/(.+)?angular(/\t)core(.+)?/, path.join (__ dirname, '). src '), // розташування вашого src {} // карта ваших маршрутів, новий webpack.ContextReplacementPlugin (/(.+)?express(\t (__dirname, 'src'), {})]};

Тепер оновіть конфігурацію Angular CLI і встановіть вихідний шлях збірки сервера, додавши наступний код до angular.json:

"архітектор": {... "сервер": {"builder": "@ angular-devkit / build-angular: server", "options": {"outputPath": "dist / server", "main": " src / main.server.ts "," tsConfig ":" src / tsconfig.server.json "}}}

Нарешті, додайте команди збирання та подачі до розділу скриптів package.json.

Таким чином ви зможете утримувати ng для звичайного рендеринга на стороні клієнта і використовувати npm run build: ssr && npm run served: ssr для використання відтворення на сервері за допомогою Universal.

"scripts": {... "build: ssr": "npm run build: клієнт-і-сервер-пакети && npm runpack: сервер", "служити: ssr": "вузол dist / server", "build: клієнт-і-сервер-пакети ":" ng build -prod && ng run-app: server "," webpack: server ":" webpack --config webpack.server.config.js --progress - colors " }

7.4 Створення та запуск програми

Тепер, коли все налаштовано, потрібно добре йти! Створіть програму та запустіть сервер.

npm run build: ssr && npm виконання: ssr

GitHub репо & жити демо

Див. GitHub repo тут

Див тут

Закриття думок

Загалом, створення цього демо з Angular було приємним досвідом. Створення проекту і захоплення загальної ідеї та концепцій Angular було простіше, ніж я думав - це був мій перший раз з цим фреймворком! Я можу остаточно побачити, як підхід може бути корисним для великої команди.

Однак включення Universal до мого проекту було складніше, ніж я передбачав; дуже легко заблукати у всіх конфігураційних файлах!

Мені потрібно було трохи менше двох днів, щоб побудувати цю демонстрацію, включаючи початкове читання та виправлення помилок. Документація Angular була повною та легкою для виконання, оскільки кожен фрагмент коду був повністю пояснений.

Якби я хотів ще просунути цей приклад, я міг би отримати продукти з API, а не знущатися над ними в додатку і скористатися службами та ін'єкціями залежностей, як пояснено в офіційну документацію імітувати більш реальний сценарій.

Сподіваюся, що це допоможе вам отримати ваш кутовий SEO право! :)

Якщо ви користуєтеся цією публікацією, будь ласка, візьміть секунду поділіться ним у Twitter . Є коментарі, запитання? Натисніть розділ нижче!

Навіщо турбуватися про кутовий SEO?
Чи не підтримується Google Angular?
Отже, що це означає?
Навіщо турбуватися про кутовий SEO?
Чи не підтримується Google Angular?
Швидше за все?
ContextReplacementPlugin (/(.+)?
Angular(/\t)core(.+)?
ContextReplacementPlugin (/(.+)?
Є коментарі, запитання?