Front End: Utilizarea Gatsby.js și Node.js pentru actualizări statice ale site-urilor

Publicat: 2022-03-11

Pentru unele cerințe ale proiectului, generarea statică a paginilor nu este doar suficientă , ci este și cea mai eficientă în ceea ce privește viteza și scalabilitatea.

În prima jumătate a acestei serii, am combinat Node.js, Express, MongoDB, cron și Heroku pentru a oferi un back-end gata pentru CI care consumă API-ul GitHub conform unui program zilnic. Acum suntem gata să-l adăugăm pe Gatsby la amestec pentru a finaliza proiectul nostru de generare a paginilor statice.

Dezvoltarea front-end-ului: faceți-l un site web Gatsby

Deoarece site-urile web Gatsby se bazează pe React, este util dacă ești deja familiarizat cu cum să construiești un site web cu React.

Pentru stil, am preferat Bootstrap, reactstrap și react-markdown. Poate știți că notele de lansare în GitHub sunt stocate în format Markdown, de unde avem nevoie de un convertor.

Structura statică a proiectului site-ului web

Structura noastră de fișiere/folder va fi după cum urmează:

O rădăcină standard de proiect front-end cu un folder public gol și un folder src pentru fișiere precum package.json. Sub folderul src se află un subfolder de stiluri pentru global.css și un subdosar de șabloane pentru all-repositories.js și repository.js.

Pentru ce sunt aceste fișiere? Să vedem:

  • env.development și env.production sunt fișiere de configurare a variabilelor de mediu.
  • Șablonul all-repositories.js va fi folosit pentru pagina noastră de pornire, care conține o listă de depozite.
  • Șablonul repository.js va fi folosit pentru a afișa detalii pentru un anumit depozit.
  • gatsby-node.js este locul unde ne consumăm endpoint-ul back-end și rulăm metodele createPage .
  • package.json , ca întotdeauna, conține dependențe și proprietăți ale proiectului.
  • global.css este fișierul nostru principal de foaie de stil.

Implementarea site-ului Gatsby

Ca și în cazul back-end-ului nostru, rulați npm install (sau yarn , dacă aveți Yarn instalat) după ce adăugați dependențele necesare la pachetul package.json :

 { // ... "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" } // ... }

env.development și env.production au numai URL-ul back-end pentru mediile corespunzătoare. Primul are:

 API_URL=http://localhost:3000

…în timp ce producția are:

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

gatsby-node.js va fi rulat o singură dată în timp ce construiți codul. Așa că trebuie să adunăm toate informațiile necesare din partea noastră din spate aici. Apoi, răspunsul va fi folosit cu șabloanele noastre pentru a genera paginile statice corespunzătoare.

În cazul nostru, all-repositories.js are nevoie de toate depozitele, iar repository.js are nevoie de depozitul corespunzător pentru fiecare iterație. În cele din urmă, putem genera dinamic căile paginii, trecând owner depozitului și parametrii name ca parte a câmpului 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 } }); }); };

Pentru all-repositories.js și repository.js , dacă omitem stilul, pur și simplu colectăm date din pageContext și le folosim pe măsură ce folosim parametrii în React.

În all-repositories.js , vom folosi câmpul repositories din pageContext astfel:

 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> // ... );

În ceea ce privește repository.js , vom folosi în schimb câmpul de repository din 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> );

Acum, asigurați-vă că partea din spate este în funcțiune. Vă veți aminti că pentru acest proiect l-am setat ca http://localhost:3000.

Apoi, rulați gatsby develop de la rădăcina proiectului dumneavoastră front-end și deschideți http://localhost:8000.

Dacă ați adăugat câteva depozite (proprietar/nume) la back-end și ați rulat funcția update-via-GitHub-API cel puțin o dată, ar trebui să vedeți ceva de genul acesta:

Arhivele care listează pagina de pornire a aplicației noastre, afișând informații de bază pentru un eșantion de repoziții GitHub

Și după ce faceți clic pe unul dintre depozite, ar trebui să vedeți ceva de genul acesta:

Un exemplu de pagină cu detalii ale depozitului, care arată mai multe informații despre depozitul GitHub facebook/react

După modificările noastre de mai sus, implementarea noastră front-end este încheiată.

Grozav! Acum trebuie doar să ne desfășurăm.

Implementarea front-end-ului

Nu trebuie să facem nicio modificare în aplicația noastră front-end în această parte. Îl vom implementa pur și simplu în Netlify — veți avea nevoie de un cont acolo.

Dar mai întâi, trebuie să implementăm codul nostru în GitHub, GitLab sau Bitbucket. Ca și în cazul back-end-ului, mi-am implementat codul în GitHub.

Apoi, conectați-vă la Netlify și faceți clic pe butonul „Site nou din Git” de pe tabloul de bord. Urmați pașii de pe ecran pentru a vă selecta furnizorul Git și pentru a găsi depozitul.

Pentru ultimul pas, dacă ați structurat corect codul, Netlify va seta automat comanda de compilare și va publica directorul corect, după cum urmează:

Setările corecte pentru opțiunile de compilare ale Netlify: implementați master, utilizați „gatsby build” ca comandă de compilare și publicați în directorul „public/”.

Apoi faceți clic pe „Implementați site-ul”. Acesta vă va implementa site-ul într-un subdomeniu Netlify generat aleatoriu, dar îl puteți schimba oricând — mi-am schimbat implementarea la https://sample-create-page-api-gatsby.netlify.com, unde puteți găsi o demonstrație live a aplicației finalizate.

