Il front-end: utilizzo di Gatsby.js e Node.js per gli aggiornamenti statici del sito

Pubblicato: 2022-03-11

Per alcuni requisiti di progetto, la generazione di pagine statiche non è solo sufficiente , è anche la più efficiente in termini di velocità e scalabilità.

Nella prima metà di questa serie, abbiamo combinato Node.js, Express, MongoDB, cron e Heroku per fornire un back-end pronto per la CI che utilizza l'API di GitHub secondo una pianificazione giornaliera. Ora siamo pronti per aggiungere Gatsby al mix per completare il nostro progetto di generazione di pagine statiche.

Sviluppare il front-end: trasformalo in un sito web di Gatsby

Poiché i siti Web di Gatsby sono basati su React, è utile se hai già familiarità con come creare un sito Web con React.

Per lo styling, ho preferito Bootstrap, reactstrap e react-markdown. Potresti sapere che le note di rilascio in GitHub sono archiviate in formato Markdown, da qui la nostra necessità di un convertitore.

Struttura statica del progetto del sito web

La nostra struttura di file/cartelle sarà la seguente:

Una radice di progetto front-end standard con una cartella pubblica vuota e una cartella src per file come package.json. Sotto la cartella src ci sono una sottocartella di stili per global.css e una sottocartella di modelli per all-repositories.js e repository.js.

A cosa servono questi file? Vediamo:

  • env.development e env.production sono file di configurazione delle variabili di ambiente.
  • Il modello all-repositories.js verrà utilizzato per la nostra home page, contenente un elenco di repository.
  • Il modello repository.js verrà utilizzato per mostrare i dettagli per un determinato repository.
  • gatsby-node.js è dove consumiamo il nostro endpoint back-end ed eseguiamo i nostri metodi createPage .
  • package.json , come sempre, contiene le dipendenze e le proprietà del progetto.
  • global.css è il nostro file di foglio di stile principale.

Implementazione del sito web di Gatsby

