Angular SEO Done Right z renderowaniem po stronie serwera [Live Demo]

  1. Po co zawracać sobie głowę Angular SEO? Czy program Angular nie jest wspierany przez Google?
  2. Jak radzić sobie z problemami Angular SEO
  3. Samouczek techniczny: Przykładowy, przyjazny dla SEO przykładowy SPA z Universal
  4. Konfigurowanie środowiska programistycznego
  5. 1. Konfiguracja struktury projektu przy użyciu Angular CLI
  6. 2. Tworzenie pierwszego komponentu kątowego
  7. 2.1 Wyśmiewanie listy produktów
  8. 3. Lista produktów aplikacji
  9. 4. Dodawanie routingu do aplikacji Angular
  10. 5. Tworzenie komponentu produktu
  11. 6. Integracja funkcjonalności koszyka na zakupy
  12. 7. Korzystanie z Angular Universal dla SEO
  13. 7.1 Instalowanie Angular Universal
  14. 7.2 Edycja aplikacji klienta
  15. 7.3 Konfigurowanie serwera
  16. 7.4 Budowanie i uruchamianie aplikacji
  17. GitHub repo i demo na żywo
  18. Zamykanie myśli

W pośpiechu? Przejdź do poradnik techniczny lub demo na żywo .

Google indeksuje i renderuje JavaScript w dalszym ciągu w dość niejasny sposób.

Sprzeczne stwierdzenia i eksperymenty można znaleźć w całej sieci.

Co to znaczy?

Jako programista POTRZEBUJESZ optymalizacji witryn zbudowanych za pomocą popularnych platform JS dla SEO.

Mając to na uwadze, oto trzecia część naszych bieżących skryptów JavaScript dotyczących serii zagadnień SEO:

  1. Budowanie wstępnie przygotowanej aplikacji Vue.js
  2. Zastosowanie React SEO z Next.js .
  3. Tutaj zajmę się Angular SEO.

Dokładniej, stworzymy serwerowy Angular e-commerce SPA przy użyciu Universal .

Oto kroki, które zastosujemy, aby to osiągnąć:

  1. Konfigurowanie projektu Angular.
  2. Tworzenie komponentów kątowych.
  3. Włączanie funkcji e-commerce w naszym SPA.
  4. Użycie Universal w celu ułatwienia SEO naszej aplikacji Angular

To powinno być zabawne!

Po co zawracać sobie głowę Angular SEO? Czy program Angular nie jest wspierany przez Google?

Kątowy to framework JS o otwartym kodzie źródłowym opracowany przez inżynierów Google w 2010 roku.

Wspaniale jest uzupełnić bezgłowy stos lub jakikolwiek JAMstack z tego powodu. Ale nadal ma wspólne problemy SEO znane ze struktur JavaScript.

Aplikacje jednostronicowe JS dynamicznie dodają zawartość do stron za pomocą JavaScript. Nie jest to optymalne dla SEO: przeszukiwacze najprawdopodobniej nie uruchomią kodu JS, nie napotkając w ten sposób rzeczywistej zawartości strony.

Począwszy od 2018 roku, słowo mówi, że Google może indeksować i wyświetlać strony wypełnione w JavaScript, czytając je tak, jak robią to nowoczesne przeglądarki. Mimo że cytaty z giganta sam nie jestem tak optymistyczny:

„Czasy się zmieniły. Dzisiaj, dopóki nie blokujesz Googlebotowi indeksowania plików JavaScript lub CSS, generalnie jesteśmy w stanie renderować i rozumieć Twoje strony internetowe, takie jak nowoczesne przeglądarki”.

„Czasami sytuacja nie jest idealna podczas renderowania, co może negatywnie wpłynąć na wyniki wyszukiwania Twojej witryny”.

„Czasami JavaScript może być dla nas zbyt złożony lub tajemniczy, w którym to przypadku nie możemy w pełni i dokładnie renderować strony”.

Chociaż Google stara się zrenderować JS, STILL pokonuje wszystkie inne wyszukiwarki lub roboty społecznościowe (Facebook, Twitter, LinkedIn). Zoptymalizowanie renderowania aplikacji przyniesie również korzyści dla Twoich działań na tych kanałach!

