Cómo autoalojar tu aplicación Next.js
Cuando despliegues tu aplicación Next.js, es posible que desees configurar cómo se manejan diferentes características según tu infraestructura.
🎥 Ver: Aprende más sobre autoalojar Next.js → YouTube (45 minutos).
Optimización de imágenes
La Optimización de imágenes a través de next/image
funciona con autoalojamiento sin configuración cuando se despliega usando next start
. Si prefieres tener un servicio separado para optimizar imágenes, puedes configurar un cargador de imágenes.
La Optimización de imágenes puede usarse con una exportación estática definiendo un cargador de imágenes personalizado en next.config.js
. Ten en cuenta que las imágenes se optimizan en tiempo de ejecución, no durante la construcción.
Es bueno saber:
- En sistemas Linux basados en glibc, la Optimización de imágenes puede requerir configuración adicional para evitar un uso excesivo de memoria.
- Aprende más sobre el comportamiento de caché de imágenes optimizadas y cómo configurar el TTL.
- También puedes desactivar la Optimización de imágenes y conservar otros beneficios de usar
next/image
si lo prefieres. Por ejemplo, si optimizas las imágenes por separado.
Middleware
El Middleware funciona con autoalojamiento sin configuración cuando se despliega usando next start
. Como requiere acceso a la solicitud entrante, no es compatible cuando se usa una exportación estática.
El Middleware usa el runtime Edge, un subconjunto de todas las APIs de Node.js disponibles para ayudar a garantizar baja latencia, ya que puede ejecutarse antes de cada ruta o recurso en tu aplicación. Si no deseas esto, puedes usar el runtime completo de Node.js para ejecutar Middleware.
Si buscas añadir lógica (o usar un paquete externo) que requiera todas las APIs de Node.js, podrías mover esta lógica a un layout como un Componente de Servidor. Por ejemplo, verificando headers y redireccionando. También puedes usar headers, cookies o parámetros de consulta para redireccionar o reescribir a través de next.config.js
. Si eso no funciona, también puedes usar un servidor personalizado.
Variables de entorno
Next.js puede soportar variables de entorno tanto en tiempo de construcción como en tiempo de ejecución.
Por defecto, las variables de entorno solo están disponibles en el servidor. Para exponer una variable de entorno al navegador, debe tener el prefijo NEXT_PUBLIC_
. Sin embargo, estas variables públicas se incluirán en el paquete JavaScript durante next build
.
Para leer variables de entorno en tiempo de ejecución, recomendamos usar getServerSideProps
o adoptar incrementalmente el App Router.
Esto te permite usar una única imagen Docker que puede promoverse a través de múltiples entornos con diferentes valores.
Es bueno saber:
- Puedes ejecutar código al iniciar el servidor usando la función
register
.- No recomendamos usar la opción runtimeConfig, ya que no funciona con el modo de salida independiente. En su lugar, recomendamos adoptar incrementalmente el App Router.
Caché e ISR
Next.js puede almacenar en caché respuestas, páginas estáticas generadas, salidas de construcción y otros recursos estáticos como imágenes, fuentes y scripts.
El almacenamiento en caché y la revalidación de páginas (con Regeneración Estática Incremental) usan la misma caché compartida. Por defecto, esta caché se almacena en el sistema de archivos (en disco) en tu servidor Next.js. Esto funciona automáticamente con autoalojamiento usando tanto el Pages Router como el App Router.
Puedes configurar la ubicación de la caché de Next.js si deseas persistir páginas y datos en caché en almacenamiento duradero, o compartir la caché entre múltiples contenedores o instancias de tu aplicación Next.js.
Caché automática
- Next.js establece el header
Cache-Control
comopublic, max-age=31536000, immutable
para recursos verdaderamente inmutables. No puede ser sobrescrito. Estos archivos inmutables contienen un hash SHA en el nombre del archivo, por lo que pueden almacenarse en caché indefinidamente. Por ejemplo, Importaciones de imágenes estáticas. Puedes configurar el TTL para imágenes. - La Regeneración Estática Incremental (ISR) establece el header
Cache-Control
comos-maxage: <revalidate in getStaticProps>, stale-while-revalidate
. Este tiempo de revalidación se define en tu funcióngetStaticProps
en segundos. Si establecesrevalidate: false
, por defecto tendrá una duración de caché de un año. - Las páginas renderizadas dinámicamente establecen un header
Cache-Control
comoprivate, no-cache, no-store, max-age=0, must-revalidate
para evitar que se almacenen en caché datos específicos del usuario. Esto aplica tanto al App Router como al Pages Router. Esto también incluye Modo Borrador.
Recursos estáticos
Si deseas alojar recursos estáticos en un dominio o CDN diferente, puedes usar la configuración assetPrefix
en next.config.js
. Next.js usará este prefijo de recurso al recuperar archivos JavaScript o CSS. Separar tus recursos a un dominio diferente tiene la desventaja de tiempo adicional en la resolución DNS y TLS.
Aprende más sobre assetPrefix
.
Configuración de la caché
Por defecto, los recursos de caché generados se almacenarán en memoria (por defecto 50mb) y en disco. Si estás alojando Next.js usando una plataforma de orquestación de contenedores como Kubernetes, cada pod tendrá una copia de la caché. Para evitar que se muestren datos obsoletos ya que la caché no se comparte entre pods por defecto, puedes configurar la caché de Next.js para proporcionar un manejador de caché y desactivar el almacenamiento en memoria.
Para configurar la ubicación de la caché ISR/Data cuando autoalojas, puedes configurar un manejador personalizado en tu archivo next.config.js
:
module.exports = {
cacheHandler: require.resolve('./cache-handler.js'),
cacheMaxMemorySize: 0, // desactivar caché en memoria por defecto
}
Luego, crea cache-handler.js
en la raíz de tu proyecto, por ejemplo:
const cache = new Map()
module.exports = class CacheHandler {
constructor(options) {
this.options = options
}
async get(key) {
// Esto podría almacenarse en cualquier lugar, como almacenamiento duradero
return cache.get(key)
}
async set(key, data, ctx) {
// Esto podría almacenarse en cualquier lugar, como almacenamiento duradero
cache.set(key, {
value: data,
lastModified: Date.now(),
tags: ctx.tags,
})
}
async revalidateTag(tags) {
// tags es un string o un array de strings
tags = [tags].flat()
// Iterar sobre todas las entradas en la caché
for (let [key, value] of cache) {
// Si los tags del valor incluyen el tag especificado, eliminar esta entrada
if (value.tags.some((tag) => tags.includes(tag))) {
cache.delete(key)
}
}
}
// Si deseas tener caché temporal en memoria para una sola solicitud que se reinicia
// antes de la siguiente solicitud, puedes aprovechar este método
resetRequestCache() {}
}
Usar un manejador de caché personalizado te permitirá garantizar consistencia entre todos los pods que alojan tu aplicación Next.js. Por ejemplo, puedes guardar los valores en caché en cualquier lugar, como Redis o AWS S3.
Es bueno saber:
revalidatePath
es una capa de conveniencia sobre los tags de caché. Llamar arevalidatePath
llamará a la funciónrevalidateTag
con un tag especial por defecto para la página proporcionada.
Caché de construcción
Next.js genera un ID durante next build
para identificar qué versión de tu aplicación se está sirviendo. La misma construcción debe usarse e iniciarse en múltiples contenedores.
Si estás reconstruyendo para cada etapa de tu entorno, necesitarás generar un ID de construcción consistente para usar entre contenedores. Usa el comando generateBuildId
en next.config.js
:
module.exports = {
generateBuildId: async () => {
// Esto podría ser cualquier cosa, usando el último hash git
return process.env.GIT_HASH
},
}
Desfase de versión
Next.js mitigará automáticamente la mayoría de los casos de desfase de versión y recargará automáticamente la aplicación para recuperar nuevos recursos cuando se detecte. Por ejemplo, si hay una discrepancia en el deploymentId
, las transiciones entre páginas realizarán una navegación dura versus usar un valor precargado.
Cuando la aplicación se recarga, puede haber una pérdida del estado de la aplicación si no está diseñado para persistir entre navegaciones de página. Por ejemplo, usar el estado de la URL o almacenamiento local persistiría el estado después de una recarga de página. Sin embargo, el estado del componente como useState
se perdería en tales navegaciones.
Apagados elegantes manuales
Con autoalojamiento, es posible que desees ejecutar código cuando el servidor se apague con señales SIGTERM
o SIGINT
.
Puedes establecer la variable de entorno NEXT_MANUAL_SIG_HANDLE
como true
y luego registrar un manejador para esa señal dentro de tu archivo _document.js
. Necesitarás registrar la variable de entorno directamente en el script package.json
, no en el archivo .env
.
Es bueno saber: El manejo manual de señales no está disponible en
next dev
.
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "NEXT_MANUAL_SIG_HANDLE=true next start"
}
}
if (process.env.NEXT_MANUAL_SIG_HANDLE) {
process.on('SIGTERM', () => {
console.log('Recibido SIGTERM: limpiando')
process.exit(0)
})
process.on('SIGINT', () => {
console.log('Recibido SIGINT: limpiando')
process.exit(0)
})
}