Come con il nostro back-end, esegui npm install (o yarn , se hai installato Yarn) dopo aver aggiunto le dipendenze richieste al package.json del front-end:

 { // ... "dependencies": { "axios": "^0.18.0", "bootstrap": "^4.3.1", "gatsby": "^2.0.0", "react": "^16.5.1", "react-dom": "^16.5.1", "react-markdown": "^4.0.6", "reactstrap": "^7.1.0" } // ... }

I file env.development ed env.production hanno solo l'URL di back-end per gli ambienti corrispondenti. Il primo ha:

 API_URL=http://localhost:3000

…mentre la produzione ha:

 API_URL=https://[YOUR_UNIQUE_APP_NAME].herokuapp.com

gatsby-node.js verrà eseguito solo una volta durante la creazione del codice. Quindi dobbiamo raccogliere tutte le informazioni necessarie dal nostro back-end qui. Quindi, la risposta verrà utilizzata con i nostri modelli per generare le pagine statiche appropriate.

Nel nostro caso, all-repositories.js bisogno di tutti i repository e repository.js bisogno del repository corrispondente per ogni iterazione. Infine possiamo generare i percorsi delle pagine in modo dinamico, passando il owner del repository e i parametri del name come parte del campo del path :

 const axios = require('axios'); require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` }); const getRepositoryData = async () => { console.log(process.env.API_URL); return axios.get(`${process.env.API_URL}/repositories`); }; exports.createPages = async ({ actions: { createPage } }) => { let repositories = await getRepositoryData(); repositories = repositories.data; // Create a page that lists all repositories. createPage({ path: `/`, component: require.resolve('./src/templates/all-repositories.js'), context: { repositories } }); // Create a page for each repository. repositories.forEach(repository => { createPage({ path: `/repository/${repository.owner}/${repository.name}`, component: require.resolve('./src/templates/repository.js'), context: { repository } }); }); };

Per all-repositories.js e repository.js , se omettiamo lo stile, stiamo semplicemente raccogliendo dati da pageContext e utilizzandoli mentre utilizziamo i parametri in React.

In all-repositories.js , useremo il campo dei repositories di pageContext in questo modo:

 export default ({pageContext: {repositories}}) => ( // ... <ListGroup> {/* Because the repositories parameter is a list, we are iterating over all items and using their fields */} {repositories.map(repository => (repository.tagName && <ListGroupItem className="repository-list-item"> // ... <Row> {`${repository.repositoryDescription}`} </Row> // ... </ListGroupItem> ))} </ListGroup> // ... );

Per quanto riguarda repository.js , utilizzeremo invece il campo repository di pageContext :

 export default ({pageContext: {repository}}) => ( <div className="layout"> {repository.tagName && <ListGroupItem className="repository-list-item"> // ... <h1 className="release-notes">{`Release notes`}</h1> <hr/> {/* This the place where we will use Markdown-formatted release notes */} <ReactMarkdown source={`${repository.releaseDescription}`}/> </ListGroupItem> } // ... </div> );

Ora assicurati che il tuo back-end sia attivo e funzionante. Ricorderai che per questo progetto l'abbiamo impostato come http://localhost:3000.

Quindi, esegui gatsby develop dalla radice del tuo progetto front-end e apri http://localhost:8000.

Se hai aggiunto alcuni repository (proprietario/nome) al back-end ed eseguito la funzione update-via-GitHub-API almeno una volta, dovresti vedere qualcosa del genere:

La home page dell'elenco dei repository della nostra app, che mostra le informazioni di base per un campione di repository GitHub

E dopo aver fatto clic su uno dei repository, dovresti vedere qualcosa del genere:

Una pagina dei dettagli del repository di esempio, che mostra ulteriori informazioni sul repository GitHub di facebook/react

Dopo le modifiche di cui sopra, la nostra implementazione front-end è terminata.

Grande! Ora non ci resta che schierare.

Distribuzione del front-end

In questa parte non è necessario apportare modifiche alla nostra applicazione front-end. Lo implementeremo semplicemente su Netlify: avrai bisogno di un account lì.

Ma prima, dobbiamo distribuire il nostro codice su GitHub, GitLab o Bitbucket. Come per il back-end, ho distribuito il mio codice su GitHub.

Quindi, accedi a Netlify e fai clic sul pulsante "Nuovo sito da Git" sulla dashboard. Segui i passaggi sullo schermo per selezionare il tuo provider Git e trovare il tuo repository.

Per il passaggio finale, se hai strutturato correttamente il tuo codice, Netlify imposterà automaticamente il comando build e pubblicherà la directory correttamente come segue:

Le impostazioni corrette per le opzioni di build di Netlify: Deploy master, usa "gatsby build" come comando di build e pubblica nella directory "public/".

Quindi fare clic su "Distribuisci sito". Distribuirà il tuo sito a un sottodominio Netlify generato casualmente, ma puoi cambiarlo in qualsiasi momento: ho cambiato la mia distribuzione in https://sample-create-page-api-gatsby.netlify.com, dove puoi trovare una demo dal vivo dell'app completata.

Fin qui tutto bene. Ma poiché è un'applicazione di pagina statica, dobbiamo ricostruirla quotidianamente per mantenerla aggiornata.

Aggiornamento giornaliero utilizzando un Build Hook

Gli hook di build in Netlify funzionano come trigger di build, quindi puoi attivarli dal tuo back-end al termine del lavoro cron. Per fare ciò, crea prima un build hook in Netlify.

Nella sezione "Crea e distribuisci → Distribuzione continua", puoi trovare "Crea hook". Fai clic su "Aggiungi gancio di costruzione".

Dove trovare build hook in Netlify

Dagli un nome e salvalo. (Ho chiamato il mio build-from-backend .) Quindi copia il collegamento che genera.

Ora apriamo il nostro progetto di back-end e aggiungiamo queste poche righe al file cron.controller.js . Stiamo semplicemente inviando una richiesta POST all'URL build-hook di Netlify.

 const Axios = require('axios'); const Config = require('../config/env.config'); const NETLIFY_BUILD_HOOK_URI = Config.netlifyEndpoint; function updateGatsby() { if (NETLIFY_BUILD_HOOK_URI) { console.log('Gatsby build request will be send'); Axios.post(NETLIFY_BUILD_HOOK_URI).then(() => { console.log('Gatsby build request was successful'); }); } }

Quindi aggiorna la nostra funzione updateDaily :

 function updateDaily() { RepositoryController.updateRepositories().then(() => { updateGatsby(); }); }

Infine, aggiorna il nostro file env.config.js per impostare la proprietà netlifyEndpoint da raccogliere dalle variabili di ambiente:

 "netlifyEndpoint": process.env.NETLIFY_BUILD_HOOK || ""

Ora, dovrai impostare la variabile d'ambiente NETLIFY_BUILD_HOOK che hai copiato da Netlify un momento fa. In Heroku, puoi impostare le variabili d'ambiente dalla sezione "impostazioni" della tua applicazione.

Dopo aver eseguito il push del tuo commit, l'applicazione back-end invierà una richiesta di build a Netlify e le tue pagine verranno aggiornate quotidianamente, al termine del tuo cron job. Ecco come dovrebbe apparire il repository dopo aver aggiunto la funzionalità di build hook, insieme alle versioni finali del repository back-end e del repository front-end.

Come tocco finale al progetto, mostreremo come utilizzare una funzione AWS Lambda attivata da AWS CloudWatch che risveglierà il tuo back-end in tempo per ogni aggiornamento giornaliero.

AWS Lambda e AWS CloudWatch Simple Request

AWS Lambda è una piattaforma di elaborazione serverless. Abbiamo solo bisogno delle basi di questa piattaforma per i nostri scopi qui. Avrai bisogno di un account AWS.

Innanzitutto, accedi ad AWS con il tuo account e trova la Lambda Management Console. Ad esempio, per us-east-2 , può essere trovato su https://us-east-2.console.aws.amazon.com/lambda/home.

Se non è già selezionato, vai alla sezione "Funzioni":

La sezione "Funzioni" di AWS Lambda

Qui creeremo la nostra funzione da zero facendo clic su "Crea funzione". Diamogli un nome esplicativo. Useremo Node.js come linguaggio di runtime. Quindi fare clic sulla successiva "Crea funzione" per finalizzarla.

Pagina "Crea funzione" di AWS Lambda, compilata in create triggerMyBackendAtUTCMidnight con un runtime Node.js e un nuovo ruolo con autorizzazioni Lambda di base

Ci reindirizzerà alla pagina della nuova funzione dove possiamo scrivere il nostro codice in index.js .

Implementiamo la nostra prima funzione lambda. Poiché non abbiamo dipendenze di terze parti, dobbiamo utilizzare i moduli principali di Node.js. (Se invece desideri abilitare le dipendenze di terze parti, segui questa guida di AWS.)

Assicurati che il nome del metodo esportato ( handler in questo caso) corrisponda al parametro "Handler" nella pagina:

Il parametro Handler con "index.handler" come valore

Il resto è una semplice richiesta GET al tuo back-end:

 const https = require('https'); exports.handler = async (event) => { return new Promise((resolve, reject) => { https.get(process.env.HEROKU_APP_URL, (resp) => { let data = ''; resp.on('data', (chunk) => { data += chunk; }); resp.on('end', () => { resolve(JSON.parse(data)); }); }).on("error", (err) => { reject("Error: " + err.message); }); }); };

Assicurati di impostare la variabile di ambiente HEROKU_APP_URL nella pagina e salva la configurazione:

Impostazione della variabile di ambiente richiesta in AWS Lambda. Il valore visualizzato è https://sample-github-api-consumer-nod.herokuapp.com/repositories.

Un ultimo passaggio consiste nell'aggiungere una regola di attivazione CloudWatch per eseguire questa funzione dieci minuti prima di ogni aggiornamento giornaliero, in questa serie di articoli, che funziona fino alle 23:50:

Configurazione di CloudWatch Events per aggiungere una regola di attivazione

Il nostro tipo di regola di trigger CloudWatch sarà una "Espressione di pianificazione" e, in base al formato accettato, la nostra espressione cron sarà cron(50 23 * * ? *) .

La pagina "Configura trigger" di AWS CloudWatch, impostata per creare una nuova regola denominata cronDailyUpdate con l'espressione indicata sopra e il trigger abilitato

Ora abbiamo configurato la nostra funzione AWS Lambda in modo che venga attivata dalla nostra regola CloudWatch.

Ora alimenta le nostre pagine Web statiche: Gatsby/React e Netlify

Con un pizzico di AWS Lambda/CloudWatch aggiunto al nostro back-end Node.js/MongoDB/Heroku e Gatsby e Netlify che generano e ospitano il nostro front-end, la nostra app è completa!

Ho condiviso un link demo dal vivo in precedenza, ma sentiti libero di dare un'occhiata anche a una versione migliorata del mio prototipo: ha alcune modifiche extra che so che ti piaceranno.

Puoi usarlo come modello per progetti simili: spero che questi articoli ti aiutino a creare prototipi delle tue app in un modo più veloce ed economico. Grazie per aver letto!

Toptal è un partner di consulenza AWS avanzato.