Jest to zbyt dużo niezindeksowanej treści JavaScript, aby pozostawić ją na stole.

Jak radzić sobie z problemami Angular SEO

Aby Twoja witryna Angular znalazła się na szczycie wyników wyszukiwania, musisz trochę popracować.

Pobierz jako Google

Jeśli masz już aplikację publiczną Angular, udaj się do swojej Google Search Console i biegnij Pobierz jako Google na stronach wymagających indeksowania. To powie Ci, co Googlebots może lub nie ma dostępu.

To daje wyobrażenie o tym, które obszary wymagają pracy SEO.

Sposoby na to nie różnią się od tego, co widzieliśmy już w Vue lub React, ale narzędzia to robią.

Prerendering

Ten jest dość prosty. JavaScript jest renderowany w przeglądarce; statyczny kod HTML jest zapisywany i zwracany do robotów indeksujących. To rozwiązanie jest idealne dla prostych aplikacji, które nie polegają na żadnym serwerze. Jest łatwiejszy w konfiguracji niż renderowanie po stronie serwera, ale mimo to ma świetne wyniki SEO.

Dla wstępnego renderowania kątowego proponuję przyjrzeć się Prerender.io .

Renderowanie po stronie serwera

Oto co zrobię tutaj.

Korzystam z SSR Angular Universal .

Mówiąc prościej, uruchomi to Angular na zapleczu, tak aby po złożeniu żądania treść była renderowana w DOM dla użytkownika.

Chociaż ta metoda zwiększa obciążenie serwera, może zwiększyć wydajność na wolniejszych urządzeniach / połączeniach, ponieważ pierwsza strona będzie ładować się szybciej, niż gdyby klient musiał renderować samą stronę.

Badaliśmy te dwie metody Samouczek wideo Vue.js . Treść dotyczy również Angular!

Czy użycie tych technik oznacza, że ​​nagle pojawi się na górze SERP ? Być może. Najprawdopodobniej? Nie. Istnieje wiele innych zagadnień SEO: świetne mobilne UX, połączenie HTTPS, mapa witryny, świetna treść, linki zwrotne itp. Ten post wymienia kilka porad SEO w swoim podsumowaniu!

Samouczek techniczny: Przykładowy, przyjazny dla SEO przykładowy SPA z Universal

Warunki wstępne

  • Podstawowe zrozumienie aplikacji jednostronicowych (SPA)
  • Podstawowa znajomość Maszynopis [opcjonalny]
  • ZA Konto Snipcart (na zawsze za darmo w trybie testowym)

Konfigurowanie środowiska programistycznego

Zainstaluj globalnie interfejs Angular CLI, używając następującej komendy:

npm install -g @ angular / cli

Używam sass w moim projekcie. Jeśli zdecydujesz się to zrobić i nie masz go już zainstalowanego, dobrze:

npm install -g sass

1. Konfiguracja struktury projektu przy użyciu Angular CLI

Utwórz swój projekt za pomocą Angular CLI.

ng new my-app - style = scss --routing

Zauważyłem, jak dodałem do polecenia argument stylu i routingu?

W ten sposób routing i scss zostaną wstawione bezpośrednio do projektu, co jest znacznie łatwiejsze niż próba dodania go później.

Po wykonaniu tej czynności przejdź do katalogu projektu i obsłuż swój projekt.

cd my-app ng służą

Projekt powinien być teraz widoczny lokalnie pod adresem: http: // localhost: 4200 /

2. Tworzenie pierwszego komponentu kątowego

Podobnie jak wiele nowoczesnych bibliotek lub frameworków frontowych, Angular używa systemu komponentów.

W Angular każdy komponent oprócz głównej aplikacji to katalog znajdujący się w src / app / zawierający trzy pliki: plik TypeScript, plik stylizacji i plik HTML.

Ponieważ to demo jest prostym sklepem e-commerce, użyję dwóch komponentów. Komponent produktów będzie zawierał listę i łącze do każdej strony produktu. A komponent produktu wyświetli wszystkie szczegółowe informacje o produkcie.

Użyj wbudowanego polecenia Angular CLI, aby wygenerować nowe komponenty:

ng generuje produkty składowe ng generuje produkt składowy

2.1 Wyśmiewanie listy produktów

