Il front-end: utilizzo di Gatsby.js e Node.js per gli aggiornamenti statici del sito
Pubblicato: 2022-03-11Per 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:
A cosa servono questi file? Vediamo:
-
env.development
eenv.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 metodicreatePage
. -
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:
E dopo aver fatto clic su uno dei repository, dovresti vedere qualcosa del genere:
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:

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".
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":
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.
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 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:
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:
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 * * ? *)
.
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!