Das Frontend: Verwenden von Gatsby.js und Node.js für statische Site-Updates
Veröffentlicht: 2022-03-11Für einige Projektanforderungen ist die statische Seitengenerierung nicht nur ausreichend , sondern auch am effizientesten in Bezug auf Geschwindigkeit und Skalierbarkeit.
In der ersten Hälfte dieser Serie haben wir Node.js, Express, MongoDB, Cron und Heroku kombiniert, um ein CI-fähiges Backend bereitzustellen, das die API von GitHub gemäß einem täglichen Zeitplan nutzt. Jetzt sind wir bereit, Gatsby zu der Mischung hinzuzufügen, um unser Projekt zur Generierung statischer Seiten abzuschließen.
Entwicklung des Frontends: Machen Sie es zu einer Gatsby-Website
Da Gatsby-Websites auf React basieren, ist es hilfreich, wenn Sie bereits mit dem Erstellen einer Website mit React vertraut sind.
Beim Styling habe ich Bootstrap, Reactstrap und React-Markdown bevorzugt. Sie wissen vielleicht, dass Versionshinweise in GitHub im Markdown-Format gespeichert sind, daher benötigen wir einen Konverter.
Statische Website-Projektstruktur
Unsere Datei-/Ordnerstruktur sieht wie folgt aus:
Wozu dienen diese Dateien? Mal sehen:
-
env.development
undenv.production
sind Konfigurationsdateien für Umgebungsvariablen. - Für unsere Homepage wird das Template
all-repositories.js
verwendet, das eine Liste von Repositories enthält. - Die Vorlage
repository.js
wird verwendet, um Details für ein bestimmtes Repository anzuzeigen. -
gatsby-node.js
wir unseren Back-End-Endpunkt und führen unserecreatePage
-Methoden aus. -
package.json
enthält wie immer Abhängigkeiten und Projekteigenschaften. -
global.css
ist unsere Haupt-Stylesheet-Datei.
Gatsby-Website-Implementierung
Führen Sie wie bei unserem Backend npm install
(oder yarn
, wenn Sie Yarn installiert haben) aus, nachdem Sie die erforderlichen Abhängigkeiten zur package.json
des Frontends hinzugefügt haben:
{ // ... "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" } // ... }
Die Dateien env.development
und env.production
haben nur die Back-End-URL für ihre entsprechenden Umgebungen. Ersteres hat:
API_URL=http://localhost:3000
…während die Produktion:
API_URL=https://[YOUR_UNIQUE_APP_NAME].herokuapp.com
gatsby-node.js
wird nur einmal ausgeführt, während Sie Ihren Code erstellen. Wir müssen hier also alle notwendigen Informationen von unserem Backend sammeln. Anschließend wird die Antwort mit unseren Vorlagen verwendet, um die entsprechenden statischen Seiten zu generieren.
In unserem Fall benötigt all-repositories.js
alle Repositories und repository.js
benötigt das entsprechende Repository für jede Iteration. Schließlich können wir Seitenpfade dynamisch generieren, indem wir den Repository- owner
und die name
als Teil des path
übergeben:
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 } }); }); };
Wenn wir für all-repositories.js
und repository.js
das Styling weglassen, sammeln wir einfach Daten aus pageContext
und verwenden sie, wenn wir Parameter in React verwenden.
In all-repositories.js
verwenden wir das repositories
-Feld von pageContext
wie folgt:
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> // ... );
Wie für repository.js
verwenden wir stattdessen das repository
-Feld von 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> );
Stellen Sie jetzt sicher, dass Ihr Backend betriebsbereit ist. Sie werden sich erinnern, dass wir für dieses Projekt http://localhost:3000 eingestellt haben.
Führen Sie als Nächstes gatsby develop
im Stammverzeichnis Ihres Front-End-Projekts aus und öffnen Sie http://localhost:8000.
Wenn Sie einige Repositories (Besitzer/Name) zu Ihrem Backend hinzugefügt und die Update-via-GitHub-API-Funktion mindestens einmal ausgeführt haben, sollten Sie so etwas sehen:
Und nachdem Sie auf eines der Repositories geklickt haben, sollten Sie so etwas sehen:
Nach unseren obigen Änderungen ist unsere Front-End-Implementierung abgeschlossen.
Toll! Jetzt müssen wir nur noch bereitstellen.
Bereitstellen des Frontends
Wir müssen in diesem Teil keine Änderungen an unserer Frontend-Anwendung vornehmen. Wir stellen es einfach auf Netlify bereit – Sie benötigen dort ein Konto.
Aber zuerst müssen wir unseren Code auf GitHub, GitLab oder Bitbucket bereitstellen. Wie beim Backend habe ich meinen Code auf GitHub bereitgestellt.
Melden Sie sich dann bei Netlify an und klicken Sie in Ihrem Dashboard auf die Schaltfläche „Neue Site von Git“. Befolgen Sie die Schritte auf dem Bildschirm, um Ihren Git-Anbieter auszuwählen und Ihr Repository zu finden.
Wenn Sie Ihren Code im letzten Schritt richtig strukturiert haben, setzt Netlify automatisch den Build-Befehl und veröffentlicht das Verzeichnis wie folgt korrekt:

