Semplifica il tuo stack con un generatore di siti statici personalizzato

Pubblicato: 2022-03-10
Riassunto veloce ↬ Nello sviluppo moderno, ci sono così tanti ottimi strumenti per lo sviluppo di siti Web, ma spesso sono più di quanto necessario per un determinato progetto. In questo articolo, esploreremo come prendere una semplice pagina HTML e rendere il suo contenuto modificabile in un CMS senza framework e senza JavaScript lato client.

Con l'avvento del movimento Jamstack, i siti serviti staticamente sono tornati di moda. La maggior parte degli sviluppatori che forniscono HTML statico non creano HTML nativo. Per avere una solida esperienza di sviluppo, ci rivolgiamo spesso a strumenti chiamati Static Site Generators (SSG).

Questi strumenti sono dotati di molte funzionalità che rendono piacevole la creazione di siti statici su larga scala. Sia che forniscano semplici hook in API di terze parti come le origini dati di Gatsby o forniscano una configurazione approfondita come l'enorme raccolta di motori di modelli di 11ty, c'è qualcosa per tutti nella generazione di siti statici.

Poiché questi strumenti sono progettati per diversi casi d'uso, devono avere molte funzionalità. Queste caratteristiche li rendono potenti. Li rendono anche piuttosto complessi e opachi per i nuovi sviluppatori. In questo articolo, prenderemo l'SSG fino ai suoi componenti di base e creeremo il nostro.

Che cos'è un generatore di siti statici?

Al centro, un generatore di siti statici è un programma che esegue una serie di trasformazioni su un gruppo di file per convertirli in risorse statiche, come HTML. Che tipo di file può accettare, come li trasforma e quali tipi di file escono differenziano gli SSG.

Jekyll, uno dei primi e ancora popolari SSG, utilizza Ruby per elaborare modelli Liquid e file di contenuto Markdown in HTML.

Gatsby utilizza React e JSX per trasformare componenti e contenuti in HTML. Quindi fa un ulteriore passo avanti e crea un'applicazione a pagina singola che può essere servita in modo statico.

11ty esegue il rendering di HTML da motori di creazione di modelli come Liquid, Handlebars, Nunjucks o letterali di modelli JavaScript.

Ognuna di queste piattaforme ha funzionalità aggiuntive per semplificarci la vita. Forniscono temi, creano pipeline, architettura di plug-in e altro ancora. Con ogni funzionalità aggiuntiva arriva più complessità, più magia e più dipendenze. Sono caratteristiche importanti, certo, ma non tutti i progetti ne hanno bisogno.

Tra questi tre diversi SSG, possiamo vedere un altro tema comune: dati + modelli = sito finale. Questa sembra essere la funzionalità principale dei siti statici del generatore. Questa è la funzionalità su cui baseremo il nostro SSG.

Al centro, un generatore di siti statici è un programma che esegue una serie di trasformazioni su un gruppo di file per convertirli in risorse statiche, come HTML.

Il nostro nuovo stack tecnologico del generatore di siti statici: manubrio, Sanity.io e Netlify

Per creare il nostro SSG, avremo bisogno di un motore di modelli, un'origine dati e un host in grado di eseguire il nostro SSG e costruire il nostro sito. Molti generatori utilizzano Markdown come fonte di dati, ma cosa accadrebbe se facessimo un ulteriore passo avanti e collegassimo nativamente il nostro SSG a un CMS?

  • Fonte dati: Sanity.io
  • Recupero dati e modelli: Nodo e Manubri
  • Host e distribuzione: Netlify.

Prerequisiti

  • NodeJS installato
  • Account Sanity.io
  • Conoscenza di Git
  • Conoscenza di base della riga di comando
  • Conoscenza di base della distribuzione a servizi come Netlify.

Nota : per seguire, puoi trovare il codice in questo repository su GitHub.

Altro dopo il salto! Continua a leggere sotto ↓

Configurare la nostra struttura del documento in HTML

Per iniziare la nostra struttura del documento, scriveremo HTML semplice. Non c'è bisogno di complicare le cose ancora.

Nella struttura del nostro progetto, dobbiamo creare un luogo in cui risiedano i nostri file sorgente. In questo caso, creeremo una directory src e inseriremo il nostro index.html all'interno.

In index.html , delineeremo il contenuto che desideriamo. Questa sarà una pagina relativamente semplice.

 <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Title of the page!</title> </head> <body> <h1>The personal homepage of Bryan Robinson</h1> <p>Some pagraph and rich text content next</p> <h2>Bryan is on the internet</h2> <ul> <li><a href="linkURL">List of links</a></li> </ul> </body> </html>