Przed edycją komponentów musisz utworzyć strukturę danych dla produktów.

Wygeneruj plik product.ts bezpośrednio w folderze src / app / i nadaj mu wszystkie żądane właściwości.

klasa eksportu Produkt {id: string; nazwa: ciąg; cena: numer; waga: liczba; opis: string; }

Stwórz także mocked-product.ts w tej samej lokalizacji. Ten plik zaimportuje klasę produktu i wyeksportuje tablicę produktów.

W ten sposób będziesz mógł zaimportować listę produktów do dowolnego komponentu.

import {Product} z './product'; export const PRODUKTY: Produkt [] = [{id: "ac-1", nazwa: „Centralny klimatyzator”, cena: 5000,00, waga: 900000, opis: „Dzięki temu centralnemu klimatyzatorowi wszystko jest w porządku”. }, {id: "ac-2", nazwa: "Window Air Conditioner", cena: 300,00, waga: 175000, opis: "Idealny do utrzymania chłodu w pokoju lub małym mieszkaniu." }, {id: "ac-3", nazwa: "A fan", cena: 10,00, waga: 2000, opis: „Niedrogi, ale skuteczny sposób na powstrzymanie współpracowników przed narzekaniem na upał”. },]

3. Lista produktów aplikacji

Dobra, produkt z powodzeniem wyszydzony! Wymieńmy teraz nasze produkty na stronie głównej. Aby to zrobić, otwórz produkty products.component.ts i dodaj:

import {Component, OnInit} z '@ angular / core'; import {PRODUCTS} z „../produktów”; @ Component ({selector: 'app-products', templateUrl: './products.component.html', styleUrls: ['./products.component.scss']}) klasa eksportu ProductsComponent implementuje OnInit {products = PRODUCTS; constructor () {} ngOnInit () {}}

Jak widać, każdy komponent Angulara importuje klasę Component z biblioteki rdzeniowej Angular. @Component ({}) to funkcja dekoratora, która oznacza klasę jako składnik Angular i zapewnia większość jej metadanych.

Wartość pary kluczy selektora to znacznik XML, który można dołączyć do szablonów w celu renderowania tego komponentu.

Zrób to teraz, usuwając wszystko wygenerowane w szablonie głównej aplikacji (app.component.html) i dodaj odpowiedni tag:

<app-products> </app-products>

Gdy już to zrobisz, jeśli odwiedzisz stronę, powinieneś zostać powitany przez:

Teraz zmodyfikujmy plik products.component.html, aby wyświetlić listę produktów przy użyciu dyrektywy repeatera Angulara * ngFor i kierownicy ({{}}), aby powiązać dane z klasy do szablonu.

<h2> Produkty </h2> <ul * ngFor = "pozwól produktowi produktów"> <li> {{product.name}} </li> </ul>

4. Dodawanie routingu do aplikacji Angular

Zmieńmy ten sklep w aplikację jednostronicową z wbudowanym routingiem Angulara.

Ponieważ podczas tworzenia projektu dodałeś argument --routing, możesz przejść bezpośrednio do app-routing.module.ts i przeformułować go na następujący kod:

import {NgModule} z '@ angular / core'; import {Routes, RouterModule} z '@ angular / router'; importuj {ProductComponent} z './product/product.component'; importuj {ProductsComponent} z './products/products.component'; const route: Routes = [{ścieżka: '', komponent: ProductsComponent}, {ścieżka: 'product /: id', komponent: ProductComponent}]; @NgModule ({import: [RouterModule.forRoot (route)], export: [RouterModule]}) export class AppRoutingModule {}

Moduł ten importuje produkty i komponenty produktów oraz tworzy tablicę tras łączących każdą ścieżkę z komponentem.

Możesz zobaczyć, że dodałem symbol zastępczy: id, który będzie mógł pobrać w komponencie produktu, aby wyświetlić odpowiedni produkt.

Ważne jest również zainicjowanie routera przez dodanie RouterModule.forRoot (route) do importu modułu.

Po wykonaniu tej czynności możesz zastąpić tag komponentu w szablonie aplikacji (app.component.html) tagiem <router-outlet>:

<outter-outlet> </router-outlet>

