El front-end: uso de Gatsby.js y Node.js para actualizaciones de sitios estáticos

Publicado: 2022-03-11

Para algunos requisitos de proyectos, la generación de páginas estáticas no solo es suficiente , sino que también es la más eficiente en términos de velocidad y escalabilidad.

En la primera mitad de esta serie, combinamos Node.js, Express, MongoDB, cron y Heroku para ofrecer un back-end listo para CI que consume la API de GitHub de acuerdo con un programa diario. Ahora estamos listos para agregar a Gatsby a la mezcla para completar nuestro proyecto de generación de páginas estáticas.

Desarrollo de la interfaz: Conviértalo en un sitio web de Gatsby

Debido a que los sitios web de Gatsby se basan en React, es útil si ya está familiarizado con cómo crear un sitio web con React.

Para el estilo, preferí Bootstrap, reactstrap y react-markdown. Es posible que sepa que las notas de la versión en GitHub se almacenan en formato Markdown, de ahí nuestra necesidad de un convertidor.

Estructura del proyecto de sitio web estático

Nuestra estructura de archivos/carpetas será la siguiente:

Una raíz de proyecto front-end estándar con una carpeta pública vacía y una carpeta src para archivos como package.json. Debajo de la carpeta src hay una subcarpeta de estilos para global.css y una subcarpeta de plantillas para all-repositories.js y repository.js.

¿Para qué son estos archivos? Vamos a ver:

  • env.development y env.production son archivos de configuración de variables de entorno.
  • La plantilla all-repositories.js se usará para nuestra página de inicio, que contiene una lista de repositorios.
  • La plantilla repository.js se usará para mostrar los detalles de un repositorio determinado.
  • gatsby-node.js es donde consumimos nuestro punto final de back-end y ejecutamos nuestros métodos createPage .
  • package.json , como siempre, contiene dependencias y propiedades del proyecto.
  • global.css es nuestro archivo de hoja de estilo principal.

Implementación del sitio web de Gatsby

Al igual que con nuestro back-end, ejecute npm install (o yarn , si tiene Yarn instalado) después de agregar las dependencias requeridas al paquete front-end 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" } // ... }

Los archivos env.development y env.production solo tienen la URL de back-end para sus entornos correspondientes. El primero tiene:

 API_URL=http://localhost:3000

…mientras que la producción tiene:

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

gatsby-node.js se ejecutará solo una vez mientras construye su código. Así que tenemos que recopilar toda la información necesaria de nuestro back-end aquí. Luego, la respuesta se usará con nuestras plantillas para generar las páginas estáticas apropiadas.

En nuestro caso, all-repositories.js necesita todos los repositorios y repository.js necesita el repositorio correspondiente para cada iteración. Finalmente, podemos generar rutas de página dinámicamente, pasando los parámetros de owner y name del repositorio como parte del campo 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 } }); }); };

Para all-repositories.js y repository.js , si omitimos el estilo, simplemente recopilamos datos de pageContext y los usamos como usamos parámetros en React.

En all-repositories.js , usaremos el campo de repositories de pageContext de esta manera:

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

En cuanto a repository.js , en su lugar usaremos el campo de 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> );

Ahora, asegúrese de que su back-end esté en funcionamiento. Recordará que para este proyecto lo configuramos como http://localhost:3000.

A continuación, ejecute gatsby develop desde la raíz de su proyecto front-end y abra http://localhost:8000.

Si agregó algunos repositorios (propietario/nombre) a su back-end y ejecutó la función de actualización a través de GitHub-API al menos una vez, debería ver algo como esto:

La página de inicio de la lista de repositorios de nuestra aplicación, que muestra información básica para una muestra de repositorios de GitHub

Y después de hacer clic en uno de los repositorios, debería ver algo como esto:

Una página de detalles del repositorio de muestra, que muestra más información sobre el repositorio de facebook/react GitHub

Después de nuestros cambios anteriores, nuestra implementación de front-end está lista.

¡Genial! Ahora solo tenemos que desplegar.

Implementación del front-end

No necesitamos hacer ningún cambio en nuestra aplicación front-end en esta parte. Simplemente lo implementaremos en Netlify; necesitará una cuenta allí.

Pero primero, tenemos que implementar nuestro código en GitHub, GitLab o Bitbucket. Al igual que con el back-end, implementé mi código en GitHub.

Luego, inicie sesión en Netlify y haga clic en el botón "Nuevo sitio desde Git" en su tablero. Siga los pasos en pantalla para seleccionar su proveedor de Git y encontrar su repositorio.

Para el paso final, si estructuró su código correctamente, Netlify configurará automáticamente el comando de compilación y publicará el directorio correctamente de la siguiente manera:

La configuración correcta para las opciones de compilación de Netlify: implementar maestro, usar "gatsby build" como comando de compilación y publicar en el directorio "public/".

Luego haga clic en "Implementar sitio". Implementará su sitio en un subdominio Netlify generado aleatoriamente, pero puede cambiarlo en cualquier momento. Cambié mi implementación a https://sample-create-page-api-gatsby.netlify.com, donde puede encontrar una demostración en vivo de la aplicación completa.