Manteniamo questo semplice. Inizieremo con un h1 per la nostra pagina. Lo seguiremo con alcuni paragrafi di informazioni biografiche e ancoreremo la pagina con un elenco di collegamenti per vedere di più.

Converti il ​​nostro HTML in un modello che accetta i dati

Dopo aver ottenuto la nostra struttura di base, dobbiamo impostare un processo per combinarlo con una certa quantità di dati. Per fare ciò, utilizzeremo il motore di modelli Manubri.

Al centro, Handlebars prende una stringa simile a HTML, inserisce i dati tramite le regole definite nel documento e quindi genera una stringa HTML compilata.

Per utilizzare Handlebars, dovremo inizializzare un package.json e installare il pacchetto.

Esegui npm init -y per creare la struttura di un file package.json con del contenuto predefinito. Una volta che abbiamo questo, possiamo installare Manubri.

 npm install handlebars

Il nostro script di compilazione sarà uno script Node. Questo è lo script che useremo localmente per costruire, ma anche quello che il nostro fornitore di distribuzione e host useranno per costruire il nostro HTML per il sito live.

Per avviare il nostro script, creeremo un file index.js e avremo bisogno di due pacchetti nella parte superiore. Il primo è Handlebars e il secondo è un modulo predefinito in Node per accedere al file system corrente.

 const fs = require('fs'); const Handlebars = require('handlebars');

Useremo il modulo fs per accedere al nostro file sorgente, così come per scrivere su un file di distribuzione. Per iniziare la nostra build, creeremo una funzione main per il nostro file da eseguire quando viene chiamato e una funzione buildHTML per combinare i nostri dati e markup.

 function buildHTML(filename, data) { const source = fs.readFileSync(filename,'utf8').toString(); const template = Handlebars.compile(source); const output = template(data); return output } async function main(src, dist) { const html = buildHTML(src, { "variableData": "This is variable data"}); fs.writeFile(destination, html, function (err) { if (err) return console.log(err); console.log('index.html created'); }); } main('./src/index.html', './dist/index.html');

La funzione main() accetta due argomenti: il percorso del nostro modello HTML e il percorso in cui vogliamo che il nostro file costruito viva. Nella nostra funzione principale, eseguiamo buildHTML sul percorso di origine del modello con una certa quantità di dati.

La funzione build converte il documento di origine in una stringa e la passa a Handlebars. Handlebars compila un modello usando quella stringa. Quindi passiamo i nostri dati nel modello compilato e Handlebars esegue il rendering di una nuova stringa HTML sostituendo qualsiasi variabile o logica del modello con l'output dei dati.

Restituiamo quella stringa nella nostra funzione main e utilizziamo il metodo writeFile fornito dal modulo del file system di Node per scrivere il nuovo file nella posizione specificata se la directory esiste.

Per evitare errori, aggiungi una directory dist al tuo progetto con un file .gitkeep al suo interno. Non vogliamo eseguire il commit dei nostri file compilati (il nostro processo di compilazione lo farà), ma vorremo assicurarci di avere questa directory per il nostro script.

Prima di creare un CMS per gestire questa pagina, confermiamo che funziona. Per testare, modificheremo il nostro documento HTML per utilizzare i dati che vi abbiamo appena passato. Useremo la sintassi della variabile Handlebars per includere il contenuto di variableData .

 <h1>{{ variableData }}</h1>

Ora che il nostro HTML ha una variabile, siamo pronti per eseguire il nostro script del nodo.

 node index.js

Una volta terminato lo script, dovremmo avere un file in /dist/index.html . Se leggiamo open this in un browser, vedremo il nostro markup renderizzato, ma anche la nostra stringa "This is variable data".

Connessione a un CMS

Abbiamo un modo per mettere insieme i dati con un modello, ora abbiamo bisogno di una fonte per i nostri dati. Questo metodo funzionerà con qualsiasi origine dati che dispone di un'API. Per questa demo utilizzeremo Sanity.io.

Sanity è un'origine dati API-first che tratta i contenuti come dati strutturati. Hanno un sistema di gestione dei contenuti open source per rendere più conveniente la gestione e l'aggiunta di dati sia per gli editori che per gli sviluppatori. Il CMS è ciò che viene spesso definito CMS "Headless". Invece di un sistema di gestione tradizionale in cui i tuoi dati sono strettamente collegati alla tua presentazione, un CMS headless crea un livello di dati che può essere utilizzato da qualsiasi frontend o servizio (e possibilmente molti contemporaneamente).

