Cómo previsualizar contenido con el Modo de Vista Previa en Next.js

Nota: Esta característica ha sido reemplazada por el Modo Borrador.

Ejemplos

En la documentación de Páginas y la documentación de Obtención de Datos, hablamos sobre cómo pre-renderizar una página en tiempo de compilación (Generación Estática) usando getStaticProps y getStaticPaths.

La Generación Estática es útil cuando tus páginas obtienen datos de un CMS sin cabeza (headless CMS). Sin embargo, no es ideal cuando estás escribiendo un borrador en tu CMS y quieres previsualizarlo inmediatamente en tu página. Querrás que Next.js renderice estas páginas en tiempo de solicitud en lugar de tiempo de compilación, y que obtenga el contenido del borrador en lugar del contenido publicado. Querrás que Next.js omita la Generación Estática solo para este caso específico.

Next.js tiene una característica llamada Modo de Vista Previa que resuelve este problema. Aquí hay instrucciones sobre cómo usarlo.

Paso 1: Crear y acceder a una ruta API de vista previa

Revisa la documentación de Rutas API primero si no estás familiarizado con las Rutas API de Next.js.

Primero, crea una ruta API de vista previa. Puede tener cualquier nombre, por ejemplo pages/api/preview.js (o .ts si usas TypeScript).

En esta ruta API, necesitas llamar a setPreviewData en el objeto de respuesta. El argumento para setPreviewData debe ser un objeto, y esto puede ser usado por getStaticProps (más sobre esto más adelante). Por ahora, usaremos {}.

export default function handler(req, res) {
  // ...
  res.setPreviewData({})
  // ...
}

res.setPreviewData establece algunas cookies en el navegador que activan el modo de vista previa. Cualquier solicitud a Next.js que contenga estas cookies será considerada como modo de vista previa, y el comportamiento para páginas generadas estáticamente cambiará (más sobre esto más adelante).

Puedes probar esto manualmente creando una ruta API como la siguiente y accediendo a ella manualmente desde tu navegador:

pages/api/preview.js
// ejemplo simple para probarlo manualmente desde tu navegador.
export default function handler(req, res) {
  res.setPreviewData({})
  res.end('Modo de vista previa activado')
}

Si abres las herramientas de desarrollo de tu navegador y visitas /api/preview, notarás que las cookies __prerender_bypass y __next_preview_data se establecerán en esta solicitud.

Accediendo de forma segura desde tu CMS sin cabeza

En la práctica, querrás llamar a esta ruta API de forma segura desde tu CMS sin cabeza. Los pasos específicos variarán dependiendo de qué CMS sin cabeza estés usando, pero aquí hay algunos pasos comunes que podrías seguir.

Estos pasos asumen que el CMS sin cabeza que estás usando admite configurar URLs de vista previa personalizadas. Si no lo hace, aún puedes usar este método para asegurar tus URLs de vista previa, pero necesitarás construir y acceder a la URL de vista previa manualmente.

Primero, debes crear una cadena de token secreto usando un generador de tokens de tu elección. Este secreto solo lo conocerán tu aplicación Next.js y tu CMS sin cabeza. Este secreto evita que personas que no tienen acceso a tu CMS accedan a las URLs de vista previa.

Segundo, si tu CMS sin cabeza admite configurar URLs de vista previa personalizadas, especifica lo siguiente como la URL de vista previa. Esto asume que tu ruta API de vista previa está ubicada en pages/api/preview.js.

Terminal
https://<tu-sitio>/api/preview?secret=<token>&slug=<ruta>
  • <tu-sitio> debe ser tu dominio de despliegue.
  • <token> debe ser reemplazado con el token secreto que generaste.
  • <ruta> debe ser la ruta de la página que quieres previsualizar. Si quieres previsualizar /posts/foo, entonces debes usar &slug=/posts/foo.

Tu CMS sin cabeza podría permitirte incluir una variable en la URL de vista previa para que <ruta> pueda establecerse dinámicamente basado en los datos del CMS, como: &slug=/posts/{entry.fields.slug}

Finalmente, en la ruta API de vista previa:

  • Verifica que el secreto coincida y que el parámetro slug exista (si no, la solicitud debe fallar).
  • Llama a res.setPreviewData.
  • Luego redirige el navegador a la ruta especificada por slug. (El siguiente ejemplo usa una redirección 307).
export default async (req, res) => {
  // Verifica el secreto y los parámetros
  // Este secreto solo debe ser conocido por esta ruta API y el CMS
  if (req.query.secret !== 'MI_TOKEN_SECRETO' || !req.query.slug) {
    return res.status(401).json({ message: 'Token inválido' })
  }

  // Consulta el CMS sin cabeza para verificar si el `slug` proporcionado existe
  // getPostBySlug implementaría la lógica de consulta necesaria al CMS sin cabeza
  const post = await getPostBySlug(req.query.slug)

  // Si el slug no existe, evita que se active el modo de vista previa
  if (!post) {
    return res.status(401).json({ message: 'Slug inválido' })
  }

  // Activa el Modo de Vista Previa estableciendo las cookies
  res.setPreviewData({})

  // Redirige a la ruta del post obtenido
  // No redirigimos a req.query.slug para evitar vulnerabilidades de redirección abierta
  res.redirect(post.slug)
}

