
Come rendere un sito SPA indicizzato correttamente (InertiaJS)
By
InertiaJS ci viene in aiuto con un sito SPA (Single Page Application). Un sito SAP ha un “punto di ingresso” HTML (di solito un div) a cui vengono agganciate tutte le pagine, tipico esempio è ReactJS, il quale a partire da quel punto tutte le pagine vengono generate dagli scripts Javascript.
Analizzerò un sito Laravel che usa React per la generazione delle pagine e InertiaJS come strumento di generazione e utilizzo delle rotte di Laravel.
Utilizzare Inertia ci risolve già una grande quantità di problemi, quindi ne consiglio caldamente l’utilizzo quando si sviluppa un sito Laravel + React (vedi questo articolo).
Laravel
La view da cui tutto il sito partirà è di norma app.blade.php, e questo è un tipico esempio:
// resources/views
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<!-- Start cookieyes banner -->
<script id="cookieyes" type="text/javascript" src="https://cdn-cookieyes.com/client_data/dc1bb35facd7addaccf4e8a9/script.js"></script>
<!-- End cookieyes banner -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title inertia>{{ config('app.name', 'Laravel') }}</title>
<meta name="description" content="@yield('meta_description', 'Sito che raccoglie molte delle pubblicazioni uscite nel tempo che raccontano lui e le sue opere.')">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
<!-- Styles -->
<!-- Scripts -->
@routes
@viteReactRefresh
@vite(['resources/js/app.jsx', "resources/js/Pages/{$page['component']}.jsx"])
@vite(['resources/css/app.css'])
@inertiaHead
</head>
<body class="font-sans antialiased">
@inertia
</body>
</html>
Faccio subito notare 2 cose:
- il tag <title inerita>
- e il tag <meta name=”description” ecc…
Questi 2 punti sono essenziali per rendere ogni pagina “visualizzata” dai bot di Google (e gli altri motori di ricerca) diversa e impedire che venga ignorata non avendo elementi distintivi rispetto alle altre.
Per impostare questi valori in modo specifico per la pagina interessata, nel file .jsx va usato questo tag Javascript <Head></Head>
import { Head } from '@inertiajs/react';
export default function NomePagina() {
return (
<>
<Head>
<title>Titolo specifico di questa pagina</title>
<meta name="description" content="Descrizione specifica di questa pagina per i motori di ricerca." />
</Head>
{/* Resto del contenuto pagina */}
</>
);
}Robots
Altro elemento da verificare è il file robots.txt dentro la cartella public, deve essere almeno così
User-agent: * Allow: /
Sitemap
Per aiutare i bots a trovare tutte le pagine, dare il giusto peso ad ognuna e indicare la frequenza di aggiornamento, consiglio di usare la sitemap e nello specifico di installare il plugin per Laravel spatie/laravel-sitemap.
Instlliamo questo plugin e pubblichiamo il suo file di configurazione
composer require spatie/laravel-sitemap php artisan vendor:publish --provider="Spatie\Sitemap\SitemapServiceProvider" --tag=sitemap-config
Possiamo creare un comando Laravel da eseguire per far generare automaticamente la sitemap
php artisan make:command GenerateSitemap
Questo crea il file app/Console/Commands/GenerateSitemap.php il cui contenuto dovrebbe essere qualcosa del genere
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Spatie\Sitemap\SitemapGenerator;
class GenerateSitemap extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'sitemap:generate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate the sitemap';
/**
* Execute the console command.
*/
public function handle(): int
{
SitemapGenerator::create(config('app.url'))
->writeToFile(public_path('sitemap.xml'));
$this->info('Sitemap generated successfully.');
return self::SUCCESS;
}
}
adesso lo possiamo eseguire da console
php artisan sitemap:generate
In progetti complessi con molte pagine dinamiche può aver senso partire dalle rotte presenti nei file di Laravel (per esempio web.php). Prendiamo i modelli Eloquent che servono a generare le pagine e iteriamo su di esse per generare i vari url da inserire nella sitemap, per esempio vedi questo
Quote::query()
->select(['id', 'updated_at'])
->orderBy('id')
->chunkById(500, function ($quotes) use ($sitemap): void {
foreach ($quotes as $quote) {
$url = Url::create(
route('show-quote', ['id' => $quote->id])
)
->setPriority(0.7)
->setChangeFrequency(Url::CHANGE_FREQUENCY_YEARLY);
if ($quote->updated_at !== null) {
$url->setLastModificationDate($quote->updated_at);
}
$sitemap->add($url);
}
});Vediamo che il modello di dati Quote viene filtrato, ordinato e spezzettato in chunk di 500 elementi per poi creare il suo URL, dargli una priorità e una frequenza di aggiornamento. Infine lo aggiungiamo alla sitemap.
Lanciando il comando dovremmo vedere che adesso la sitemap si popola di tutti gli url necessari.
Google Search Console
Bene adesso passiamo questa sitemap a Google Search Console e lasciamo che vengano indicizzate le varie pagine.