Sanity è un servizio a pagamento, ma hanno un piano "Standard" che è gratuito e ha tutte le funzionalità di cui abbiamo bisogno per un sito come questo.

Impostare la sanità mentale

Il modo più rapido per iniziare a lavorare con un nuovo progetto Sanity è utilizzare Sanity CLI. Inizieremo installandolo a livello globale.

 npm install -g @sanity/cli

La CLI ci dà accesso a un gruppo di helper per la gestione, la distribuzione e la creazione. Per iniziare, eseguiremo sanity init . Questo ci guiderà attraverso un questionario per aiutare a avviare il nostro Studio (quello che Sanity chiama il loro CMS open source).

 Select a Project to Use: Create new project HTML CMS Use the default dataset configuration? Y // this creates a "Production" dataset Project output path: studio // or whatever directory you'd like this to live in Select project template Clean project with no predefined schemas

Questo passaggio creerà un nuovo progetto e un nuovo set di dati nel tuo account Sanity, creerà una versione locale di Studio e legherà insieme i dati e il CMS per te. Per impostazione predefinita, la directory di studio verrà creata nella radice del nostro progetto. In progetti su larga scala, potresti voler configurarlo come un repository separato. Per questo progetto, va bene tenerlo legato.

Per eseguire il nostro Studio in locale, cambieremo la directory nella directory di studio ed eseguiremo sanity start . Questo eseguirà Studio su localhost:3333 . Quando accedi, ti verrà presentata una schermata che ti informa che hai "Schema vuoto". Con questo, è il momento di aggiungere il nostro schema, che è il modo in cui i nostri dati saranno strutturati e modificati.

Creazione di uno schema di sanità mentale

Il modo in cui crei documenti e campi all'interno di Sanity Studio consiste nel creare schemi all'interno del file schemas/schema.js .

Per il nostro sito creeremo un tipo di schema chiamato "Informazioni sui dettagli". Il nostro schema fluirà dal nostro HTML. In generale, potremmo trasformare la maggior parte della nostra pagina web in un unico campo rich-text, ma è una buona pratica strutturare i nostri contenuti in modo disaccoppiato. Ciò fornisce una maggiore flessibilità nel modo in cui potremmo voler utilizzare questi dati in futuro.

Per la nostra pagina web, vogliamo un insieme di dati che includa quanto segue:

  • Titolo
  • Nome e cognome
  • Biografia (con editing rich text)
  • Un elenco di siti Web con un nome e un URL.

Per definire questo nel nostro schema, creiamo un oggetto per il nostro documento e definiamo i suoi campi. Un elenco annotato dei nostri contenuti con il relativo type di campo:

  • Titolo — stringa
  • Nome completo: stringa
  • Biografia: serie di "blocchi"
  • Elenco siti Web: matrice di oggetti con campi nome e stringa URL.
 types: schemaTypes.concat([ /* Your types here! */ { title: "About Details", name: "about", type: "document", fields: [ { name: 'title', type: 'string' }, { name: 'fullName', title: 'Full Name', type: 'string' }, { name: 'bio', title: 'Biography', name: 'content', type: 'array', of: [ { type: 'block' } ] }, { name: 'externalLinks', title: 'Social media and external links', type: 'array', of: [ { type: 'object', fields: [ { name: 'text', title: 'Link text', type: 'string' }, { name: 'href', title: 'Link url', type: 'string' } ] } ] } ] } ])

Aggiungi questo ai tuoi tipi di schema, salva e il tuo Studio si ricompilerà e ti presenterà i tuoi primi documenti. Da qui, aggiungeremo i nostri contenuti nel CMS creando un nuovo documento e compilando le informazioni.

Strutturare i tuoi contenuti in modo riutilizzabile

A questo punto, ti starai chiedendo perché abbiamo un "nome completo" e un "titolo". Questo perché vogliamo che i nostri contenuti abbiano il potenziale per essere multiuso. Includendo un campo del nome invece di includere il nome solo nel titolo, diamo a quei dati un uso maggiore. Possiamo quindi utilizzare le informazioni in questo CMS per alimentare anche una pagina di curriculum o PDF. Il campo della biografia potrebbe essere utilizzato in modo programmatico in altri sistemi o siti Web. Questo ci consente di avere un'unica fonte di verità per gran parte di questo contenuto invece di essere dettato dal caso d'uso diretto di questo particolare sito.

Trascinare i nostri dati nel nostro progetto

Ora che abbiamo reso disponibili i nostri dati tramite un'API, inseriamoli nel nostro progetto.

Installa e configura il client JavaScript Sanity

