Le Front End : Utilisation de Gatsby.js et Node.js pour les mises à jour statiques du site

Publié: 2022-03-11

Pour certaines exigences de projet, la génération de pages statiques n'est pas seulement suffisante , c'est aussi la plus efficace en termes de vitesse et d'évolutivité.

Dans la première moitié de cette série, nous avons combiné Node.js, Express, MongoDB, cron et Heroku pour fournir un back-end prêt pour CI qui utilise l'API de GitHub selon un calendrier quotidien. Nous sommes maintenant prêts à ajouter Gatsby au mix pour terminer notre projet de génération de page statique.

Développer le front-end : faites-en un site Web Gatsby

Étant donné que les sites Web Gatsby sont basés sur React, il est utile que vous sachiez déjà comment créer un site Web avec React.

Pour le style, j'ai préféré Bootstrap, reactstrap et react-markdown. Vous savez peut-être que les notes de publication dans GitHub sont stockées au format Markdown, d'où notre besoin d'un convertisseur.

Structure de projet de site Web statique

Notre structure de fichiers/dossiers sera la suivante :

Une racine de projet frontale standard avec un dossier public vide et un dossier src pour des fichiers comme package.json. Sous le dossier src se trouvent un sous-dossier styles pour global.css et un sous-dossier templates pour all-repositories.js et repository.js.

A quoi servent ces fichiers ? Voyons voir:

  • env.development et env.production sont des fichiers de configuration de variable d'environnement.
  • Le modèle all-repositories.js sera utilisé pour notre page d'accueil, contenant une liste de référentiels.
  • Le modèle repository.js sera utilisé pour afficher les détails d'un référentiel donné.
  • gatsby-node.js est l'endroit où nous consommons notre point de terminaison principal et exécutons nos méthodes createPage .
  • package.json , comme toujours, contient les dépendances et les propriétés du projet.
  • global.css est notre fichier de feuille de style principal.

Mise en place du site Web Gatsby

Comme pour notre back-end, exécutez npm install (ou yarn , si Yarn est installé) après avoir ajouté les dépendances requises au package.json du 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" } // ... }

Les fichiers env.development et env.production n'ont que l'URL principale de leurs environnements correspondants. Le premier a :

 API_URL=http://localhost:3000

…alors que la production a :

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

gatsby-node.js ne sera exécuté qu'une seule fois pendant que vous construisez votre code. Nous devons donc rassembler toutes les informations nécessaires à partir de notre back-end ici. Ensuite, la réponse sera utilisée avec nos modèles pour générer les pages statiques appropriées.

Dans notre cas, all-repositories.js a besoin de tous les référentiels, et repository.js besoin du référentiel correspondant pour chaque itération. Enfin, nous pouvons générer dynamiquement des chemins de page, en transmettant les paramètres de owner et de name du référentiel dans le champ de 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 } }); }); };

Pour all-repositories.js et repository.js , si nous omettons le style, nous recueillons simplement des données à partir de pageContext et les utilisons comme nous utilisons des paramètres dans React.

Dans all-repositories.js , nous utiliserons le champ repositories de pageContext comme ceci :

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

Comme pour repository.js , nous utiliserons à la place le champ repository de 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> );

Maintenant, assurez-vous que votre back-end est opérationnel. Vous vous souviendrez que pour ce projet, nous l'avons défini comme http://localhost:3000.

Ensuite, exécutez gatsby develop à partir de la racine de votre projet frontal et ouvrez http://localhost:8000.

Si vous avez ajouté des référentiels (propriétaire/nom) à votre backend et exécuté la fonctionnalité update-via-GitHub-API au moins une fois, vous devriez voir quelque chose comme ceci :

La page d'accueil de la liste des référentiels de notre application, affichant les informations de base d'un échantillon de référentiels GitHub

Et après avoir cliqué sur l'un des référentiels, vous devriez voir quelque chose comme ceci :

Un exemple de page de détail du référentiel, montrant plus d'informations sur le référentiel facebook/react GitHub

Après nos modifications ci-dessus, notre implémentation frontale est terminée.

Génial! Il ne nous reste plus qu'à nous déployer.

Déploiement du frontal

Nous n'avons pas besoin d'apporter de modifications à notre application frontale dans cette partie. Nous allons simplement le déployer sur Netlify - vous aurez besoin d'un compte là-bas.

Mais d'abord, nous devons déployer notre code sur GitHub, GitLab ou Bitbucket. Comme pour le back-end, j'ai déployé mon code sur GitHub.

Ensuite, connectez-vous à Netlify et cliquez sur le bouton "Nouveau site de Git" sur votre tableau de bord. Suivez les étapes à l'écran pour sélectionner votre fournisseur Git et trouver votre référentiel.

Pour la dernière étape, si vous avez correctement structuré votre code, Netlify définira automatiquement la commande de construction et le répertoire de publication correctement comme suit :

Les paramètres corrects pour les options de construction de Netlify : Déployez le maître, utilisez "gatsby build" comme commande de construction et publiez dans le répertoire "public/".

Cliquez ensuite sur "Déployer le site". Il déploiera votre site sur un sous-domaine Netlify généré de manière aléatoire, mais vous pouvez le modifier à tout moment. J'ai changé mon déploiement en https://sample-create-page-api-gatsby.netlify.com, où vous pouvez trouver une démo en direct. de l'application terminée.