Znacznik wyjścia routera wyświetli widok dla odpowiedniej ścieżki określonej w tablicy tras. W tym przypadku katalog główny wyświetli widok dla komponentu Produkty.

Możesz teraz dodać routerLink = 'relativePath' zamiast dowolnego atrybutu href = 'path' w tagach <a>. Na przykład możesz zaktualizować plik products.component.html za pomocą czegoś takiego:

<h2> Produkty </h2> <ul * ngFor = „pozwól produktowi produktów”> <li> <a routerLink="/product/{{product.id}}"> {{product.name}} </ a > </li> </ul>

W ten sposób każdy element na naszej liście wyśle ​​użytkownika do widoku z komponentem produktu.

5. Tworzenie komponentu produktu

Teraz utwórzmy komponent szczegółów produktu. W pliku TypeScript, product.component.ts, dodaj następujący kod:

import {Component, OnInit} z '@ angular / core'; import {ActivatedRoute} z '@ angular / router'; importuj {Location} z '@ angular / common'; import {PRODUCTS} z „../produktów”; import {Product} z '../product'; @ Component ({selector: 'app-product', templateUrl: './product.component.html', styleUrls: ['./product.component.scss']}) klasa eksportu ProductComponent implementuje OnInit {products = PRODUCTS; url: String; produkt: Produkt; konstruktor (prywatna trasa: ActivatedRoute, prywatna lokalizacja: Lokalizacja) {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): Product {return this.products.find (product => product.id === productId); }}

Powyżej zaimportowałem ActivatedRoute i Location z Angular. Pozwoli ci to pobrać productId z adresu URL i pobrać bieżącą ścieżkę bezpośrednio w konstruktorze.

Zaimportowaliśmy również naszą szyderczą tablicę produktów, pobraliśmy bieżący produkt przy użyciu identyfikatora z trasy za pomocą find () i poprzedziliśmy adres URL adresem początkowym żądań serwera.

Zaktualizujmy teraz szablon komponentu (product.component.html), aby wyświetlić niezbędne informacje i utworzyć przycisk Kup zgodny z Definicja produktu 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] = "product.name" [attr.data-item-url] = "url" [attr.data-item-price] = "product.price" [attr.data-item-weight] = " product.weight "[attr.data-item-description] =" product.description "> Kup ({{product.price}} $) </button> </div>

Zauważ, że nie użyłem nawiasów klamrowych do powiązania danych w atrybutach HTML?

Możesz użyć nawiasów klamrowych tylko dla właściwości, a nie atrybutów. Dlatego musisz użyć składni wiązania atrybutów Angulara, jak pokazano w powyższym kodzie.

6. Integracja funkcjonalności koszyka na zakupy

Teraz zintegrujmy Snipcart, dodając wymagane skrypty z naszym kluczem API do pliku index.html, który obsługuje naszą główną aplikację.

W ten sposób będzie mógł wchodzić w interakcje ze wszystkimi twoimi widokami.

<! doctype html> <html lang = "en"> <head> <meta charset = "utf-8"> <title> Angular Snipcart </title> <base href = "/"> <meta name = "viewport" content = "width = szerokość urządzenia, initial-scale = 1"> <link rel = "icon" type = "image / x-icon" href = "favicon.ico"> </head> <body> <app- root> </app-root> </body> <skrypt src = "https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"> </script> <skrypt 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>

W demie na żywo edytowałem również kilka szablonów, aby ułatwić stylizację każdego komponentu.

Zostawię tę część Tobie, ponieważ nie jest to główny cel przewodnika.

7. Korzystanie z Angular Universal dla SEO

W końcu zróbmy naszą aplikację przyjazną SEO za pomocą SSR.

W tym pokazie skorzystam z a Node.js Express serwer. Pamiętaj, że można dodać Angular Universal na dowolnym serwerze, o ile może on współdziałać z funkcją renderModuleFactory Angulara, ale konfiguracja będzie najprawdopodobniej inna niż ta pokazana w tym poście.

7.1 Instalowanie Angular Universal

Aby rozpocząć, dodajmy niezbędne narzędzia do środowiska programistycznego:

npm install --save @ angular / platforma-serwer @ nguniversal / module-map-ngfactory-loader ts-loader @ nguniversal / express-engine

7.2 Edycja aplikacji klienta

