hand Inicio

SERVICIOS

Salir

nochedía

GatsbyJS básico

3300 palabras
13 minutos
July 16, 2020

Gatsby es una de las mejores alternativas existentes para generar webs estáticas

Y qué cosas no se pueden hacer con webs estáticas, en la época de los servicios externalizados?

Te lo explico en este curso, tutorial, guía o introducción a GatsbyJS

Prólogo

Gatsby es velocidad

Esto es así porque no hay backend más allá del servidor simple que sirve las páginas estáticas

Y en este paradigma realmente simplificas el tiempo de desarrollo y el tiempo de ejecución

Además, Gatsby es React, con lo que tus opciones para desarrollar aplicaciones complejas son enormes

Vamos allá

  1. Prólogo
  2. Entorno de trabajo
  3. Empezando con el Hello World
  4. Navegación
  5. Utilizando Typography
  6. Ejemplo de página completa
  7. Creando las páginas programáticamente
  8. Query Templates
  9. Schema
  10. La página web
  11. Comentario

Entorno de trabajo

Lo primero de todo es prepararte el entorno de trabajo, tienes el curso aquí

Empezando con el Hello World

Empezamos con el starter

Y nos centramos en el archivo index.js

Importamos React, básico para utilizar Gatsby

Y exportamos un componente por defecto, con la nomenclatura ES6 (tienes el curso de JavaScript aquí), que no es más que una función que nos devuelve elementos html

Pero no es html sino que es JSX, porque si queremos podemos hacer lo siguiente

Todo lo que va entre corchetes se evalúa, aquí tenemos la magia del JSX

Dicho esto, depende de cómo exportamos los componentes los podremos importar de una u otra manera

Para poder importar lo primero necesitamos hacer

O lo que es lo mismo

Y lo podemos importar con el nombre que queramos (y precisamente por eso mejor que no exportes / importes así)

La alternativa, y lo importamos de la segunda manera

Así sólo puedes importarlo por el nombre del componente, aunque luego si quieres le puedes poner alias

Un detalle

El primero es un componente, porque empieza en mayúsculas

El segundo no lo es

Y ya que estamos hablando de componentes, para utilizarlos lo haces como si fuera html, como el elemento <App />

Entonces, para generar nuestro primer site en Gatsby ponemos en el index.js

Ejecutamos en el terminal

Y nos vamos a localhost:8000

Styled Components

Hay muchas maneras de estilar nuestra página web

Aquí utilizaré styled-components, muy muy muy parecida a @emotion, y que nos permite estilar con css-in-js

Para instalarlo

Y luego nos vamos al archivo gatsby-config.js

Volvemos a index.js

Como ves, acabamos de crear un componente que no es un componente de React sino de styled-components, y esta manera de escribir es en realidad JavaScript, se trata de las tagged templates (explicación)

A efectos prácticos lo que nos permite esto es volcar literalmente código css en el mismo lugar donde estamos escribiendo JSX

Argumentos en los componentes

Para comunicarnos entre componentes tenemos los argumentos

Aquí pasamos argumentos tanto en el componente css <Title> como en el componente <Hola>, y lo hacemos al estilo html (o más bien xml)

Y cómo los recibimos? Con los props, que los podemos desestructurar tal cual (si queremos)

Y con los componentes css? Pues necesitamos hacerlo de una forma algo distinta, necesitamos añadir una función anónima y esa función es la que recibirá los props como argumento

También los podemos desestructurar (si queremos)

Y la libertad que tenemos es absoluta, esto es completamente equivalente

Pero, y si queremos pasarle muchos argumentos? No hay alternativas?

Sí, de forma natural, como lo haríamos en html

Y ya lo tenemos, todo lo que vaya entre los tags se pasa como argumento con el nombre especial de props.children

Si lo pruebas con codesandbox, recuerda que tienes que añadir las dependencias, en este caso de styled-components

Ojo, esto que estamos viendo no es Gatsby, esto es el React que necesitamos para Gatsby

Pequeño inciso, este código es el mismo

Para qué sirve?

Para poner un elemento que luego se transforme en nada en html

Para qué lo necesitamos?

Un componente de React no puede devolver más de un elemento, por lo que siempre necesitaremos un único elemento padre

Navegación

Qué historia tiene la navegación? Ponemos simplemente un <a href=""> y listos no?

Sí, pero Gatsby nos ofrece una navegación out-of-the-box que ya nos pre-carga los links con antelación

Esto quiere decir que cuando el usuario vaya a esa dirección (si es que va), la transición será instantánea