Jusqu'ici tout va bien. Mais comme il s'agit d'une application de page statique, nous devons la reconstruire quotidiennement pour la maintenir à jour.

Mise à jour quotidienne à l'aide d'un crochet de construction

Les crochets de construction dans Netlify fonctionnent comme des déclencheurs de construction, vous pouvez donc les déclencher depuis votre back-end une fois la tâche cron terminée. Pour ce faire, créez d'abord un crochet de construction dans Netlify.

Sous la section "Construire et déployer → Déploiement continu", vous pouvez trouver "Construire des hooks". Cliquez sur "Ajouter un crochet de construction".

Où trouver des crochets de construction dans Netlify

Donnez-lui un nom et enregistrez-le. (J'ai appelé le mien build-from-backend .) Ensuite, copiez le lien qu'il génère.

Ouvrons maintenant notre projet back-end et ajoutons ces quelques lignes au fichier cron.controller.js . Nous envoyons simplement une requête POST à ​​l'URL build-hook de 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'); }); } }

Ensuite, mettez à jour notre fonction updateDaily :

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

Enfin, mettez à jour notre fichier env.config.js pour définir la propriété netlifyEndpoint à collecter à partir des variables d'environnement :

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

Maintenant, vous devrez définir la variable d'environnement NETLIFY_BUILD_HOOK que vous avez copiée depuis Netlify il y a un instant. Dans Heroku, vous pouvez définir des variables d'environnement à partir de la section "paramètres" de votre application.

Après avoir poussé votre commit, l'application back-end enverra une demande de construction à Netlify et vos pages seront mises à jour quotidiennement, à la fin de votre travail cron. Voici à quoi devrait ressembler le référentiel après l'ajout de la fonctionnalité de crochet de construction, ainsi que les versions finales du référentiel principal et du référentiel frontal.

Comme touche finale au projet, nous montrerons comment utiliser une fonction AWS Lambda déclenchée par AWS CloudWatch qui réveillera votre back-end à temps pour chaque mise à jour quotidienne.

Demande simple AWS Lambda et AWS CloudWatch

AWS Lambda est une plateforme informatique sans serveur. Nous n'avons besoin que des bases mêmes de cette plate-forme pour nos besoins ici. Vous aurez besoin d'un compte AWS.

Tout d'abord, connectez-vous à AWS avec votre compte et recherchez la console de gestion Lambda. Par exemple, pour us-east-2 , il peut être trouvé à https://us-east-2.console.aws.amazon.com/lambda/home.

S'il n'est pas déjà sélectionné, rendez-vous dans la section « Fonctions » :

La section "Fonctions" d'AWS Lambda

Ici, nous allons créer notre fonction à partir de zéro en cliquant sur "Créer une fonction". Donnons-lui un nom explicatif. Nous utiliserons Node.js comme langage d'exécution. Cliquez ensuite sur la prochaine "Créer une fonction" pour la finaliser.

La page « Créer une fonction » d'AWS Lambda, renseignée lors de la création du triggerMyBackendAtUTCMidnight avec un environnement d'exécution Node.js et un nouveau rôle avec des autorisations Lambda de base

Cela nous redirigera vers la page de la nouvelle fonction où nous pourrons écrire notre code dans index.js .

Implémentons notre première fonction lambda. Comme nous n'avons pas de dépendances tierces, nous devons utiliser les modules de base de Node.js. (Si vous souhaitez plutôt activer les dépendances tierces, veuillez suivre ce guide d'AWS.)

Assurez-vous que le nom de la méthode exportée ( handler dans ce cas) correspond au paramètre "Handler" dans la page :

Le paramètre Handler avec "index.handler" comme valeur

Le reste est une simple requête GET à votre 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); }); }); };

Assurez-vous de définir la variable d'environnement HEROKU_APP_URL dans la page et enregistrez votre configuration :

Définition de la variable d'environnement requise dans AWS Lambda. La valeur affichée est https://sample-github-api-consumer-nod.herokuapp.com/repositories.

Une dernière étape consiste à ajouter une règle de déclenchement CloudWatch pour exécuter cette fonction dix minutes avant chaque mise à jour quotidienne. Dans cette série d'articles, cela correspond à 23h50 :

Configuration de CloudWatch Events pour ajouter une règle de déclenchement

Notre type de règle de déclenchement CloudWatch sera une « expression de planification » et, selon le format accepté, notre expression cron sera cron(50 23 * * ? *) .

La page "Configurer les déclencheurs" d'AWS CloudWatch, configurée pour créer une nouvelle règle appelée cronDailyUpdate avec l'expression donnée ci-dessus et le déclencheur activé

Nous avons maintenant configuré notre fonction AWS Lambda pour qu'elle soit déclenchée par notre règle CloudWatch.

Alimente maintenant nos pages Web statiques : Gatsby/React et Netlify

Avec un soupçon d'AWS Lambda/CloudWatch ajouté à notre back-end Node.js/MongoDB/Heroku, et Gatsby et Netlify générant et hébergeant notre front-end, notre application est complète !

J'ai partagé un lien de démonstration en direct plus tôt, mais n'hésitez pas à consulter également une version améliorée de mon prototype - il comporte quelques modifications supplémentaires que je sais que vous allez adorer.

Vous pouvez l'utiliser comme modèle pour des projets similaires. J'espère que ces articles vous aideront à prototyper vos applications de manière plus rapide et plus rentable. Merci d'avoir lu!

Toptal est un partenaire de conseil AWS avancé.