Hero

Desacoplando Drupal con Next.js

Septiembre 21, 2023

mvessuri
devops

Desacoplando Drupal con Next.js

Introducción

Drupal es, sin duda, un poderoso y completo Sistema de Gestión de Contenidos (CMS) que ha ganado su reputación por sus sólidas capacidades de gestión de contenidos. Sin embargo, cuando se trata de la presentación, la capa Front-End integrada de Drupal, basada en Twig, a veces se queda atrás en comparación con alternativas más modernas como ReactJS u otros frameworks de Front-End. El uso de componentes de ReactJS dentro de un tema de Drupal puede mejorar la experiencia del Front-End en cierta medida. Sin embargo, este enfoque a menudo se enfrenta a limitaciones de rendimiento inherentes a Drupal.

Afortunadamente, Drupal reconoció esta limitación hace muchos años y ofrece un tipo diferente de arquitectura conocida como “Drupal Desacoplado”. En este artículo, exploraremos cómo combinar las sólidas capacidades de gestión de contenidos de Drupal con la suave experiencia de usuario de ReactJS aprovechando el poder del framework React Next.js.

Next.js

Antes de sumergirnos en la integración de Drupal con Next.js, primero comprendamos qué ofrece Next.js.

Next.js es un framework React de código abierto desarrollado por Vercel y proporcionado bajo la Licencia MIT. Ofrece una variedad de estructuras, características y optimizaciones adicionales construidas sobre React.js estándar, simplificando el desarrollo y funcionamiento de aplicaciones web.

Next.js es un framework JavaScript, pero brinda una experiencia de desarrollo orientada a TypeScript para construir aplicaciones React. Viene con soporte incorporado para TypeScript y un conjunto completo de tipos específicos de Next.js. También tiene una gran característica que, al iniciar un servidor de desarrollo, detectará el uso de TypeScript en tu proyecto e instalará los paquetes necesarios, completará el archivo tsconfig.json y creará el archivo next-env.d.ts.

Otra ventaja de Next.js sobre otros frameworks de JavaScript es que incluye capacidades de renderización en el lado del servidor, división automática de código y generación de sitios estáticos que te ayudan a crear aplicaciones web amigables para SEO y rápidas. Su sistema de enrutamiento intuitivo y la carga dinámica aseguran una navegación fluida y tiempos de carga optimizados para tus usuarios.

Drupal como un CMS desacoplado

Drupal es un CMS altamente versátil que tradicionalmente sigue una arquitectura unificada, manejando tanto la gestión de contenidos como la representación en el Front-End. Sin embargo, también se puede utilizar como un CMS desacoplado, centrándose únicamente en la gestión de contenidos y exponiendo una API para que las aplicaciones externas la consuman. Este enfoque es comúnmente conocido como “Drupal Desacoplado”.

La comunidad de Drupal ha dedicado esfuerzos sustanciales para transformar Drupal en un CMS orientado a API. Esto significa que los datos almacenados y gestionados por Drupal pueden ser fácilmente accedidos por otro software, como un sitio de Next.js en nuestro caso.

Drupal Core ha admitido durante mucho tiempo funcionalidades de API Rest y JSON API, proporcionando opciones de integración fluida. Además, puedes mejorar las capacidades de la API de Drupal incorporando el soporte de GraphQL como un módulo contribuido.

En este artículo, nos centraremos en JSON API, pero también es posible utilizar GraphQL para conectar Drupal con un sitio de Next.js.

Next.js para Drupal

Lo que hace posible la conexión entre Drupal y Next.js es un proyecto llamado Next.js for Drupal. Esta solución incluye un módulo de Drupal, un paquete Node.js con una clase DrupalClient para facilitar las interacciones con Drupal, y dos proyectos iniciales de Next.js. Estos inicios están diseñados específicamente para ayudar a los desarrolladores a crear aplicaciones que se integren perfectamente con Drupal a través de JSON API o GraphQL.

Este proyecto también proporciona una buena documentación y ejemplos para diferentes escenarios. El proyecto está patrocinado por Chapter Three, y ellos, junto con la comunidad, hicieron un gran trabajo al proporcionar todo el código y la documentación necesarios para construir una aplicación de Next.js con Drupal como fuente de contenido.

