Front End: Używanie Gatsby.js i Node.js do statycznych aktualizacji witryn

Opublikowany: 2022-03-11

W przypadku niektórych wymagań projektowych statyczne generowanie stron jest nie tylko wystarczające , ale jest również najbardziej wydajne pod względem szybkości i skalowalności.

W pierwszej połowie tej serii połączyliśmy Node.js, Express, MongoDB, cron i Heroku, aby dostarczyć gotowy do CI backend, który wykorzystuje API GitHub zgodnie z dziennym harmonogramem. Teraz jesteśmy gotowi, aby dodać Gatsby'ego do miksu, aby ukończyć nasz projekt generowania statycznej strony.

Tworzenie interfejsu: zrób z niego witrynę Gatsby

Ponieważ witryny Gatsby są oparte na React, przydatne jest, jeśli wiesz już, jak zbudować witrynę internetową za pomocą Reacta.

Do stylizacji preferowałem Bootstrap, Reactstrap i React-Markdown. Być może wiesz, że informacje o wydaniu w GitHub są przechowywane w formacie Markdown, dlatego potrzebujemy konwertera.

Statyczna struktura projektu strony internetowej

Nasza struktura plików/folderów będzie następująca:

Standardowy główny projekt frontonu z pustym folderem publicznym i folderem src dla plików takich jak package.json. Pod folderem src znajduje się podfolder style dla global.css oraz podfolder templates dla all-repositories.js i repository.js.

Do czego służą te pliki? Zobaczmy:

  • env.development i env.production to pliki konfiguracyjne zmiennych środowiskowych.
  • Szablon all-repositories.js zostanie użyty na naszej stronie głównej, zawierającej listę repozytoriów.
  • Szablon repository.js posłuży do pokazania szczegółów dla danego repozytorium.
  • gatsby-node.js to miejsce, w którym wykorzystujemy nasz punkt końcowy zaplecza i uruchamiamy nasze metody createPage .
  • package.json jak zawsze zawiera zależności i właściwości projektu.
  • global.css to nasz główny plik arkusza stylów.

Wdrożenie strony internetowej Gatsby

Podobnie jak w przypadku naszego zaplecza, uruchom npm install (lub yarn , jeśli masz zainstalowany Yarn) po dodaniu wymaganych zależności do package.json interfejsu użytkownika:

 { // ... "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 mają tylko adresy URL zaplecza dla odpowiednich środowisk. Ten pierwszy ma:

 API_URL=http://localhost:3000

…podczas gdy produkcja ma:

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

gatsby-node.js zostanie uruchomiony tylko raz podczas tworzenia kodu. Dlatego musimy zebrać tutaj wszystkie niezbędne informacje z naszego zaplecza. Następnie odpowiedź zostanie wykorzystana z naszymi szablonami do wygenerowania odpowiednich stron statycznych.

W naszym przypadku all-repositories.js potrzebuje wszystkich repozytoriów, a repository.js potrzebuje odpowiedniego repozytorium dla każdej iteracji. Na koniec możemy dynamicznie generować ścieżki do stron, przekazując owner repozytorium i parametry name jako część pola 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 } }); }); };

W przypadku all-repositories.js i repository.js , jeśli pominiemy stylowanie, po prostu zbieramy dane z pageContext i używamy ich tak, jak używamy parametrów w React.

W all-repositories.js użyjemy pola repositories pageContext w następujący sposób:

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

Jeśli chodzi o repository.js , zamiast tego użyjemy pola repository 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> );

Teraz upewnij się, że Twój backend jest gotowy do pracy. Przypomnij sobie, że dla tego projektu ustawiliśmy go jako http://localhost:3000.

Następnie uruchom program gatsby develop z katalogu głównego projektu front-end i otwórz http://localhost:8000.

Jeśli dodałeś kilka repozytoriów (właściciel/nazwa) do swojego zaplecza i przynajmniej raz uruchomiłeś funkcję aktualizacji przez GitHub-API, powinieneś zobaczyć coś takiego:

Repozytoria zawierające stronę główną naszej aplikacji, pokazujące podstawowe informacje o próbce repozytoriów GitHub

A po kliknięciu jednego z repozytoriów powinieneś zobaczyć coś takiego:

Przykładowa strona szczegółów repozytorium, pokazująca więcej informacji o repozytorium facebook/react GitHub

Po powyższych zmianach nasza implementacja front-endowa jest zakończona.

Świetnie! Teraz musimy tylko wdrożyć.

Wdrażanie interfejsu

W tej części nie musimy wprowadzać żadnych zmian w naszej aplikacji front-endowej. Po prostu wdrożymy go do Netlify — będziesz potrzebować tam konta.

Ale najpierw musimy wdrożyć nasz kod w GitHub, GitLab lub Bitbucket. Podobnie jak w przypadku zaplecza, wdrożyłem swój kod na GitHub.

Następnie zaloguj się do Netlify i kliknij przycisk „Nowa witryna z Git” na pulpicie nawigacyjnym. Postępuj zgodnie z instrukcjami wyświetlanymi na ekranie, aby wybrać dostawcę Git i znaleźć swoje repozytorium.

W ostatnim kroku, jeśli poprawnie ustrukturyzowałeś kod, Netlify automatycznie ustawi polecenie budowania i opublikuje katalog poprawnie w następujący sposób:

Prawidłowe ustawienia opcji budowania Netlify: Wdróż master, użyj "gatsby build" jako polecenia budowania i opublikuj w katalogu "public/".

Następnie kliknij „Wdróż witrynę”. Wdroży twoją witrynę w losowo wygenerowanej subdomenie Netlify, ale możesz to zmienić w dowolnym momencie — zmieniłem moje wdrożenie na https://sample-create-page-api-gatsby.netlify.com, gdzie możesz znaleźć demo na żywo ukończonej aplikacji.

Na razie w porządku. Ale ponieważ jest to statyczna aplikacja strony, musimy ją codziennie przebudowywać, aby była aktualna.

Codzienna aktualizacja za pomocą haka do budowania

Build hooks w Netlify działają jako wyzwalacze kompilacji, więc możesz je wyzwolić ze swojego zaplecza po zakończeniu zadania cron. Aby to zrobić, najpierw utwórz hak do budowania w Netlify.

W sekcji „Buduj i wdrażaj → Ciągłe wdrażanie” możesz znaleźć „Buduj haki”. Kliknij „Dodaj hak kompilacji”.

Gdzie znaleźć haki do budowania w Netlify

Nadaj mu nazwę i zapisz. (Nazwałem mine build-from-backend .) Następnie skopiuj link, który generuje.

Teraz otwórzmy nasz projekt zaplecza i dodajmy te kilka linijek do pliku cron.controller.js . Po prostu wysyłamy żądanie POST na adres URL build-hook 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'); }); } }

Następnie zaktualizuj naszą funkcję updateDaily :

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

Na koniec zaktualizuj nasz plik env.config.js , aby ustawić właściwość netlifyEndpoint , która ma być zbierana ze zmiennych środowiskowych:

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

Teraz musisz ustawić zmienną środowiskową NETLIFY_BUILD_HOOK , którą przed chwilą skopiowałeś z Netlify. W Heroku możesz ustawić zmienne środowiskowe z sekcji „ustawienia” twojej aplikacji.

Po wypchnięciu zatwierdzenia, aplikacja zaplecza wyśle ​​żądanie kompilacji do Netlify, a Twoje strony będą aktualizowane codziennie, pod koniec zadania cron. Oto, jak powinno wyglądać repozytorium po dodaniu funkcji przechwycenia kompilacji, wraz z ostatecznymi wersjami repozytorium zaplecza i repozytorium frontonu.

Na zakończenie projektu pokażemy, jak korzystać z funkcji AWS Lambda wyzwalanej przez AWS CloudWatch, która obudzi Twój backend na czas przy każdej codziennej aktualizacji.

