Skip to content
Come rendere un sito SPA indicizzato correttamente (InertiaJS)

Come rendere un sito SPA indicizzato correttamente (InertiaJS)

By Pier Luigi Papeschi

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.