Teraz, gdy mamy już wszystkie niezbędne narzędzia, wyedytujmy kod po stronie klienta, aby umożliwić przejście między stroną renderowaną po stronie serwera a aplikacją po stronie klienta. W app.module.ts zastąp import BrowserModule w dekoratorze @NgModule () następującym kodem:

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

Ponieważ aplikacja jest wbudowana w kod po stronie serwera i kod po stronie klienta, będziesz potrzebować dwóch ścieżek wyjściowych. Zacznijmy od określenia ścieżki wyjściowej dla przeglądarki. Aby to zrobić, edytuj outputPath w angular.json.

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

7.3 Konfigurowanie serwera

Teraz, gdy dokonałeś koniecznej modyfikacji w kliencie, wyedytujmy kod serwera.

Utwórz app.server.module.ts w katalogu src / app.

import {NgModule} z '@ angular / core'; import {ServerModule} z '@ angular / platform-server'; import {ModuleMapLoaderModule} z '@ nguniversal / module-map-ngfactory-loader'; import {AppModule} z './app.module'; import {AppComponent} z './app.component'; @NgModule ({import: [AppModule, ServerModule, ModuleMapLoaderModule], bootstrap: [AppComponent],}) klasa eksportu AppServerModule {}

Wygeneruj plik main.server.ts w katalogu src /, który eksportuje AppServerModule, który będzie stanowił punkt wejścia twojego serwera.

export {AppServerModule} z './app/app.server.module';

Utwórz również plik server.ts w katalogu głównym aplikacji. Ten plik zawiera kod serwera Express. Będzie słuchać przychodzącego żądania, obsługiwać żądany zasób i wyświetlać strony HTML, wywołując metodę renderModuleFactory (opakowaną przez ngExpressEngine).

// Są ważne i potrzebne, zanim cokolwiek innego zaimportuje 'zone.js / dist / zone-node'; import „reflect-metadata”; import {enableProdMode} z '@ angular / core'; import * jako ekspresowy z „express”; importuj {join} z 'path'; // Szybszy serwer renderuje w / Prod mode (tryb dev nigdy nie jest potrzebny) enableProdMode (); // Express server const app = express (); const PORT = process.env.PORT || 4000; const DIST_FOLDER = join (process.cwd (), „dist”); // * UWAGA :: pozostaw to jako require (), ponieważ ten plik jest zbudowany dynamicznie z const webpack const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require ('./ dist / server / main'); // Express Engine import {ngExpressEngine} z '@ nguniversal / express-engine'; // Importuj mapę modułu dla leniwego ładowania import {supplyModuleMap} z '@ nguniversal / module-map-ngfactory-loader'; app.engine ('html', ngExpressEngine ({bootstrap: AppServerModuleNgFactory, dostawcy: [dostarczanieModuleMap (LAZY_MODULE_MAP)]})); app.set ('view engine', 'html'); app.set ('views', join (DIST_FOLDER, 'browser')); // TODO: implementuj bezpiecznie żądania danych app.get ('/ api / *', (req, res) => {res.status (404) .send ('żądania danych nie są obsługiwane');}); // Pliki statyczne serwera z / browser app.get ('*. *', Express.static (join (DIST_FOLDER, 'browser'))); // Wszystkie regularne trasy używają uniwersalnego silnika app.get ('*', (req, res) => {res.render ('index', {req});}); // Uruchom serwer Node app.listen (PORT, () => {console.log (`Serwer nasłuchujący na http: // localhost: $ {PORT}`);});

Po skonfigurowaniu serwera musisz dodać i zaktualizować pliki konfiguracyjne. Utwórz plik tsconfig.server.json w katalogu src.

