Das Frontend: Verwenden von Gatsby.js und Node.js für statische Site-Updates

Veröffentlicht: 2022-03-11

Fü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:

Ein Standard-Front-End-Projektstamm mit einem leeren öffentlichen Ordner und einem src-Ordner für Dateien wie „package.json“. Unter dem Ordner „src“ befinden sich ein Unterordner „styles“ für „global.css“ und ein Unterordner „templates“ für „all-repositories.js“ und „repository.js“.

Wozu dienen diese Dateien? Mal sehen:

  • env.development und env.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 unsere createPage -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:

Die Startseite unserer App mit Repository-Listen, die grundlegende Informationen für ein Beispiel von GitHub-Repositorys enthält

Und nachdem Sie auf eines der Repositories geklickt haben, sollten Sie so etwas sehen:

Eine Beispiel-Repository-Detailseite mit weiteren Informationen zum facebook/react GitHub-Repository

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:

Die richtigen Einstellungen für die Build-Optionen von Netlify: Master bereitstellen, „gatsby build“ als Build-Befehl verwenden und im Verzeichnis „public/“ veröffentlichen.

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“.

Wo finde ich Build-Hooks in Netlify?

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":

Der Abschnitt „Funktionen“ von AWS Lambda

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.

AWS Lambdas „Create function“-Seite, ausgefüllt bei create triggerMyBackendAtUTCMidnight mit einer Node.js-Laufzeit und einer neuen Rolle mit grundlegenden Lambda-Berechtigungen

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 Handler-Parameter mit „index.handler“ als Wert

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:

Festlegen der erforderlichen Umgebungsvariablen in AWS Lambda. Der angezeigte Wert ist https://sample-github-api-consumer-nod.herokuapp.com/repositories.

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:

Konfigurieren von CloudWatch-Ereignissen zum Hinzufügen einer Triggerregel

Unser CloudWatch-Triggerregeltyp ist ein „Zeitplanausdruck“ und unser Cron-Ausdruck ist gemäß dem akzeptierten Format cron(50 23 * * ? *) .

Die AWS CloudWatch-Seite „Trigger konfigurieren“ ist so eingestellt, dass eine neue Regel namens cronDailyUpdate mit dem oben angegebenen Ausdruck und aktiviertem Trigger erstellt wird

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!

Toptal ist ein fortgeschrittener AWS-Beratungspartner.