Si tiene éxito, el navegador será redirigido a la ruta que deseas previsualizar con las cookies del modo de vista previa establecidas.

Paso 2: Actualizar getStaticProps

El siguiente paso es actualizar getStaticProps para que admita el modo de vista previa.

Si solicitas una página que tiene getStaticProps con las cookies del modo de vista previa establecidas (a través de res.setPreviewData), entonces getStaticProps será llamado en tiempo de solicitud (en lugar de tiempo de compilación).

Además, será llamado con un objeto context donde:

  • context.preview será true.
  • context.previewData será el mismo que el argumento usado para setPreviewData.
export async function getStaticProps(context) {
  // Si solicitas esta página con las cookies del modo de vista previa establecidas:
  //
  // - context.preview será true
  // - context.previewData será el mismo que
  //   el argumento usado para `setPreviewData`.
}

Usamos res.setPreviewData({}) en la ruta API de vista previa, por lo que context.previewData será {}. Puedes usar esto para pasar información de sesión desde la ruta API de vista previa a getStaticProps si es necesario.

Si también estás usando getStaticPaths, entonces context.params también estará disponible.

Obtener datos de vista previa

Puedes actualizar getStaticProps para obtener datos diferentes basados en context.preview y/o context.previewData.

Por ejemplo, tu CMS sin cabeza podría tener un endpoint API diferente para posts en borrador. Si es así, puedes usar context.preview para modificar la URL del endpoint API como se muestra a continuación:

export async function getStaticProps(context) {
  // Si context.preview es true, añade "/preview" al endpoint API
  // para solicitar datos de borrador en lugar de datos publicados. Esto variará
  // dependiendo de qué CMS sin cabeza estés usando.
  const res = await fetch(`https://.../${context.preview ? 'preview' : ''}`)
  // ...
}

¡Eso es todo! Si accedes a la ruta API de vista previa (con secret y slug) desde tu CMS sin cabeza o manualmente, ahora deberías poder ver el contenido de vista previa. Y si actualizas tu borrador sin publicarlo, deberías poder previsualizar el borrador.

Configura esto como la URL de vista previa en tu CMS sin cabeza o accede manualmente, y deberías poder ver la vista previa.

Terminal
https://<tu-sitio>/api/preview?secret=<token>&slug=<ruta>

Más detalles

Bueno saber: durante el renderizado, next/router expone una bandera isPreview, consulta la documentación del objeto router para más información.

Especificar la duración del Modo de Vista Previa

setPreviewData acepta un segundo parámetro opcional que debe ser un objeto de opciones. Acepta las siguientes claves:

  • maxAge: Especifica el número (en segundos) que durará la sesión de vista previa.
  • path: Especifica la ruta bajo la cual se aplicará la cookie. Por defecto es /, lo que activa el modo de vista previa para todas las rutas.
setPreviewData(data, {
  maxAge: 60 * 60, // Las cookies del modo de vista previa expiran en 1 hora
  path: '/about', // Las cookies del modo de vista previa se aplican a rutas con /about
})

Limpiar las cookies del Modo de Vista Previa

Por defecto, no se establece una fecha de expiración para las cookies del Modo de Vista Previa, por lo que la sesión de vista previa termina cuando se cierra el navegador.

Para limpiar las cookies del Modo de Vista Previa manualmente, crea una ruta API que llame a clearPreviewData():

pages/api/clear-preview-mode-cookies.js
export default function handler(req, res) {
  res.clearPreviewData({})
}

Luego, envía una solicitud a /api/clear-preview-mode-cookies para invocar la Ruta API. Si llamas a esta ruta usando next/link, debes pasar prefetch={false} para evitar llamar a clearPreviewData durante la precarga de enlaces.

Si se especificó una ruta en la llamada a setPreviewData, debes pasar la misma ruta a clearPreviewData:

pages/api/clear-preview-mode-cookies.js
export default function handler(req, res) {
  const { path } = req.query

  res.clearPreviewData({ path })
}

Límites de tamaño de previewData

Puedes pasar un objeto a setPreviewData y tenerlo disponible en getStaticProps. Sin embargo, como los datos se almacenarán en una cookie, hay un límite de tamaño. Actualmente, los datos de vista previa están limitados a 2KB.

Funciona con getServerSideProps

El modo de vista previa también funciona con getServerSideProps. También estará disponible en el objeto context que contiene preview y previewData.

Bueno saber: No debes establecer la cabecera Cache-Control cuando uses el Modo de Vista Previa porque no se puede omitir. En su lugar, recomendamos usar ISR.

Funciona con Rutas API

Las Rutas API tendrán acceso a preview y previewData bajo el objeto de solicitud. Por ejemplo:

export default function myApiRoute(req, res) {
  const isPreview = req.preview
  const previewData = req.previewData
  // ...
}

Único por cada next build

Tanto el valor de la cookie de bypass como la clave privada para encriptar previewData cambian cuando se completa next build. Esto asegura que la cookie de bypass no pueda ser adivinada.

Bueno saber: Para probar el Modo de Vista Previa localmente sobre HTTP, tu navegador necesitará permitir cookies de terceros y acceso al almacenamiento local.