El módulo de Drupal

El módulo de Drupal proporcionado por el proyecto Next.js for Drupal habilita características como la Regeneración Estática Incremental y el modo Vista Previa de borradores y contenido (que aún no se ha publicado en el sitio de Next.js).

Lo primero que debes hacer es instalar el paquete de compositor Next.js for Drupal que contiene los módulos de Drupal necesarios. Puedes hacerlo fácilmente en un sitio web de Drupal 9 o 10 existente, o puedes crear una nueva instancia de Drupal desde cero para que actúe como el CMS de tu sitio de Next.js.

composer require drupal/next

También deberás aplicar dos parches para solucionar un par de problemas existentes con algunas de las dependencias de este módulo.

"extra": {
  "patches": {
    "drupal/subrequests": {
      "Get same results on different request": "https://www.drupal.org/files/issues/2019-07-18/change_request_type-63049395-09.patch"
    },
    "drupal/decoupled_router": {
      "Unable to resolve path on node in other language than default": "https://www.drupal.org/files/issues/2022-11-30/decouple_router-3111456-resolve-language-issue-58.patch"
    }
  }
}

Para aplicar parches a tus dependencias de Composer, necesitarás un complemento para Composer. Si estás comenzando un nuevo proyecto de Drupal o tu proyecto existente aún no tiene este complemento de Composer instalado, puedes hacerlo con el siguiente comando:

composer require cweagans/composer-patches

La documentación del proyecto Next.js for Drupal explica cómo hacerlo detalladamente en su Guía de Inicio Rápido.

Para configurar la integración, necesitas habilitar dos módulos de Drupal: el módulo Next y ya sea el módulo Next.js JSON:API o el módulo Next.js GraphQL, según tu método preferido para conectar Drupal y Next.js. Aunque se recomienda JSON:API para la mayoría de las integraciones, puedes optar por GraphQL si tu caso de uso lo requiere.

Puedes instalar estos módulos a través de la interfaz de administración de Drupal en la pantalla de “Ampliar” (Extend). Alternativamente, si prefieres un enfoque de línea de comandos como yo, puedes utilizar Drush para instalarlos con el siguiente comando.

drush pmi next next_jsonapi

Alias de Rutas

El complemento next-drupal de Next.js y los proyectos iniciales utilizan rutas en las funciones de obtención de datos. Por lo tanto, si aún no has configurado alias de rutas en tu sitio de Drupal, deberás configurarlos al menos para los tipos de contenido a los que deseas acceder desde Next.js.

Path Alias

Eso es todo lo que se requiere técnicamente en el lado de Drupal para hacer que el contenido esté disponible en un sitio de Next.js a través de JSON:API. Sin embargo, es probable que desees configurar algunas cosas adicionales, como el modo de vista previa, para poder ver cómo lucen los borradores y el contenido aún no publicado en el sitio de Next.js. Finalmente, definitivamente querrás tener la revalidación a pedido. Esta característica te permitirá actualizar tu sitio de Next.js cada vez que se cree, actualice o elimine cierto contenido en Drupal.

Ve a /admin/config/services/next y haz clic en el botón + Agregar sitio Next.js. Define una etiqueta para identificar tu sitio Next.js y la URL base para él. Para habilitar el modo de vista previa, completa la URL de vista previa y el secreto de vista previa, y para habilitar la revalidación a pedido, completa la URL de revalidación y el secreto de revalidación.

Obteniendo Datos de Drupal

La obtención de datos de Drupal sigue los métodos estándar de Next.js. En tus páginas, tienes una función de exportación que devuelve todos los datos necesarios para que la página se renderice. En Next.js, existen dos funciones de exportación: getStaticProps y getServerSideProps. Ambas funciones son muy similares, pero getServerSideProps se utiliza para la representación en el lado del servidor, y getStaticProps se utiliza para la Generación de Sitios Estáticos, incluida la Regeneración Estática Incremental.

El proyecto Next.js for Drupal proporciona un útil DrupalClient que incluye funciones auxiliares para obtener datos JSON:API de Drupal. También ofrece soporte para GraphQL, pero eso está fuera del alcance de este artículo. Existen muchas funciones disponibles para obtener recursos de Drupal. Aquí tienes algunos ejemplos de las más comunes.