Proste żądanie AWS Lambda i AWS CloudWatch

AWS Lambda to bezserwerowa platforma obliczeniowa. Do naszych celów potrzebujemy tylko podstaw tej platformy. Będziesz potrzebować konta AWS.

Najpierw zaloguj się do AWS za pomocą swojego konta i znajdź konsolę zarządzania Lambda. Na przykład dla us-east-2 można go znaleźć pod adresem https://us-east-2.console.aws.amazon.com/lambda/home.

Jeśli nie jest jeszcze zaznaczone, przejdź do sekcji „Funkcje”:

Sekcja „Funkcje” AWS Lambda

Tutaj stworzymy naszą funkcję od podstaw, klikając „Utwórz funkcję”. Nadajmy mu nazwę wyjaśniającą. Będziemy używać Node.js jako języka uruchomieniowego. Następnie kliknij następną „Utwórz funkcję”, aby ją sfinalizować.

Strona „Create function” w AWS Lambda, wypełniona podczas tworzenia triggerMyBackendAtUTCMidnight z runtime Node.js i nową rolą z podstawowymi uprawnieniami Lambda

Przekieruje nas na stronę nowej funkcji, gdzie możemy napisać nasz kod w index.js .

Zaimplementujmy naszą pierwszą funkcję lambda. Ponieważ nie mamy żadnych zależności zewnętrznych, musimy użyć podstawowych modułów Node.js. (Jeśli zamiast tego chcesz włączyć zależności innych firm, postępuj zgodnie z tym przewodnikiem z AWS.)

Upewnij się, że nazwa eksportowanej metody (w tym przypadku handler ) odpowiada parametrowi „Handler” na stronie:

Parametr Handler z "index.handler" jako wartością

Reszta to proste żądanie GET do twojego zaplecza:

 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); }); }); };

Upewnij się, że ustawiłeś zmienną środowiskową HEROKU_APP_URL na stronie i zapisz konfigurację:

Ustawienie wymaganej zmiennej środowiskowej w AWS Lambda. Pokazana wartość to https://sample-github-api-consumer-nod.herokuapp.com/repositories.

Ostatnim krokiem jest dodanie reguły wyzwalacza CloudWatch, aby uruchomić tę funkcję dziesięć minut przed każdą codzienną aktualizacją — w tej serii artykułów działa to do 23:50:

Konfigurowanie zdarzeń CloudWatch w celu dodania reguły wyzwalającej

Naszym typem reguły wyzwalacza CloudWatch będzie „Wyrażenie harmonogramu” i, zgodnie z przyjętym formatem, naszym wyrażeniem cron będzie cron(50 23 * * ? *) .

Strona AWS CloudWatch „Konfiguruj wyzwalacze”, ustawiona na tworzenie nowej reguły o nazwie cronDailyUpdate z wyrażeniem podanym powyżej i włączonym wyzwalaczem

Skonfigurowaliśmy teraz naszą funkcję AWS Lambda tak, aby była wyzwalana przez naszą regułę CloudWatch.

Teraz zasilamy nasze statyczne strony internetowe: Gatsby/React i Netlify

Dzięki odrobinie AWS Lambda/CloudWatch dodanej do naszego backendu Node.js/MongoDB/Heroku oraz generowaniu i hostowaniu naszego interfejsu Gatsby i Netlify, nasza aplikacja jest gotowa!

Wcześniej udostępniłem link do demonstracji na żywo, ale zachęcam do wypróbowania ulepszonej wersji mojego prototypu — zawiera kilka dodatkowych zmian, które pokochasz.

Możesz użyć tego jako planu dla podobnych projektów — mam nadzieję, że te artykuły pomogą Ci w szybszym i bardziej opłacalnym prototypowaniu aplikacji. Dziękuje za przeczytanie!

Toptal jest zaawansowanym partnerem konsultingowym AWS.