Până acum, bine. Dar pentru că este o aplicație de pagină statică, trebuie să o reconstruim zilnic pentru a o menține la zi.

Actualizare zilnică folosind un cârlig de construcție

Build hooks în Netlify funcționează ca declanșatori de compilare, astfel încât să le puteți declanșa din back-end după ce lucrarea cron se termină. Pentru a face asta, mai întâi creați un cârlig de compilare în Netlify.

În secțiunea „Construiți și implementați → Implementare continuă”, puteți găsi „Construiți cârlige”. Faceți clic pe „Adăugați cârlig de construcție”.

Unde găsiți cârlige de construcție în Netlify

Dă-i un nume și salvează-l. (Am sunat al meu build-from-backend .) Apoi copiați linkul pe care îl generează.

Acum să deschidem proiectul nostru back-end și să adăugăm aceste câteva linii în fișierul cron.controller.js . Pur și simplu trimitem o solicitare POST către adresa URL a hook-ului de compilare a 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'); }); } }

Apoi actualizați funcția noastră updateDaily :

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

În cele din urmă, actualizați fișierul nostru env.config.js pentru a seta proprietatea netlifyEndpoint să fie colectată din variabilele de mediu:

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

Acum, va trebui să setați variabila de mediu NETLIFY_BUILD_HOOK pe care ați copiat-o din Netlify acum un moment. În Heroku, puteți seta variabile de mediu din secțiunea „Setări” a aplicației dumneavoastră.

După ce v-ați împins commit-ul, aplicația back-end va trimite o solicitare de construire către Netlify, iar paginile dvs. vor fi actualizate zilnic, la sfârșitul jobului dvs. de cron. Iată cum ar trebui să arate repo-ul după adăugarea funcționalității de build hook, împreună cu versiunile finale ale repo-ului back-end și ale repo-ului front-end.

Ca finală a proiectului, vă vom arăta cum să utilizați o funcție AWS Lambda declanșată de AWS CloudWatch, care vă va trezi back end la timp pentru fiecare actualizare zilnică.

AWS Lambda și AWS CloudWatch Solicitare simplă

AWS Lambda este o platformă de calcul fără server. Avem nevoie doar de elementele de bază ale acestei platforme pentru scopurile noastre aici. Veți avea nevoie de un cont AWS.

Mai întâi, conectați-vă la AWS cu contul dvs. și găsiți Consola de management Lambda. De exemplu, pentru us-east-2 , poate fi găsit la https://us-east-2.console.aws.amazon.com/lambda/home.

Dacă nu este deja selectat, accesați secțiunea „Funcții”:

Secțiunea „Funcții” AWS Lambda

Aici, ne vom crea funcția de la zero făcând clic pe „Creați funcție”. Să-i dăm un nume explicativ. Vom folosi Node.js ca limbaj de rulare. Apoi faceți clic pe următoarea „Creare funcție” pentru a o finaliza.

Pagina „Creare funcție” a AWS Lambda, completată la create triggerMyBackendAtUTCMidnight cu un timp de rulare Node.js și un nou rol cu ​​permisiuni Lambda de bază

Ne va redirecționa către pagina noii funcții unde putem scrie codul nostru în index.js .

Să implementăm prima noastră funcție lambda. Deoarece nu avem dependențe de la terți, trebuie să folosim modulele de bază ale Node.js. (Dacă doriți să activați dependențele terțelor părți, vă rugăm să urmați acest ghid de la AWS.)

Asigurați-vă că numele metodei exportate ( handler în acest caz) se potrivește cu parametrul „Handler” din pagină:

Parametrul Handler cu „index.handler” ca valoare

Restul este o simplă solicitare GET către 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); }); }); };

Asigurați-vă că setați variabila de mediu HEROKU_APP_URL în pagină și salvați configurația:

Setarea variabilei de mediu necesare în AWS Lambda. Valoarea afișată este https://sample-github-api-consumer-nod.herokuapp.com/repositories.

Un ultim pas este adăugarea unei reguli de declanșare CloudWatch pentru a rula această funcție cu zece minute înainte de fiecare actualizare zilnică — în această serie de articole, care se realizează până la 23:50:

Configurarea evenimentelor CloudWatch pentru a adăuga o regulă de declanșare

Tipul nostru de regulă de declanșare CloudWatch va fi o „Expresie de planificare” și, conform formatului acceptat, expresia noastră cron va fi cron(50 23 * * ? *) .

Pagina AWS CloudWatch „Configurare declanșatoare”, setată să creeze o nouă regulă numită cronDailyUpdate cu expresia dată mai sus și declanșatorul activat

Acum am configurat funcția noastră AWS Lambda pentru a fi declanșată de regula noastră CloudWatch.

Acum alimentăm paginile noastre web statice: Gatsby/React și Netlify

Cu o picătură de AWS Lambda/CloudWatch adăugată la back-end-ul nostru Node.js/MongoDB/Heroku și Gatsby și Netlify generând și găzduind front-end-ul nostru, aplicația noastră este completă!

Am distribuit mai devreme un link demonstrativ live, dar nu ezitați să verificați și o versiune îmbunătățită a prototipului meu – are câteva modificări suplimentare pe care știu că o să vă placă.

Puteți utiliza acest lucru ca plan pentru proiecte similare — sper că aceste articole vă vor ajuta să vă prototipați aplicațiile într-un mod mai rapid și mai rentabil. Multumesc pentru lectura!

Toptal este un partener de consultanță AWS avansat.