Obtener un recurso por su ID o Ruta

Si simplemente deseas obtener un único recurso para el cual ya conoces el tipo y su UUID, puedes utilizar la función getResource.

const article = await drupal.getResource(
  "node--article",
  "dad82fe9-f2b7-463e-8c5f-02f73018d6cb"
);

El tipo y el UUID son parámetros requeridos para esta función, pero existen algunos parámetros opcionales que pueden ser útiles. Por ejemplo, el parámetro “locale” se puede utilizar para obtener el recurso en un idioma específico.

De manera similar, puedes obtener un recurso de Drupal conociendo su ruta utilizando la función getResourceByPath:

const node = await drupal.getResourceByPath("/blog/slug-for-article")

Creación de Rutas Dinámicas y Obtención de Contenido de Drupal

En muchos casos, como en un blog, definirás un solo archivo de componente React que será utilizado por muchas páginas. En este escenario, utilizas corchetes cuadrados para definir rutas dinámicas en Next.js. Estos archivos de página tienen segmentos dinámicos que se completan en el momento de la solicitud o se pregeneran en el momento de la construcción. Por ejemplo, en el archivo pages/blog/[slug].js, [slug] es el segmento dinámico que se reemplazará por cada entrada de blog específica.

Aunque las rutas son dinámicas, si estamos utilizando la Generación de Sitios Estáticos, Next.js debe saber qué rutas forman parte de nuestra aplicación, ya que necesita esta información para pregenerar cada una de las páginas al momento de hacer la construcción de la app. En la práctica, esto significa que si estamos utilizando getStaticProps, también debemos definir una función getStaticPaths en nuestros archivos de página.

Afortunadamente, Next.js for Drupal también proporciona una función getStaticPathsFromContext para obtener todas las rutas de un tipo de contenido de Drupal.

export async function getStaticPaths(context): Promise<GetStaticPathsResult> {
  return {
    paths: await drupal.getStaticPathsFromContext('node--article', context),
    fallback: "blocking",
  };
}

Esto devolverá las rutas para todos los nodos de artículo en nuestro backend de Drupal. Si necesitamos reducir las rutas, podemos utilizar el parámetro opcional params, que acepta cualquier parámetro JSON:API, como filter.

Ahora necesitamos obtener los datos para cada página, pero no conocemos el UUID de cada recurso. En su lugar, obtendremos la ruta desde el contexto de las funciones getStaticProps o getServerSideProps. Next.js for Drupal proporciona dos funciones para lograr esto: translatePathFromContext, que devuelve información sobre una ruta de Drupal desde el contexto, y getResourceFromContext, que obtiene el recurso de Drupal para el contexto actual.

Veamos un ejemplo de esto.

export async function getStaticProps(context) {
  const path = await drupal.translatePathFromContext(context);

  const node = await drupal.getResourceFromContext(path, context);

  return {
    props: {
      node,
    },
  };
}

Modo de vista previa

Si estamos utilizando getStaticProps, Next.js obtiene todos los datos de la página de nuestro CMS de Drupal y utiliza la generación estática para pre-renderizarlos en el momento de la construcción. Esto hace que las páginas sean mucho más rápidas, ya que no es necesario construirlas para cada solicitud y pueden ser almacenadas en caché por una CDN, mejorando el rendimiento y el SEO.

iFrame preview of Next.js on Drupal

Esto es genial una vez que hemos publicado el contenido de la página, pero probablemente queremos saber cómo se verán las nuevas páginas en nuestro sitio de Next.js antes de publicarlas. Para este escenario, Next.js tiene una función llamada Modo de Vista Previa que permite eludir la Generación Estática solo para este caso específico.

Para configurarlo, debes crear una ruta de API de vista previa en la aplicación de Next.js y una función que maneje la solicitud y llame a setPreviewData en el objeto de respuesta. Esto establece algunas cookies en el navegador, activando el modo de vista previa.