Per prima cosa, abbiamo bisogno dell'accesso ai dati in Node. Possiamo usare il client JavaScript Sanity per creare quella connessione.

 npm install @sanity/client

Questo recupererà e installerà l'SDK JavaScript. Da qui, dobbiamo configurarlo per recuperare i dati dal progetto che abbiamo impostato in precedenza. Per farlo, imposteremo uno script di utilità in /utils/SanityClient.js . Forniamo all'SDK il nostro ID progetto e il nome del set di dati e siamo pronti per usarlo nel nostro script principale.

 const sanityClient = require('@sanity/client'); const client = sanityClient({ projectId: '4fs6x5jg', dataset: 'production', useCdn: true }) module.exports = client;

Recupero dei nostri dati con GROQ

Nel nostro file index.js , creeremo una nuova funzione per recuperare i nostri dati. Per fare ciò, utilizzeremo il linguaggio di query nativo di Sanity, il GROQ open source.

Costruiremo la query in una variabile e quindi utilizzeremo il client che abbiamo configurato per recuperare i dati in base alla query. In questo caso, costruiamo un oggetto con una proprietà chiamata about . In questo oggetto, vogliamo restituire i dati per il nostro documento specifico. Per fare ciò, interroghiamo in base al documento _id che viene generato automaticamente quando creiamo il nostro documento.

Per trovare l' _id del documento, accediamo al documento in Studio e lo copiamo dall'URL o ci spostiamo in modalità "Ispeziona" per visualizzare tutti i dati sul documento. Per accedere a Inspect, fai clic sul menu "kabob" in alto a destra o usa la scorciatoia Ctrl + Alt + I . Questa visualizzazione elencherà tutti i dati su questo documento, incluso il nostro _id . Sanity restituirà un array di oggetti documento, quindi per semplicità, restituiremo la 0th voce.

Passiamo quindi la query al metodo di fetch del nostro client Sanity e restituirà un oggetto JSON di tutti i dati nel nostro documento. In questa demo, restituire tutti i dati non è un grosso problema. Per implementazioni più grandi, GROQ consente una "proiezione" opzionale per restituire solo i campi espliciti desiderati.

 const client = require('./utils/SanityClient') // at the top of the file // ... async function getSanityData() { const query = `{ "about": *[_id == 'YOUR-ID-HERE'][0] }` let data = await client.fetch(query); }

Conversione del campo Rich Text in HTML

Prima di poter restituire i dati, è necessario eseguire una trasformazione nel nostro campo RTF. Mentre molti CMS utilizzano editor di testo RTF che restituiscono direttamente HTML, Sanity utilizza una specifica open source chiamata Portable Text. Portable Text restituisce una matrice di oggetti (pensa al rich text come a un elenco di paragrafi e altri blocchi multimediali) con tutti i dati sullo stile del rich text e le proprietà come collegamenti, note a piè di pagina e altre annotazioni. Ciò consente di spostare e utilizzare il testo in sistemi che non supportano HTML, come assistenti vocali e app native.

Per il nostro caso d'uso, significa che dobbiamo trasformare l'oggetto in HTML. Esistono moduli NPM che possono essere utilizzati per convertire il testo portatile in vari usi. Nel nostro caso useremo un pacchetto chiamato block-content-to-html.

 npm install @sanity/block-content-to-html

Questo pacchetto renderà tutto il markup predefinito dall'editor di testo RTF. Ogni tipo di stile può essere ignorato per conformarsi a qualsiasi markup necessario per il tuo caso d'uso. In questo caso, lasceremo che il pacchetto faccia il lavoro per noi.

 const blocksToHtml = require('@sanity/block-content-to-html'); // Added to the top async function getSanityData() { const query = `{ "about": *[_type == 'about'][0] }` let data = await client.fetch(query); data.about.content = blocksToHtml({ blocks: data.about.content }) return await data }

Utilizzo del contenuto di Sanity.io nel manubrio

Ora che i dati sono in una forma che possiamo usarli, lo passeremo alla nostra funzione buildHTML come argomento dati.

 async function main(src, dist) { const data = await getSanityData(); const html = buildHTML(src, data) fs.writeFile(dist, html, function (err) { if (err) return console.log(err); console.log('index.html created'); }); }

Ora possiamo modificare il nostro HTML per utilizzare i nuovi dati. Useremo più chiamate variabili nel nostro modello per estrarre la maggior parte dei nostri dati.

Per eseguire il rendering della nostra variabile di content RTF, dovremo aggiungere un ulteriore livello di parentesi graffe alla nostra variabile. Questo dirà a Handlebars di eseguire il rendering dell'HTML invece di visualizzare l'HTML come una stringa.

