SEO optimalizovaný CSR React.js pomocí React snap

Pokoušíte se Vaši React.js aplikaci udělat více SEO friendly? Určitě jste přišli na to, že to není až tak jednoduché, jak se může na první pohled zdát. Obzvlášť, pokud se bavíme o rozsáhlé aplikaci se spoustou dynamického obsahu, a to ještě třeba spolu s obrovským backendem bez CSR.

V čem je problém?

V React.js bohužel zatím není žádná nativní cesta proto, abyste mohli dynamicky měnit například title nebo meta tagy podle toho, co zrovna crawler prohledává. Podívejte se na Váš index.html v public složce (create-react-app) – to je v podstatě jediné, co defaultně crawleři vidí.

Co s tím? Že by CSR?

První, co většinu programátorů okamžitě napadne, je aplikovat server-side-rendering, ale tohle bohužel nebyla cesta pro nás, protože jsme potřebovali, aby aplikace běžela lokálně na zařízení uživatele. Každopádně frontend jsme měli už kompletně napsaný a měnit ho na CSR, by přineslo víc problémů než užitku. Hledali jsme tedy dál.

Pokus číslo 2: React-helmet

Na základě článků a diskuzí jsme se rozhodli vyzkoušet React-helmet balíček, který doporučuje i React.js. Vše vypadalo dobře, title i meta tagy se měnily jak na localhostu, tak na naší staging branch, ale bohužel nic nefungovalo v produkci.

Důvod, kvůli kterému balíček nefungoval, byl hned po přečtení dokumentace vcelku jasný. Naše stage a localhost funguje jinak než produkce. Localhost i stage se totiž nespouštěly z vybuilděného kódu. To bylo jasné u localhostu, ale u stage nám chvilku trvalo, než jsme na to přišli. Stage jsme spouštěli přes serve balíček, kdežto produkci na základě vybuilděných static souborů, které se poté nahrají na AWS.

Pokus číslo 3: Prerender.io

Dále jsme zkoušeli zaimplementovat Prerender.io, doteď pořádně nevíme, jestli jsme vše použili správně, ale v našem případě zkrátka nic nefungovalo. V jednu chvíli se nám přes Prerender.io podařilo zprovoznit home page, ale to bylo vše. Dalším důležitým faktorem je to, že chceme mít web co nejvíce pod naší kontrolou, ne záviset na 3rd party službě.

S React-snap jsme SEO Friendly apce už o krok blíž!

Po dlouhém hledání, co budeme dělat dát, jsme nakonec narazili na balíček React-snap, který by měl dělat přesně to, co chceme. Vybuildit statické HTML soubory s JS. A to opravdu udělal! Tedy… né tak úplně.

Pozor na umístění componentů! Problém s react-snap byl ten, že jsme měnili header elementy (title, metas) natolik hluboko v components tree, že si tyto změny si zkrátka nedohledal.

Na první pohled si toho nevšimnete, jelikož například na localhostu se title i meta tagy nakonec načtou, ale při buildění na ně React-snap jednoduše nepočkal. Tím pádem vygenerované static soubory neobsahovaly žádné header elementy. Tenhle problém má vcelku jednoduché řešení.

Přesuňte <Helmet /> component  co nejvíce “nahoru” (top-level component , např. <App />), jak to jen půjde. React-helmet by sice měl fungovat kdekoliv, ale v našem případě tomu tak bohužel nebylo.

Pozor na CORS

Dobrá, nyní máme vybuilděné static soubory se správnými header tagy, pushnout do stage, buildění, kontrolování SEO… bum: No title or meta description tags included. Proč? Jak jsem již zmínil na začátku, naše stage běží přes serve package, který nepoužívá vybuilděné static soubory, ale pouze servuje JS kód. Stejně jako kdybych si web zapnul na localhostu přes Yarn start.  Je to sice vcelku jasné, ale zkrátka nás to nenapadlo, a zabralo nám chvíli, než nám to došlo.

Víme, že náš kód se buildí do static HTML souborů a obsahuje správné header tagy. Víme také, že SEO kontrolu nemůžeme vyzkoušet na stage branch. Pro produkci používáme vcelku jednoduchou Gitlab CI Pipeline, která nám vybuildí projekt, uloží ho jako artifact a ten poté nahraje na S3. Pushnul se nejnovější kód na prod. branch a spustila se pipeline. Instalování node modulů, buildění, build dokončen, spuštění React-snapu a… CORS. GG.

Jak CORS vyřešit?

Problém byl proto, že když React-snap buildí soubory, spouští přitom JavaScript samozřejmě. Což znamená, že pokud máme v kódu např. fetch, který hituje náš produkční BE, tak origin tohoto requestu bude IP adresa našeho CI stroje. Tohle není problém u localhostu nebo stage, protože na DEV/STAGE BE, nejsou nastaveny tak striktní CORS Policy (za účelem testování). Na produkci jsou.

Tento problém má víc řešení, úplně nejjednodušší je přidat IP adresu CI do CORS “known hosts”. Toto řešení není perfektní, ale je funkční. Po této změně by mělo být konečně vše v pořádku a build funkční.

Konečně se povedlo a apka je SEO Friendly!

To je vše, nyní je vaše React.js aplikace SEO friendly bez nutnosti používat CSR a navíc, stránky jsou předrenderované, takže aplikace se načítá daleko rychleji.