Se trata del elemento <Link to=""> y lo importamos (ahora sí) desde gatsby

Y si queremos hacerlo con styled-components ningún problema

Si quieres probar esto de los enlaces deberás crear la página /contactar.js, claro

Utilizando Typography

Typography lo encuentras en aquí y es un plugin que nos sirve para dotarnos de una estética determinada a nivel de tipografía

Si queremos hacer una página web lo más rápidamente posible, esta librería nos simplifica mucho las cosas

Primero lo instalamos

Y para añadirlo nos vamos a gatsby-config.js y lo añadimos

Podríamos haberlo escrito así

Pero si queremos pasar opciones al plugin, entonces necesitamos añadir un objeto en lugar de un string (como hemos hecho arriba)

Y en el archivo src/utils/typography.js

Aquí he escogido el tema concreto de typography-theme-wordpress-2012, por lo que nos falta instalarlo

Ahora, cuando utilizemos los tags habituales de html, el <h1>, el <blockquote>, etc, estos ya están estilados, incluyendo la fuente

Ejemplo de página completa

Al final una página web difícilmente constará de una única página

Lo suyo es dividirla en responsabilidades, un ejemplo sería éste, donde lo seguiríamos poniendo en el directorio /src/pages/

  • ./src/pages/index.js
  • ./src/components/header.js
  • ./src/components/main.js
  • ./src/components/main.js
  • ./src/components/cta.js
  • ./src/components/grid.js
  • ./src/components/footer.js
  • ./src/components/form.js (éste lo importamos desde el cta)

Esto sería una estructura de base, y a partir de aquí iríamos añadiendo funcionalidades

Lo bueno de esta configuración es que ya tenemos una manera muy cómoda de integrar css, js y html para generar una web escribiendo JavaScript moderno, que se compilará a JavaScript más compatible, que lo hará en formato estático, y con el que podremos hacer continuous deployment en un servidor tipo Netlify

Creando las páginas programáticamente

Hasta ahora, las páginas con Gatsby las hemos creado volcando páginas (formato .js) en el directorio /pages y mágicamente se convertían en páginas

Esta manera de crear páginas es simple y rápida, pero no es la habitual ya que nos resta mucha versatilidad

La alternativa es controlar la creación de las páginas, y esto se hace desde el archivo gatsby-node.js

Todo lo que escribamos en gatsby-node.js no lo ejecutará el navegador, sino que lo ejecutará NodeJS para generar los archivos de las páginas estáticas finales

Esto es importante porque NodeJS no utiliza JavaScript ES6 sino que utiliza CommonJS, una versión diferente y menos moderna

Hasta que NodeJS cambie a ES6 (está en proceso, pero es y será lento), hay que acostumbrarse a escribir un JavaScript más clásico

Para qué nos sirve generar páginas programáticamente?

Por ejemplo, nos da la oportunidad de leer datos de otra fuente, y a partir de estos datos generar nuestras páginas

Qué datos?

Los que quieras, la idea es que tengas un gestor de contenidos local o en la nube, por ejemplo el mismo WordPress, y que de allí leas los posts y generes tu página web

Cada vez que escribas un post tendrás que volver a generar tu página web

Y todo esto se puede automatizar para que automáticamente un nuevo post en WordPress active un nuevo deploy en Netlify

Cómo de factible es preparar una página con Gatsby y WordPress para un cliente?

Complicado

Básicamente porque actualizar un WordPress se hace en un momento

Pero actualizar todo el código de Gatsby implica actualizar todos los paquetes implicados, puede haber incompatibilidades, y puede que tengamos que modificar el código

De hecho, este "puede" es bastante frecuente, y normalmente estas tareas no las puede hacer un usuario avanzado, para esto necesitas ser desarrollador

En ese sentido WordPress es una maravilla

Generando contenido con Markdown

En lugar de utilizar algún gestor de contenidos, aquí utilizaremos markdown, un formato de texto increíblemente sencillo que nos sirve de forma excelente para escribir y organizar nuestro contenido

Pero si con React en lugar de escribir en JavaScript o en html escribimos en JSX, en Markdown igual, en lugar de escribir en MD escribimos en MDX

Para ilustrar cómo funciona el MDX

Para esto necesitamos instalar plugins

El gatsby-source-filesystem nos leerá archivos concretos, y el resto nos permitirá entender el código mdx

Los configuramos en gatsby-config.js

La variable __dirname nos la da NodeJS y nos devuelve el directorio donde esté el módulo, en este caso /