Per il nostro array externalLinks , dovremo utilizzare la funzionalità di looping integrata di Handlebars per visualizzare tutti i collegamenti che abbiamo aggiunto al nostro Studio.

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ about.title }}</title> </head> <body> <h1>The personal homepage of {{ about.fullName }}</h1> {{{ about.content }}} <h2>Bryan is on the internet</h2> <ul> {{#each about.externalLinks }} <li><a href="{{ this.href }}">{{ this.text }}</a></li> {{/each}} </ul> </body> </html>

Configurazione della distribuzione

Portiamo questo dal vivo. Abbiamo bisogno di due componenti per farlo funzionare. Innanzitutto, vogliamo un host statico che crei i nostri file per noi. Successivamente, dobbiamo attivare una nuova build del nostro sito quando il contenuto viene modificato nel nostro CMS.

Distribuzione su Netlify

Per l'hosting, utilizzeremo Netlify. Netlify è un host del sito statico. Serve risorse statiche, ma ha funzionalità aggiuntive che faranno funzionare il nostro sito senza intoppi. Hanno un'infrastruttura di distribuzione integrata in grado di eseguire il nostro script del nodo, webhook per attivare build e una CDN distribuita a livello globale per assicurarsi che la nostra pagina HTML venga servita rapidamente.

Netlify può guardare il nostro repository su GitHub e creare una build basata su un comando che possiamo aggiungere nella loro dashboard.

Innanzitutto, dovremo inviare questo codice a GitHub. Quindi, nella dashboard di Netlify, dobbiamo connettere il nuovo repository a un nuovo sito in Netlify.

Una volta collegato, dobbiamo dire a Netlify come costruire il nostro progetto. Nella dashboard, andremo su Impostazioni> Crea e distribuisci> Impostazioni build. In quest'area, dobbiamo cambiare il nostro "comando Build" in "node index.js" e la nostra "directory Pubblica" in "./dist".

Quando Netlify costruisce il nostro sito, eseguirà il nostro comando e quindi controllerà la cartella che elenchiamo per il contenuto e pubblicherà il contenuto all'interno.

Configurazione di un webhook

Dobbiamo anche dire a Netlify di pubblicare una nuova versione quando qualcuno aggiorna il contenuto. Per fare ciò, imposteremo un Webhook per notificare a Netlify che abbiamo bisogno di ricostruire il sito. Un Webhook è un URL a cui è possibile accedere a livello di codice da un servizio diverso (come Sanity) per creare un'azione nel servizio di origine (in questo caso Netlify).

Possiamo impostare uno specifico "Build hook" nella nostra dashboard Netlify in Impostazioni > Build & Deploy > Build hook. Aggiungi un gancio, assegnagli un nome e salva. Ciò fornirà un URL che può essere utilizzato per attivare in remoto una build in Netlify.

Successivamente, dobbiamo dire a Sanity di effettuare una richiesta a questo URL quando pubblichi le modifiche.

Possiamo usare Sanity CLI per raggiungere questo obiettivo. All'interno della nostra directory /studio , possiamo eseguire sanity hook create per connetterci. Il comando chiederà un nome, un set di dati e un URL. Il nome può essere quello che desideri, il set di dati dovrebbe essere di production per il nostro prodotto e l'URL dovrebbe essere l'URL fornito da Netlify.

Ora, ogni volta che pubblichiamo contenuti in Studio, il nostro sito Web verrà aggiornato automaticamente. Nessun quadro necessario.

  • Il codice può essere trovato in questo repository GitHub →

Prossimi passi

Questo è un piccolo esempio di cosa puoi fare quando crei i tuoi utensili. Mentre più SSG con funzionalità più complete possono essere ciò di cui hai bisogno per la maggior parte dei progetti, la creazione del tuo mini-SSG può aiutarti a capire di più su ciò che sta accadendo nel tuo generatore di scelta.

  • Questo sito pubblica solo una pagina, ma con un piccolo extra nel nostro script di build, potremmo far pubblicare più pagine. Potrebbe persino pubblicare un post sul blog.
  • L'"esperienza dello sviluppatore" è un po' carente nel repository. Potremmo eseguire il nostro script Node su qualsiasi salvataggio di file implementando un pacchetto come Nodemon o aggiungendo "ricaricamento a caldo" con qualcosa come BrowserSync.
  • I dati che risiedono in Sanity possono alimentare più siti e servizi. Potresti creare un sito di curriculum che lo utilizzi e pubblichi un PDF anziché una pagina web.
  • Potresti aggiungere CSS e farlo sembrare un sito reale.