- Co to jest Next.js?
- Obsługa React.js SEO
- Next.js Samouczek: Obsługa SEO na SPA React.js
- 1. Tworzenie struktury projektu
- 2. Wyśmiewanie prawdziwej architektury projektu dzięki Redux
- 3. Pisanie i renderowanie produktów
- 4. Generowanie plików statycznych dla React SEO
- 5. Wdrażanie zasobów statycznych
- Demo na żywo i repozytorium GitHub
- Inne ważne ogólne uwagi dotyczące SEO
- Zamykanie myśli
W pośpiechu? Przejdź do kroki samouczka lub demo na żywo .
Nie tak dawno temu mój znajomy programista opowiadał mi o nowym projekcie e-commerce dla klienta.
„Chciałbym korzystać z aplikacji React.js, gdyby nie wszystkie te problemy z SEO”.
Westchnienie
Myślałem, że już go przekonałem wcześniejszy post na Vue.js (lub ten z Angular), że SEO z frameworkami JS było łatwe do zarządzania.
Nie sądzę! Zacząłem od zera i wyjaśniłem mojemu przyjacielowi, jak radzić sobie z SEO za pomocą React SPA.
Dzisiaj odpowiadam mu słowami, używając Next.js do stworzenia przyjaznego robotowi e-commerce SPA.
W tym samouczku:
- Utwórz projekt Next.js.
- Użyj powiązań React / Redux.
- Pisz i renderuj produkty.
- Generuj statyczne pliki dla SEO.
- Wdrażaj moje zasoby statyczne za pomocą Netlify.
Zanim przejdziemy do praktyczności, przejrzyjmy trochę teorii.
Co to jest Next.js?
W skrócie Next.js to lekka platforma dla aplikacji React statycznych i renderowanych przez serwer.
Nie myl go z Nuxt, który jest ramą Uniwersalne aplikacje Vue.js —Dokładnie zainspirowany Next. Mają bardzo podobne cele.
Do tej pory musisz przynajmniej usłyszeć o React, ale dla jasności zdefiniujemy ją jako opartą na komponentach bibliotekę JavaScript do tworzenia interfejsów.
A co rozumiemy przez Universal JavaScript ? To dotyczy aplikacji, w których JavaScript działa zarówno na kliencie, jak i na serwerze. To jest świetne zarówno dla wydajności ładowania pierwszej strony, jak i dla celów SEO, jak zobaczymy za chwilę.
Next ma także fajny zestaw funkcji, w tym automatyczne dzielenie kodu, proste routing po stronie klienta, środowisko dev oparte na pakietach webpack i dowolną implementację serwera Node.js. Może być również używany jako statyczny generator witryn .
Nic dziwnego, że duże firmy, takie jak Netflix, Ticketmaster i GitHub, już z niego korzystają.
Obsługa React.js SEO
O co chodzi z SEO w React SPA? Podobnie jak wiele frameworków frontendowych, renderowanie odbywa się dynamicznie za pomocą JavaScript. Boty wyszukiwarek mają trudności z przeszukiwaniem asynchronicznej zawartości naszych stron, co skutkuje niższymi wynikami SEO.
Optymalizacja pod kątem wyszukiwarek internetowych jest obecnie bardzo konkurencyjnym polem, a drobne błędy mogą kosztować cały biznes online.
Zobaczmy, jak możemy to naprawić!
Jak mogę sprawdzić, czy moja zawartość SPA jest poprawnie przeszukana?
Proponuję, żebyś uciekał Pobierz jako Google z Google Search Console na każdej kluczowej stronie Twojej witryny.
Nazwa jest dość oczywista, ale możesz użyć tego narzędzia, aby upewnić się, że boty znajdują twoją treść. Powie ci, czy rzeczywiście może uzyskać dostęp do strony, jak ją renderuje i czy jakiekolwiek zasoby strony (obrazy lub skrypty) są zablokowane dla Googlebota.
Jeśli zauważysz, że renderowanie dynamiczne JS powoduje jakiekolwiek przeszkody w indeksowaniu wyszukiwarek, możesz szybko na nim działać.
Jak upewnić się, że moje treści są indeksowane?
Jak już dowiedziałem się z Vue.js, istnieje kilka rozwiązań tego problemu. W tym przypadku odpowiedź będzie pochodzić z Next.js.
Wszystko, co musisz określić, to właściwe podejście do konkretnych potrzeb:
→ Renderowanie po stronie serwera . W konfiguracji SSR odciążasz proces renderowania do zaplecza. Następnie zwracane są klientowi w pełni renderowane widoki HTML, co ułatwia logikę interfejsu. Z tego powodu takie podejście jest doskonałe dla aplikacji wrażliwych na czas.
→ Generowanie plików statycznych . Ten lekki proces polega na załadowaniu wszystkich twoich zasobów do statycznego kodu HTML, z którego korzystają roboty indeksujące. Wykonuje się tylko dla stron żądanych przez boty, więc nie są blokowane przez cały JavaScript, w przeciwnym razie (dla zwykłych użytkowników) wszystko jest ładowane jak zwykle.
→ Narzędzia innych firm, takie jak Prerender SPA Plugin & Prerender.io również robi ten sam proces, co ten drugi, z doskonałymi wynikami.
W tym demo zdecydowałem się na generowanie plików statycznych, ponieważ nie wymaga serwera, który pasuje bezpośrednio do Logika JAMstack .
Aby dowiedzieć się więcej o podejściach do renderowania, obejrzyj ten szczegółowy samouczek wideo . Zrobiono to dla Vue.js, ale pojęcia mają zastosowanie do React.js.
Next.js Samouczek: Obsługa SEO na SPA React.js
Warunek wstępny
1. Tworzenie struktury projektu
Zacznijmy od zera tutaj. Utwórz nowy folder, w którym ci się spodoba i uruchom następujące polecenia:
npm init npm install --save next npm install --save react npm install --save react-dom npm install --save redux npm install --save react-reduxTeraz, gdy mam wymagane zależności, napiszmy rzeczywistą strukturę plików.
root ├─── komponenty ├───lib └───strony2. Wyśmiewanie prawdziwej architektury projektu dzięki Redux
Chcę, aby to demo było jak najbardziej realne. Więc nawet jeśli będzie to trochę wymyślone dla naszego przypadku użycia, zdecydowałem się użyć Redux z React / Redux wiązania.
Później deklaruję sklep z produktami jako stanem początkowym, ale bez żadnych działań i reduktorów. Robi się to tylko po to, aby zbliżyć się do prawdziwej architektury.
Wskocz do folderu stron i utwórz plik _app.js, który jest zupełnie nowym dodatkiem do Next - będzie działać tylko wtedy, gdy używasz wersji 6 i nowszych.
Umożliwia przejście stron, granice błędów i inne. W moim przypadku użyję go do napisania nowego formatu aplikacji, który używa dostawcy React / Redux, aby wstrzyknął sklep Redux do moich komponentów.
Zastrzeżenie: ta architektura jest bardzo inspirowana to następne z demo Redux .
Oto treść mojego pliku:
import App, {Container} z importu 'next / app' React from 'react' import withReduxStore z '../lib/with-redux-store' import {Provider} z klasy 'react-redux' MyApp rozszerza aplikację {render ( ) {const {Component, pageProps, reduxStore} = this.props return (<Container> <Provider store = {reduxStore}> <div id = "main"> <h1 className = "title"> Peaky Blinders 'Store </ h1 > <Component {... pageProps} /> <div> <p> Przyjazna SEO aplikacja Next.js z <a href="https://snipcart.com/"> Snipcart </a> zasilanym sklepem. < a href = "https://github.com/snipcart/next-snipcart"> [Zobacz kod] </a> <a href = "https://snipcart.com/blog/react-seo-nextjs-tutorial "> [Przeczytaj pełny samouczek] </a> </p> </div> </div> </Provider> </Container>)}} eksportuj domyślnie zReduxStore (MyApp)Jak widać, udostępniam sklep mojemu dostawcy i przekazuję bieżące rekwizyty strony do bieżącego komponentu.
Nie eksportuję komponentu bezpośrednio, ale zamiast tego wywołuję withReduxStore z MyApp jako parametrem. Musisz stworzyć tę funkcję, ponieważ w tej chwili nie istnieje.
Jest to zdecydowanie najbardziej skomplikowana funkcja. Na potrzeby tego postu nie wyjaśnię go dokładnie, ponieważ jest nieco bardziej zaawansowany, a sekcja złożona służy tylko wtedy, gdy korzystano z renderowania po stronie serwera. Ponieważ wygeneruję statyczne zasoby, wszystko powinno być w porządku.
Przejdź więc do folderu / lib i utwórz plik with-redux-store.js o następującej treści:
importuj aplikację z 'next / app' import {initializeStore} z '../store' const isServer = typeof window === 'undefined' const __NEXT_REDUX_STORE__ = '__NEXT_REDUX_STORE__' funkcja getOrCreateStore (initialState) {// Zawsze twórz nowy sklep, jeśli serwer, w przeciwnym razie stan jest dzielony między żądania jeśli (isServer) {return initializeStore (initialState)} // Przechowuj w zmiennej globalnej jeśli klient if (! window [__ NEXT_REDUX_STORE__]) {window [__ NEXT_REDUX_STORE__] = initializeStore (initialState)} return window [__ NEXT_REDUX_STORE__} powrót okno ]} export default (App) => {return class Redux extends React.Component {statyczny async getInitialProps (appContext) {const reduxStore = getOrCreateStore () // Podaj sklep do getInitialProps stron appContext.ctx.reduxStore = reduxStore let appProps = {} if (App.getInitialProps) {appProps = oczekuj App.getInitialProps (appContext)} return {... appProps, initialReduxState: reduxStore.getState ()}} constructor (props) {super (props) this.reduxStore = getOrCreateStore ( rekwizyty. initialReduxState)} render () {return <App {... this.props} reduxStore = {this.reduxStore} />}}}Zasadniczo sprawdza to, czy aplikacja działa na serwerze lub w przeglądarce, a następnie decyduje, czy będzie obsługiwać nową instancję sklepu Redux, czy też bieżącą. Kiedy już zostanie to określone, daję je komponentowi aplikacji jako rekwizyt.
Umożliwi to dostęp do sklepu w każdym komponencie najwyższego poziomu.
Importuj initizeStore, który jest ostatnim elementem '' kontroli danych '' potrzebnym przed wskoczeniem do produktów. Utwórz plik store.js bezpośrednio w folderze głównym.
import {createStore} z 'redux' export const actionTypes = {} const initialState = {products: [{name: 'My first product', cena: 50, opis: 'I like turtles', image: 'url', id: 1}, {nazwa: „Mój drugi produkt”, cena: 100, opis: „lubię zonks”, obraz: „url”, id: 2}, {nazwa: „mój trzeci produkt”, cena: 150, opis: „Lubię smoki”, image: „url”, id: 3}]} // REDUCERS export const reduktor = (state = initialState, action) => {switch (action.type) {default: return state}} funkcja eksportu initializeStore (initialState = initialState) {return createStore (reduktor, initialState)}Jak wspomniano wcześniej, sklep ma gołe kości. To naprawdę tworzy instancje ze stanem początkowym, ale nie dostarcza niczego innego. Nadal będziesz umieszczał tam produkty, ponieważ daje realistyczny sposób dostępu do danych w komponentach, które zdefiniuję w następnym kroku.
3. Pisanie i renderowanie produktów
Dla tego demo chcę dwa różne komponenty, produkty.js, które będą wyświetlać łącze do każdego produktu, oraz produkt.js, który pokaże szczegóły każdego produktu.
Napisz każdy z nich w komponencie / folderze.
Produkty będą nieco bardziej złożone, ponieważ muszą mieć dostęp do sklepu Redux, ale oba są proste, ponieważ są elementami funkcjonalnymi. Wyrenderowują tylko to, co są podane jako rekwizyty, dlatego mogą być reprezentowane wyłącznie jako funkcja bez rozszerzania czegokolwiek.
Oto komponent produktów:
import Link z 'next / link' const ProductLink = (props) => (<div className = "product"> <Link jako = {`/ product / $ {props.id}`} href = {`/ product? id = $ {props.id} `}> <a> <img src = {props.image} alt = {props.name} height = '250' className =" thumbnail "/> <p> {props.description} < / p> <p> {props.name} </p> </a> </Link> </div>) var Products = ({products}) => (<div> <div className = "products"> {products.map (props => (<ProductLink key = {props.id} {... props} />))} </div> </div>) domyślne produkty eksportuA teraz oto product.js:
export default (props) => (f <div className = "product"> <a className="product" href={props.url }> <img src = {props.image} alt = {props.name} className = „thumbnail” /> <p> {props.name} </p> </a> <button className = "snipcart-add-item" data-item-name = {props.name} data-item-id = { props.id} data-item-image = {props.image} data-item-url = '/' data-item-price = {props.price}> Kup za {props.price} $ </button> < / div>)Teraz, gdy masz te dwa składniki, musisz użyć ich w trasach, aby mogły renderować dane.
Aby to zrobić, wygeneruj dwa nowe pliki w folderze stron, index.js i product.js.
Pierwszy z nich wygląda następująco:
import React from 'react' import {connect} z importu 'react-redux' Import produktów z importu '../components/products' Head z klasy 'next / head' Index rozszerza React.Component {render () {return (<div > <Head> <link href = "/ static / main.css" rel = "stylesheet" /> <meta name = "title" content = "Peaky Blinder's e-commerce" /> <meta name = "description" content = „Znajdź najlepsze produkty Peaky Blinders online.” /> </Head> <Produkty {... this.props} /> </div>)}} const mapStateToProps = (state) => ({products: state.products }) export default connect (mapStateToProps) (Index)To, co robi React / Redux, zamiast pozwolić ci na bezpośredni dostęp do sklepu Redux, daje ci funkcję łączenia, która daje ci możliwość odwzorowania części stanu na rekwizyt. Chociaż nie jest to zrobione tutaj, może również dać sposób odwzorowania funkcji dyspozytorskiej na rekwizyt.
To całkowicie izoluje logikę od warstwy prezentacji. Jest to naprawdę ciekawy sposób robienia rzeczy i duży wpływ na programowanie funkcjonalne, ponieważ można łatwo podzielić wszystkie zależności komponentu bezpośrednio w jego rekwizytach.
Jeśli chcesz przeczytać więcej na ten temat, znajdziesz fajny artykuł tutaj który wprowadza te pojęcia.
Pamiętając o tej zasadzie, zdefiniuj drugi plik jako:
import React from 'react' import {connect} z 'react-redux' import ProductComp z '../components/product' import Head z klasy 'next / head' Produkt rozszerza React.Component {static getInitialProps = ({query}) => ({id: query.id}) getProduct = () => (this.props.products.filter (x => x.id == this.props.id) [0]) render = () => (<div> <Head> <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 =" YjdiNWIyOTUtZTIyMy00MWMwLTkwNDUtMzI1M2M2NTgxYjE0 "id =" snipcart "> </script> <link href =" https://cdn.snipcart.com/ themes / 2.0 / base / snipcart.min.css "rel =" stylesheet "type =" text / css "/> <link href =" / static / main.css "rel =" stylesheet "/> <meta name =" title "content = {" Peaky Blinder's "+ this.getProduct (). name} /> <meta name =" description "content = {this.getProduct (). description} /> </Head> <a href =" / „> wróć do domu </a> <ProductComp {... (this.getProduct ())} /> </div>); } const mapStateToProps = (state) => ({products: state.products}) eksportuj domyślne połączenie (mapStateToProps) (Produkt)W ten sposób komponenty pozostają „czyste”, co oznacza, że nie obsługują logiki filtrowania ani logiki pobierania. Po prostu pobierają dane i pokazują je.
Dodałem także niezbędne skrypty Snipcarta. Komponent głowy Next.js jest prostym opakowaniem. Tak więc wszystko, co się tam znajdzie, będzie spakowane wewnątrz tagu głowy renderowanej strony.
W tym miejscu umieściłem także kilka tagów meta. W tym przypadku użyłem „tytułu” i „opisu”, które należy wypełnić badanymi słowami kluczowymi. Nawet jeśli nie pojawią się na stronie, pomogą robotom indeksującym zrozumieć treść Twojej strony.
W przypadku SEO ważne jest również, aby wiedzieć o meta name = „robotach” . Użyjesz go w większych projektach, w których masz dostęp do stron wewnętrznych po zalogowaniu lub dowolnej innej strony, której nie chcesz indeksować. Przeczytaj to nauczyć się wszystkich jego atrybutów.
4. Generowanie plików statycznych dla React SEO
Ponieważ strony są tworzone dynamicznie przy użyciu danych sklepu Redux, musisz podać kilka ścieżek do Next, aby wiedział, jakie trasy generować podczas tworzenia plików statycznych.
Aby to zrobić, wygeneruj plik next.config.js bezpośrednio w folderze trasy:
module.exports = {exportPathMap: function () {return {'/': {page: '/'}, '/ product / 1': {page: '/ product', zapytanie: {id: "1"}} , '/ product / 2': {page: '/ product', zapytanie: {id: "2"}}, '/ product / 3': {page: '/ product', zapytanie: {id: "3" }}}}}Naprawdę podoba mi się, jak to po prostu jest obsługiwane. Nie ma potrzeby podłączania się do procesu kompilacji; prosty plik JS pozwala to zrobić.
Oczywiście, były to tylko trzy produkty z łatwymi identyfikatorami do twardego kodu. Ale trudno byłoby stworzyć zwrócony obiekt dynamicznie w określonym formacie, ponieważ jest to plik JavaScript, w którym można użyć dowolnej logiki.
Przed wdrożeniem tego programu na jakiejkolwiek stronie trzeciej spróbujmy najpierw lokalnie.
Dodaj następującą sekcję skryptów do pliku package.json:
„skrypty”: {„build”: „next build”, „export”: „next export”, „deploy”: „next build && next export”, „start”: „next”}Teraz uruchom npm start w folderze głównym projektu. Rozpocznie się Next jako serwer i powinieneś mieć dostęp do wszystkiego pod adresem http: // localhost: 3000.
Jeśli chcesz zamiast tego wygenerować pliki statyczne, możesz to zrobić za pomocą eksportu uruchamianego przez NPM. Spowoduje to wygenerowanie folderu, w którym je znajdziesz. Jeśli chcesz umieścić je lokalnie, aby przetestować dane wyjściowe, możesz to zrobić szybko za pomocą pakietu npm, takiego jak służyć.
5. Wdrażanie zasobów statycznych
Jesteś teraz gotowy do wdrożenia witryny. Użyjmy Netlify.
Najpierw musisz przesłać swój kod do repozytorium Git, a następnie przeskoczyć do Netlify deska rozdzielcza .
Tam wybierz utworzenie nowej witryny o następującej konfiguracji:
Warto zauważyć, że twórcy Next mają także produkt do wdrażania o nazwie Teraz . Pozwala wdrożyć statyczne zasoby po zbudowaniu bezpośrednio z terminala za pomocą jednego polecenia. Jest naprawdę fajnie, ale ponieważ już używam repozytorium Git, aby pokazać mój kod, postanowiłem trzymać się Netlify.
Demo na żywo i repozytorium GitHub
Zobacz demo na żywo tutaj .
Zobacz repozytorium GitHub tutaj .
Inne ważne ogólne uwagi dotyczące SEO
- Indeksowanie mobilne jest teraz jednym z głównych czynników rankingu. Tak bardzo, że powinieneś zadbać o swoje mobilne wrażenia tak samo jak o komputerze stacjonarnym - jeśli nie więcej!
- Jeśli nadal nie zdajesz sobie sprawy ze znaczenia połączenia HTTPS, powinieneś od razu zajrzeć do niego. Jestem gospodarzem tego demo Netlify , który zapewnia bezpłatne certyfikaty SSL ze wszystkimi planami.
- Aby zwiększyć swoją grę SEO, będziesz chciał stworzyć świetna treść . Chcesz także mieć możliwość łatwej edycji i optymalizacji. Do celów edycji treści rozważ rzucenie jednego z nich bezgłowy CMS do miksu!
- Nie zapomnij dodać odpowiednich tagów meta, jak widzieliśmy wcześniej. Mapa witryny Twoich aplikacji jest również bardzo przydatna tutaj. Możesz znaleźć świetny przykład, jak zbudować mapę witryny dla projektów Next.js tutaj .
Zamykanie myśli
Gra zarówno z Next.js, jak i React była naprawdę zabawna. Nie spotkałem się z żadnymi poważniejszymi wyzwaniami, ponieważ w ich dokumentach wszystko było dość proste, co jest bardzo dokładne. Podoba mi się podejście „quiz”, oryginalne!
Zbudowanie całości zajęło mi około dwóch godzin. Trochę więcej czasu zajęło użycie powiązania react-redux: wędrowałem przez chwilę w ich przykładach, aby wyraźnie zrozumieć, co się dzieje.
Aby to wszystko dalej popchnąć, fajnie byłoby stworzyć sklep z większą liczbą produktów, aby dynamicznie wygenerować mapę. Zastanawiam się również, w którym momencie proces budowania staje się nadęty, jeśli masz zbyt wiele tras do wyeksportowania. Jeśli masz na to odpowiedź, daj mi znać w komentarzach!
Dzięki kreatywności, wspaniałemu kodowaniu i troskliwej dbałości o SEO nic nie powinno stać na przeszkodzie kolejnym projektom!
Jeśli podobał Ci się ten post, poświęć chwilę podziel się nim na Twitterze . Masz komentarze, pytania? Naciśnij sekcję poniżej!
Js?Js?
Jak mogę sprawdzić, czy moja zawartość SPA jest poprawnie przeszukana?
Jak upewnić się, że moje treści są indeksowane?
Id}`} href = {`/ product?
Masz komentarze, pytania?