{"extends": "../tsconfig.json", "compilerOptions": {"outDir": "../out-tsc/app", "baseUrl": "./", "module": "commonjs" , „types”: []}, „exclude”: [„test.ts”, „** / *. spec.ts”], „angularCompilerOptions”: {”entryModule": "app / app.server.module # AppServerModule "}}

Skonfiguruj plik webpack.server.config.js w katalogu głównym aplikacji za pomocą następującego kodu:

const ścieżka = require („ścieżka”); const webpack = require („webpack”); module.exports = {entry: {server: './server.ts'}, rozwiń: {rozszerzenia: ['.js', '.ts']}, target: 'node', tryb: 'none', / / zapewnia to, że dołączamy node_modules i inne zewnętrzne biblioteki: [/ node_modules /], output: {ścieżka: ścieżka.join (__ nazwa_katalogu, 'dist'), nazwa_pliku: '[nazwa] .js'}, moduł: { zasady: [{test: /\.ts$/, loader: 'ts-loader'}]}, wtyczki: [// Temporary Fix for issue: https://github.com/angular/angular/issues/11580 / / for 'OSTRZEŻENIE Krytyczna zależność: żądanie zależności jest wyrażeniem' new webpack.ContextReplacementPlugin (/(.+)?angular(\ *\t)))~~pobj (.+)?/, path.join (__ dirname, ' src '), // lokalizacja twojego src {} // mapy twoich tras), nowy webpack.ContextReplacementPlugin (/(.+)?express(\_)\t)).\t (__dirname, 'src'), {})]};

Teraz zaktualizuj konfigurację Angular CLI i ustaw ścieżkę wyjściową kompilacji serwera, dodając następujący kod do angular.json:

„architect”: {... „server”: {„builder”: „@ angular-devkit / build-angular: server”, „options”: {„outputPath”: „dist / server”, „main”: „ src / main.server.ts "," tsConfig ":" src / tsconfig.server.json "}}}

Na koniec dodaj kompilację i podaj polecenia do sekcji skryptów pakietu.json.

W ten sposób będziesz mógł zachować ng dla normalnego renderowania po stronie klienta i użyć polecenia npm run build: ssr && npm run serve: ssr, aby użyć renderowania po stronie serwera z Universal.

"skrypty": {... "build: ssr": "npm uruchom kompilację: pakiety klient-serwer && npm uruchom webpack: serwer", "służyć: ssr": "węzeł dist / serwer", "kompilacja: pakiety klient-serwer ":" ng build --prod && ng uruchom my-app: serwer "," webpack: serwer ":" webpack --config webpack.server.config.js --progress - colours " }

7.4 Budowanie i uruchamianie aplikacji

Teraz, gdy wszystko jest już gotowe, powinieneś być dobry! Zbuduj aplikację i uruchom serwer.

npm run build: ssr && npm run serve: ssr

GitHub repo i demo na żywo

Zobacz repozytorium GitHub tutaj

Zobacz demo na żywo tutaj

Zamykanie myśli

Podsumowując, zbudowanie tego demo z Angular było przyjemnym doświadczeniem. Stworzenie projektu i uchwycenie ogólnej idei i koncepcji Angular było łatwiejsze niż myślałem - to był mój pierwszy raz z tymi ramami! Mogę ostatecznie zobaczyć, w jaki sposób podejście może być pomocne dla dużego zespołu.

Jednak włączenie Universal do mojego projektu było trudniejsze niż się spodziewałem; naprawdę łatwo się zgubić we wszystkich plikach konfiguracyjnych!

Zbudowanie tego dema zajęło mi trochę mniej niż dwa dni, w tym wstępne czytanie i naprawianie błędów. Dokumentacja Angulara była kompletna i łatwa do śledzenia, ponieważ każdy fragment kodu został dokładnie wyjaśniony.

Gdybym chciał dalej popchnąć ten przykład, mógłbym pobrać produkty z API, a nie kpić z nich w aplikacji i korzystać z usług i wstrzykiwania zależności, jak wyjaśniono w oficjalna dokumentacja naśladować bardziej realistyczny scenariusz.

Mam nadzieję, że to pomoże Ci uzyskać prawo do Angular SEO! :)

Jeśli podobał Ci się ten post, poświęć chwilę podziel się nim na Twitterze . Masz komentarze, pytania? Naciśnij sekcję poniżej!

Po co zawracać sobie głowę Angular SEO?
Czy program Angular nie jest wspierany przez Google?
Co to znaczy?
Po co zawracać sobie głowę Angular SEO?
Czy program Angular nie jest wspierany przez Google?
Najprawdopodobniej?
ContextReplacementPlugin (/(.+)?
Angular(\ *\t)))~~pobj (.+)?
ContextReplacementPlugin (/(.+)?
Masz komentarze, pytania?