Ahora necesitamos crear la carpeta /content, fuera de /src, tal y como ves en el pantallazo

image

Y en /content ya podemos crear nuestro primer post, un archivo de nombre mi_primer_post.mdx

Y cómo lo podemos ver?

Lo esperable quizá sería que Gatsby nos proporcionara el contenido de esos archivos para que nosotros pudiésemos hacer lo que quisiéramos

Pues precisamente esto es lo que hace

Pero en lugar de hacerlo sin más, lo hace alrededor de GraphQL, un sistema que permite recabar datos a partir de queries

Para ver cómo funciona, puedes probar la herramienta GraphiQL

Está en http://localhost:8000/___graphql con gatsby develop

Allí podrás entretenerte viendo los nodes disponibles de tu aplicación, y allí encontrarás esa misma entrada de antes

GraphiQL es una herramienta que nos sirve para explorar y validar nuestras queries que luego haremos en código

Y cómo funciona gatsby-node.js?

Con una serie de hooks donde podemos definir hacer según qué cosas

onCreateNode

El plugin gatsby-source-filesystem nos genera "nodos" de GraphQL basado en lo que encuentra en el directorio al que apunta

Pero no tiene toda la información que querríamos

Vamos a añadirle un slug o lo que es lo mismo, una ruta (la ruta de nuestro archivo markdown)

Para hacerlo podemos hacer dos cosas, podemos modificar un nodo, o podemos crear un nuevo nodo de cero, aquí haremos lo segundo

Nos vamos al archivo ./gatsby-node.js (recuerda que se escribe en CommonJS, nada de funciones con fat arrows por ejemplo)

Al detalle

Esta función la definimos para eliminar los trailing slashes, es decir, para que en lugar de generarse páginas del tipo /mi-primer-post/ se generen páginas sin el slash último /mi-primer-post

Cuando Gatsby está generando los nodos, si nos enganchamos a este hook podremos participar en el proceso

Para ello utilizaremos las funciones createNode y createParentChildLink

Es decir, sólo queremos modificar los nodos graphQL si el archivo es del tipo Mdx

El nodo que recibimos lo tenemos en la variable node, aquí recabamos información del mismo

Aquí creamos el path /mi_primer_post/ creando la estructura filePath y utilizando la función createFilePath() que antes hemos importado

Después le quitamos el trailing slash con replacePath() y convertimos en /mi_primer_post

Cuando definimos un objeto, si la key y el value tienen el mismo nombre podemos ahorrarnos uno

Aquí construimos el objeto fieldData con el que agregamos cierta información, esto será la base del nuevo nodo de GraphQL que estamos fabricando

cuando utilizamos el plugin de mdx, una de las cosas que nos aporta es que nos saca la primera parte del archivo .mdx, esa que tenía una forma rara

Esta parte está escrita en formato YAML, y el plugin lo reconoce y nos lo presenta en GraphQL en el nodo node.frontmatter

Aquí creamos un ID de nodo con la función createNodeId() que Gatsby nos proporciona, donde le indicamos el id que ya tenía el nodo y lo adornamos con el tipo de nodo que estamos creando (y que le decimos MdxBlogPost porque queremos)

Y aquí creamos el nodo con la función createNode e indicando su id, su nodo padre, la información (con ...fieldData) y un subnodo internal con más información