Hasta aquí todo bien. Pero debido a que es una aplicación de página estática, tenemos que reconstruirla diariamente para mantenerla actualizada.

Actualización diaria usando un enlace de compilación

Los ganchos de compilación en Netlify funcionan como activadores de compilación, por lo que puede activarlos desde su back-end después de que finalice el trabajo cron. Para hacer eso, primero cree un enlace de compilación en Netlify.

En la sección "Construir e implementar → Implementación continua", puede encontrar "Construir ganchos". Haga clic en "Agregar enlace de compilación".

Dónde encontrar ganchos de compilación en Netlify

Dale un nombre y guárdalo. (Llamé al mío build-from-backend ). Luego copie el enlace que genera.

Ahora abramos nuestro proyecto back-end y agreguemos estas pocas líneas al archivo cron.controller.js . Simplemente estamos enviando una solicitud POST a la URL del enlace de compilación 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'); }); } }

Luego actualice nuestra función updateDaily :

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

Finalmente, actualice nuestro archivo env.config.js para configurar la propiedad netlifyEndpoint para que se recopile de las variables de entorno:

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

Ahora, deberá configurar la variable de entorno NETLIFY_BUILD_HOOK que copió de Netlify hace un momento. En Heroku, puede establecer variables de entorno desde la sección "Configuración" de su aplicación.

Después de presionar su compromiso, la aplicación de back-end enviará una solicitud de compilación a Netlify y sus páginas se actualizarán diariamente, al final de su trabajo cron. Este es el aspecto que debería tener el repositorio después de agregar la funcionalidad de enlace de compilación, junto con las versiones finales del repositorio de back-end y el repositorio de front-end.

Como toque final del proyecto, le mostraremos cómo usar una función de AWS Lambda activada por AWS CloudWatch que activará su back-end a tiempo para cada actualización diaria.

Solicitud simple de AWS Lambda y AWS CloudWatch

AWS Lambda es una plataforma informática sin servidor. Solo necesitamos los conceptos básicos de esta plataforma para nuestros propósitos aquí. Necesitará una cuenta de AWS.

Primero, inicie sesión en AWS con su cuenta y busque la consola de administración de Lambda. Por ejemplo, para us-east-2 , se puede encontrar en https://us-east-2.console.aws.amazon.com/lambda/home.

Si aún no está seleccionado, vaya a la sección "Funciones":

La sección "Funciones" de AWS Lambda

Aquí, crearemos nuestra función desde cero haciendo clic en "Crear función". Vamos a darle un nombre explicativo. Usaremos Node.js como lenguaje de tiempo de ejecución. Luego haga clic en el siguiente "Crear función" para finalizarlo.

Página "Crear función" de AWS Lambda, completada en create triggerMyBackendAtUTCMidnight con un tiempo de ejecución de Node.js y un nuevo rol con permisos básicos de Lambda

Nos redirigirá a la página de la nueva función donde podemos escribir nuestro código en index.js .

Implementemos nuestra primera función lambda. Debido a que no tenemos dependencias de terceros, debemos usar los módulos principales de Node.js. (Si desea habilitar dependencias de terceros, siga esta guía de AWS).

Asegúrese de que el nombre del método exportado ( handler en este caso) coincida con el parámetro "Manejador" en la página:

El parámetro Handler con "index.handler" como su valor

El resto es una simple solicitud GET a su 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); }); }); };

Asegúrese de establecer la variable de entorno HEROKU_APP_URL en la página y guarde su configuración:

Configuración de la variable de entorno requerida en AWS Lambda. El valor que se muestra es https://sample-github-api-consumer-nod.herokuapp.com/repositories.

Un último paso es agregar una regla de activación de CloudWatch para ejecutar esta función diez minutos antes de cada actualización diaria; en esta serie de artículos, eso funciona hasta las 23:50:

Configuración de CloudWatch Events para agregar una regla de activación

Nuestro tipo de regla de activación de CloudWatch será una "expresión de programación" y, según el formato aceptado, nuestra expresión cron será cron(50 23 * * ? *) .

La página "Configurar disparadores" de AWS CloudWatch, configurada para crear una nueva regla llamada cronDailyUpdate con la expresión proporcionada anteriormente y el disparador habilitado

Ahora hemos configurado nuestra función AWS Lambda para que se active mediante nuestra regla de CloudWatch.

Ahora impulsando nuestras páginas web estáticas: Gatsby/React y Netlify

Con una pizca de AWS Lambda/CloudWatch agregado a nuestro back-end Node.js/MongoDB/Heroku, y Gatsby y Netlify generando y alojando nuestro front-end, ¡nuestra aplicación está completa!

Anteriormente compartí un enlace de demostración en vivo, pero siéntete libre de ver también una versión mejorada de mi prototipo, tiene algunos cambios adicionales que sé que te encantarán.

Puede usar esto como modelo para proyectos similares. Espero que estos artículos lo ayuden a crear prototipos de sus aplicaciones de una manera más rápida y rentable. ¡Gracias por leer!

Toptal es un socio consultor avanzado de AWS.