Klicken Sie dann auf „Site bereitstellen“. Es wird Ihre Website auf einer zufällig generierten Netlify-Subdomain bereitstellen, aber Sie können es jederzeit ändern – ich habe meine Bereitstellung auf https://sample-create-page-api-gatsby.netlify.com geändert, wo Sie eine Live-Demo finden können der fertigen App.
So weit, ist es gut. Da es sich jedoch um eine statische Seitenanwendung handelt, müssen wir sie täglich neu erstellen, um sie auf dem neuesten Stand zu halten.
Tägliches Update mit einem Build-Hook
Build-Hooks in Netlify funktionieren als Build-Trigger, sodass Sie sie nach Abschluss des Cron-Jobs von Ihrem Backend aus auslösen können. Erstellen Sie dazu zunächst einen Build-Hook in Netlify.
Unter dem Abschnitt „Build & Deployment → Continuous Deployment“ finden Sie „Build Hooks“. Klicken Sie auf „Build-Hook hinzufügen“.
Geben Sie ihm einen Namen und speichern Sie ihn. (Ich habe meins build-from-backend
genannt.) Kopieren Sie dann den Link, den es generiert.
Lassen Sie uns nun unser Back-End-Projekt öffnen und diese wenigen Zeilen zur Datei cron.controller.js
. Wir senden einfach eine POST
-Anforderung an die Build-Hook-URL von 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'); }); } }
Dann aktualisieren Sie unsere updateDaily
Funktion:
function updateDaily() { RepositoryController.updateRepositories().then(() => { updateGatsby(); }); }
Aktualisieren Sie abschließend unsere Datei env.config.js
, um die Eigenschaft netlifyEndpoint
, die aus Umgebungsvariablen erfasst werden soll:
"netlifyEndpoint": process.env.NETLIFY_BUILD_HOOK || ""
Jetzt müssen Sie die Umgebungsvariable NETLIFY_BUILD_HOOK
setzen, die Sie vorhin von Netlify kopiert haben. In Heroku können Sie Umgebungsvariablen im Abschnitt „Einstellungen“ Ihrer Anwendung festlegen.
Nachdem Sie Ihr Commit übertragen haben, sendet die Back-End-Anwendung eine Build-Anfrage an Netlify und Ihre Seiten werden am Ende Ihres Cron-Jobs täglich aktualisiert. So sollte das Repo nach dem Hinzufügen der Build-Hook-Funktionalität zusammen mit den endgültigen Versionen des Back-End-Repos und des Front-End-Repos aussehen.
Als Abschluss des Projekts zeigen wir, wie Sie eine von AWS CloudWatch ausgelöste AWS Lambda-Funktion verwenden, die Ihr Backend rechtzeitig für jedes tägliche Update aufweckt.
Einfache Anforderung von AWS Lambda und AWS CloudWatch
AWS Lambda ist eine Serverless-Computing-Plattform. Wir brauchen hier nur die Grundlagen dieser Plattform für unsere Zwecke. Sie benötigen ein AWS-Konto.
Melden Sie sich zunächst mit Ihrem Konto bei AWS an und suchen Sie die Lambda Management Console. Für us-east-2
ist es beispielsweise unter https://us-east-2.console.aws.amazon.com/lambda/home zu finden.
Wenn es noch nicht ausgewählt ist, gehen Sie zum Abschnitt "Funktionen":
Hier erstellen wir unsere Funktion von Grund auf neu, indem wir auf „Funktion erstellen“ klicken. Geben wir ihm einen erklärenden Namen. Wir werden Node.js als Laufzeitsprache verwenden. Klicken Sie dann auf die nächste „Funktion erstellen“, um sie abzuschließen.
Es leitet uns zur Seite der neuen Funktion weiter, wo wir unseren Code in index.js
schreiben können.
Lassen Sie uns unsere erste Lambda-Funktion implementieren. Da wir keine Abhängigkeiten von Drittanbietern haben, müssen wir die Kernmodule von Node.js verwenden. (Wenn Sie stattdessen Abhängigkeiten von Drittanbietern aktivieren möchten, folgen Sie bitte dieser Anleitung von AWS.)
Stellen Sie sicher, dass der exportierte Methodenname (in diesem Fall handler
) mit dem „Handler“-Parameter auf der Seite übereinstimmt:
Der Rest ist eine einfache GET
Anfrage an Ihr Backend:
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); }); }); };
Stellen Sie sicher, dass Sie die Umgebungsvariable HEROKU_APP_URL
auf der Seite festgelegt haben, und speichern Sie Ihre Konfiguration:
Ein letzter Schritt ist das Hinzufügen einer CloudWatch-Triggerregel, um diese Funktion zehn Minuten vor jedem täglichen Update auszuführen – in dieser Artikelserie funktioniert das bis 23:50 Uhr:
Unser CloudWatch-Triggerregeltyp ist ein „Zeitplanausdruck“ und unser Cron-Ausdruck ist gemäß dem akzeptierten Format cron(50 23 * * ? *)
.
Wir haben jetzt unsere AWS Lambda-Funktion so konfiguriert, dass sie von unserer CloudWatch-Regel ausgelöst wird.
Jetzt für unsere statischen Webseiten: Gatsby/React und Netlify
Mit einer Prise AWS Lambda/CloudWatch, die unserem Node.js/MongoDB/Heroku-Backend hinzugefügt wurde, und Gatsby und Netlify, die unser Frontend generieren und hosten, ist unsere App komplett!
Ich habe vorhin einen Live-Demo-Link geteilt, aber Sie können sich gerne auch eine verbesserte Version meines Prototyps ansehen – sie enthält einige zusätzliche Änderungen, von denen ich weiß, dass Sie sie lieben werden.
Sie können dies als Blaupause für ähnliche Projekte verwenden – ich hoffe, diese Artikel helfen Ihnen dabei, Ihre Apps schneller und kostengünstiger zu prototypisieren. Danke fürs Lesen!