Y finalmente lo vinculamos con el nodo original (no estamos modificando ese nodo, estamos creando uno nuevo= con createParentChildLink

Con esto ya podríamos irnos a GraphiQL y explorar la forma que tiene el nodo que hemos creado

Pero antes, por qué no aprovechar y en lugar de añadir los tags tal cual, convertirlos en un array?

onCreatePage

Más cosas

Hemos visto como quitar los trailing slashes de nuestras páginas basadas en archivos .mdx

Pero y qué pasa con las páginas que están en /pages? Esas siguen teniendo estos trailing slashes

Para interferir en la creación de páginas necesitamos otro hook, el onCreatePage()

Devolvemos una promesa que la resolveremos ejecutando resolve()

Allí copiamos la página original con oldPage, modificamos la actual con la función replacePath que antes hemos visto, y si el resultado final es distinto (y por lo tanto el path original tenía un trailing slash) borramos y creamos una nueva página

createPages

Éste es el hook que nos permite crear páginas desde cero

No confundas el createPages() con el anterior onCreatePages()

Bien, el primer código es crítico

Aquí estamos enlazando gatsby-node.js que es puro backend con lo que será la página frontend

Una consecuencia práctica de esto y que nos ayuda a visualizar dónde estamos, es que a partir de estos archivos ./src/queries/post-query y ./src/queries/posts-query ya podremos escribir en ES6 y olvidarnos del CommonJS

Luego entraremos en detalle, de momento son las puertas de enlace entre nuestro backend y el frontend

Aquí entramos en el hook como en el caso anterior

Y aquí estamos pidiendo datos con graphQL que recibiremos en la variable result

Puedes copiar esta query en el GraphiQL y ver qué te devuelve, te servirá para visualizar qué estamos haciendo (y es muy útil)

En resumen, le estamos pidiendo los nodos que se corresponden con los archivos mdx que tenemos en /content, y se los pedimos ordenador por la date y el title y con un máximo de 1000 elementos

Si te fijas, te preguntarás qué es date?

No existe, por lo que si quieres ordenarlo por fecha, o puedes buscar la propiedad de la fecha de creación del archivo (en GraphiQL) y utilizarla, o añadir un campo en YAML al lado de title que ponga date y añadir la fecha manualmente

O puedes borrarlo de la query y pasarás a recibir las entradas ordenadas por orden alfabético

La variable posts será un array con toda la información de nuestros nodos mdx

Con esto, lo que vamos a hacer son 2 cosas:

  • Generar una página que muestre todos los posts

  • Generar para cada post una página individual

Y también podríamos generar para cada tag una página con las entradas con ese tag, que no lo haré aquí pero para que veas las virgerías que puedes hacer programáticamente

Y también para que veas todo lo que WordPress te da sin que tu tengas que hacerlo, que también hay que valorarlo

En relación al loop forEach

Las variables previous y next tienen sentido en la paginación, y es que si tenemos 500 posts no querremos hacer una página general con 500 entradas, sino que lo suyo es hacer por ejemplo 10 páginas con 50 entradas cada una, e implementar la paginación con botones

Pero esto no es lo que hacemos aquí

Aquí estamos ejecutando un createPage para cada elemento de posts, por lo tanto estamos generando las páginas individuales para los posts

Con previous y next lo que estamos haciendo es proporcionar información sobre los posts anteriores y posteriores para que luego podamos poner un enlace (si queremos)

La otra línea importante es la de component: PostTemplate

Allí vinculamos el backend con el frontend, es decir, allí la página que representa PostTemplate (tienes el require arriba de todo) es la que recibirá los argumentos que estamos definiendo con createPage

Y seguimos con la creación de la página general

Aquí si te fijas generamos un forEach a partir del número de páginas que queremos generar (si tenemos 100 entradas generaremos 5 páginas de 20 entradas cada una)

Y como antes, la línea importante es la de component: PostsTemplate (con la misma explicación)

No explicaré la paginación, pero ya puedes intuir que la mayoría de las variables arriba están relacionadas con esto

Query Templates

Hemos generado páginas para cada post y páginas para que muestren todos los posts juntos

Pero si te fijas en la query de antes, allí recabamos muy poca información

La información que necesitamos para cada página en realidad la recabamos en los archivos que importamos antes, y que son los que ahora vamos a mirar

Uno puede pensar en qué opción es mejor:

  • Si en hacer una gran query en gatsby-node.js y luego pasar esa información a las templates

  • O por el contrario hacer lo que hemos hecho, una query de mínimos en gatsby-node.js y luego que cada página haga sus queries particulares

Esta decisión en realidad tiene implicaciones importantes tanto en el build time (con gatsby build) como en el tamaño de JavaScript que nuestra página tenga que procesar

En otras palabras, cuando quieras optimizar tu página web una de las cosas que harás será jugar con estas queries

Por lo tanto, un buen consejo es que no pidas información que no necesites, cuantos menos datos involucrados mucho mejor

El código anterior era este

Lo primero va a ser crear esos archivos, empecemos con el posts-query.js

Si te fijas, con el primer párrafo lo tenemos todo!

Por qué? Porque aquí estamos importando el componente PostsPage y lo estamos exportando

Es decir, hacemos de intermediarios, y en el proceso también exportamos la constante query

Al final lo que nos permite esto es poder desacoplar la query del template en dos archivos para tenerlo todo bien segmentado y ordenado

En relación a la query ya puedes ver que aquí recabamos más información

A destacar de la query en sí, con skip: $skip y el limit estamos implementando la paginación (una página irá de las entradas del 1 al 20, la otra del 21 al 40, etc)

(evidentemente esta template es la que genera las páginas generales de los posts)

Ahora nos falta la template

Básicamente aquí esto generando una lista modified_posts que creo a partir de los nodos que recibo, y es con esa lista final que trabajaré y que se la envío al componente Structure (que es el equivalente al index.js que veíamos al principio)

Al igual que antes, todas las variables de num_of_pages, current_page, etc, sirven para implementar la paginación (si es que la necesitamos)

Ahora toca hacer lo mismo con la query y el template de las páginas individuales

Aquí recabamos más información, lo importante es el body, es decir el contenido del post

Y la template

Mucho más sencillo ya que sólo tenemos información de una entrada

Recuerda que en los archivos de las templates ya estamos en el frontend

Y el componente <Structure>?

Por ejemplo

Este componente hace la función del archivo index.js de antes

Ojo, porque para que ahora nos funcione la generación de páginas tenemos que eliminar ese archivo index.js, de otro modo Gatsby nos generaré la página principal a partir de ese archivo

Schema

Si has probado de ejecutar el gatsby develop con el código anterior habrás visto que tenemos un problema

Y es que con esta query no podemos acceder a body

Si vamos a GraphiQL veremos que en las entradas mdxBlogPost no tenemos la propiedad body

Si buscamos, sí que lo encontramos en las entradas Mdx, que son las que nos da el plugin gatsby-plugin-mdx

image
  1. Lo primero que podríamos hacer es volver al gatsby-node y añadir allí el body en el nodo, pero veríamos que no tenemos acceso a la información con lo que no podríamos hacerlo

  2. Lo segundo que podríamos hacer es crearnos un nuevo schema

Esto lo hacemos con el hook createSchemaCustomization en el mismo gatsby-node, y conceptualmente lo que haríamos es lo que queríamos hacer antes, heredar el contenido de Mdx para que también se muestre en los nodos mdxBlogPost

Haríamos algo así

Mucho trabajo para conseguir algo tan sencillo no?

Afortunadamente hay una alternativa mucho más sencilla, y es modificar la query para acceder a los datos que queramos

Por ejemplo, también para acceder a información que nos da gatsby-plugin-mdx como el tiempo de lectura o las palabras que se incluyen en ese archivo

Lo que hecho se conoce como inline fragments (documentación)

La página web

Una vez ya tenemos todo el esqueleto, nos falta aprovechar los datos que hemos generado en el backend con el frontend

El primer componente es el <Structure>, que lo hemos definido antes pero si aprovechar esos datos

Aquí estoy desestructurando todo lo que recibo

Esto lo recibimos de los templates, aquí

y aquí

Por lo tanto en esta desestructuración siempre tendré elementos vacíos porque simplemente no los tendré como argumentos

Esto lo puedo aprovechar para ver dónde estoy, si en la página de la malla de posts, o en un post individual

Y eso es lo que hago con

donde he creado también el componente <Post>

Ésta manera de estructurarme con un componente que me hace de distribuidor es una manera de estructurarse, cualquier otra alternativa será igual de válida

Vamos a por los componentes <Grid> y <Post>

Es auto-explicativo, excepto mencionar el porqué no utilizo <> en lugar de <React.fragment>

Las dos fórmulas son equivalentes, pero sólo la segunda permite que añadamos argumentos

Y en este caso, siempre que utilizemos un map() en React para volcar contenido, React nos pide que añadamos una key única para él poder monitorear ese elemento

Si no tiene la key nos protestará con un warning

Y esta parte tampoco tiene misterio, excepto por la parte <MDXRenderer> que la necesitamos para de algún modo convertir los datos que tenemos en {content} que son JavaScript a elementos html

Comentario

Con esto hemos hecho el esqueleto de una página basado en Gatsby, funcional (a medias) pero que nos ha servido para ver una gran parte de lo que define el funcionamiento de Gatsby

Y eso en realidad es lo que encontrarás en la gran mayoría de starters de los que puedes explorar el código para reconocer las partes que hemos ido viendo

🙋‍♂️

Qué tal el curso?
👌 Bien 🙌🙌
👍 Bien, pero algunas cosas podrían explicarse mejor 😬
🤷‍♂️ Da por sentadas demasiadas cosas 😒
🤷‍♂️ A ver, hay poca chicha 😬
🤷‍♂️ Los ejemplos no son muy claros 🙇‍♂️
🤷‍♂️ No se entiende, está mal escrito 👎
✍️ Hay errores, revísalo en cuanto puedas 🙏

Quizá te interese

Privacidad
by kuworking.com
[ 2020 >> kuworking ]