También es posible que debas actualizar la función getStaticProps en tus páginas para admitir el modo de vista previa, por ejemplo, para que los usuarios vean páginas no publicadas si context.preview está configurado como true. La función getStaticProps en las páginas proporcionadas por el proyecto inicial ya admite el modo de vista previa. Normalmente, getStaticProps solo se llama en el momento de la construcción, pero cuando se configuran las cookies para habilitar el modo de vista previa, getStaticProps se llama en el momento de la solicitud. Dependiendo de tu aplicación, es posible que desees obtener datos diferentes según si el modo de vista previa está habilitado o no.

Preview Mode

El módulo de Drupal puede incrustar la vista previa del sitio con un iFrame en la página de entidad. También puedes tener un enlace al sitio de Next.js y ver la vista previa en una pestaña o ventana separada. Esta función incluso admite vistas previas de revisiones, contenido en borrador y moderación de contenido.

Regeneración Estática Incremental

Por lo general, cuando trabajas con la generación de sitios estáticos, creas páginas estáticas para todo tu sitio durante el tiempo de construcción. Esto es excelente para el rendimiento, pero tiene la desventaja de que cuando deseas agregar una página o hacer una actualización en una existente, debes reconstruir todo el sitio.

Next.js ofrece una función llamada Regeneración Estática Incremental que te permite actualizar páginas generadas estáticamente después de haber construido tu sitio. Hay dos formas de hacerlo.

Regeneración Estática Incremental basada en el tiempo

La primera y más sencilla es agregando la propiedad revalidate a getStaticProps. Este valor numérico define los segundos después de los cuales una nueva solicitud a la página activará una regeneración de la página. El usuario seguirá viendo la página en caché (obsoleta), pero Next.js intentará realizar una reconstrucción en segundo plano. Si la reconstrucción tiene éxito, la siguiente solicitud obtendrá una página actualizada.

Esto significa que si configuramos la propiedad revalidate en 60 en getStaticProps de nuestra página de blog, Next.js intentará reconstruir cada página de blog cada minuto.

Revalidación a pedido

Una segunda forma de hacerlo es con la Regeneración Estática Incremental a Pedido. Este es el método compatible con el módulo Next Drupal, pero aún puedes usar la regeneración basada en el tiempo si lo prefieres.

On-demand revalidation

Con la Regeneración Estática Incremental a Pedido, solo activas la regeneración de una página cuando el contenido de Drupal se actualiza, crea o elimina.

Se debe definir un punto de entrada de API para recibir la solicitud y activar la regeneración de la página correcta. Este punto de entrada está predefinido en el proyecto inicial y recibe dos parámetros: el slug para regenerar y un secreto utilizado para validar que la solicitud de regeneración proviene de una fuente confiable.

El módulo de Drupal te permite configurar la Revalidación a Pedido por tipos de entidad. El módulo proporciona un complemento para activar una regeneración por ruta, y también ofrece una forma de definir manualmente un conjunto de rutas adicionales para regenerar, por ejemplo, es posible que desees regenerar también la página de índice de blogs cada vez que se agregue, elimine o actualice una entrada de blog.

Otras características de Next.js for Drupal

El proyecto Next.js for Drupal proporciona soporte para otras funciones que están fuera del alcance de este artículo introductorio pero que vale la pena mencionar.

  • Ayudas para operaciones de escritura JSON:API (POST, PATCH, DELETE)
  • Ayudas para obtener colecciones completas de recursos
  • Ayudas para obtener menús de Drupal, vistas e índices de Search API
  • Soporte para el componente de imagen de Next.js para imágenes en línea y entidades multimedia en campos de texto
  • Soporte para el componente de enlace de Next.js para enlaces en línea en campos de texto
  • Uso de formularios web de Drupal dentro de Next.js
  • Múltiples sitios de Next.js construidos a partir de una sola fuente de Drupal CMS

Conclusión

Next.js for Drupal es un gran proyecto, bien documentado y con una buena cantidad de ejemplos de código y proyectos iniciales para que integres un backend de Drupal con un sitio web o aplicación de Next.js. El soporte para JSON API es completo y robusto, y las características adicionales como el soporte para vistas previas de borradores y la regeneración estática incremental a pedido lo convierten en una de las mejores alternativas si deseas comenzar un nuevo proyecto desacoplado con Drupal.

Recibe consejos y oportunidades de trabajo 100% remotas y en dólares de weKnow Inc.