BackVolver al blog

Next.js 9

Next.js 9 incluye soporte para TypeScript, Enrutamiento Dinámico, Rutas API, Optimización Estática Automática y más.

Después de 70 versiones canarias, nos complace presentar Next.js 9, que incluye:

Como siempre, nos hemos esforzado por garantizar que todos estos beneficios sean compatibles con versiones anteriores. Para la mayoría de las aplicaciones Next.js, solo necesita ejecutar:

Terminal
npm i next@latest react@latest react-dom@latest

Hay muy pocos casos en los que su código pueda requerir cambios. Consulte la guía de actualización para obtener más información.

Desde nuestro último lanzamiento, nos complace haber visto empresas como IGN, Bang & Olufsen, Intercom, Buffer y Ferrari lanzarse con Next.js. ¡Vea el showcase para más ejemplos!

Soporte Integrado para TypeScript sin Configuración

Hace un año, Next.js 6 introdujo soporte básico para TypeScript a través de un plugin llamado @zeit/next-typescript. Los usuarios también tenían que personalizar su .babelrc y habilitarlo en next.config.js.

Cuando se configuraba, el plugin permitía que Next.js construyera archivos .ts y .tsx. Sin embargo, no integraba la verificación de tipos, ni proporcionaba tipos para el núcleo de Next.js. Esto significaba que un paquete comunitario tenía que mantenerse por separado en DefinitelyTyped, lo que podía desincronizarse con los lanzamientos.

Al hablar con muchos usuarios, nuevos y existentes, quedó claro que la mayoría estaba muy interesada en usar TypeScript. Querían una solución más confiable y estándar para integrar fácilmente TypeScript en su código existente o nuevo.

Por esa razón, nos propusimos integrar el soporte para TypeScript en el núcleo de Next.js, mejorando la experiencia del desarrollador y haciéndolo más rápido en el proceso.

Configuración Automatizada

Comenzar con TypeScript en Next.js es fácil: renombre cualquier archivo, página o componente de .js a .tsx. Luego, ejecute next dev!

Esto hará que Next.js detecte que TypeScript se está utilizando en su proyecto. La CLI de Next.js le guiará a través de la instalación de los tipos necesarios para React y Node.js.

Next.js también creará un tsconfig.json predeterminado con valores sensatos si no existe. Este archivo permite la verificación de tipos integrada en editores como Visual Studio Code.

Configuración Automatizada de TypeScript en Next.js 9

Verificación de Tipos Integrada

Next.js maneja la verificación de tipos tanto en desarrollo como al construir para producción.

Durante el desarrollo, Next.js le mostrará errores de tipos después de guardar un archivo. La verificación de tipos ocurre en segundo plano, permitiéndole interactuar con su aplicación actualizada en el navegador al instante. Los errores de tipos se propagarán al navegador a medida que estén disponibles.

Verificación de Tipos en Desarrollo de Next.js 9

Next.js también fallará automáticamente la construcción para producción (es decir, next build) si hay errores de tipos. Esto ayuda a evitar enviar código roto a producción.

Verificación de Tipos en Producción de Next.js 9

Verificación de Tipos en Producción de Next.js 9

Núcleo de Next.js Escrito en TypeScript

Durante los últimos meses hemos migrado la mayor parte del código base a TypeScript. Esto no solo ha reforzado nuestra calidad de código, sino que también nos permite proporcionar tipos para todos los módulos principales.

Por ejemplo, cuando importa next/link, los editores que admiten TypeScript mostrarán las propiedades permitidas y qué valores aceptan.

Tipos del Núcleo de Next.js

Tipos del Núcleo de Next.js

Segmentos de Ruta Dinámica

El enrutamiento dinámico (también conocido como URL Slugs o URLs Limpias/Bonitas) fue una de las primeras solicitudes de características en GitHub después del lanzamiento de Next.js hace 2.5 años.

El problema se "solucionó" en Next.js 2.0 introduciendo la API de servidor personalizado para usar Next.js programáticamente. Esto permitió usar Next.js como un motor de renderizado, permitiendo abstracciones y mapeo de URLs entrantes para renderizar ciertas páginas.

Hablamos con usuarios y examinamos muchas de sus aplicaciones, descubriendo que muchas tenían un servidor personalizado. Surgió un patrón: la razón más prominente para el servidor personalizado era el enrutamiento dinámico.

Sin embargo, un servidor personalizado viene con sus propias desventajas: el enrutamiento se maneja a nivel de servidor en lugar del proxy, se implementa y escala como un monolito y es propenso a problemas de rendimiento.

Dado que un servidor personalizado requiere que toda la aplicación esté disponible en una instancia, generalmente es difícil implementarlo en un entorno Serverless que resuelva estos problemas. Las solicitudes Serverless se enrutan a nivel de proxy y se escalan/ejecutan independientemente para evitar cuellos de botella de rendimiento.

Además, ¡creemos que podemos ofrecer una mejor Experiencia para el Desarrollador! Mucha de la magia de Next.js comienza cuando crea un archivo llamado pages/blog.js y de repente tiene una página accesible en /blog.

¿Por qué debería un usuario necesitar crear su propio servidor y aprender sobre la API programática de Next.js para admitir una ruta como /blog/my-first-post (/blog/:id)?

Basándonos en estos comentarios y visión, comenzamos a investigar soluciones de mapeo de rutas, impulsados por lo que los usuarios ya conocían: el directorio pages/.

Creando una Página con Enrutamiento Dinámico

Next.js admite la creación de rutas con parámetros con nombre básicos, un patrón popularizado por path-to-regexp (la biblioteca que impulsa Express).

Crear una página que coincida con la ruta /post/:pid ahora se puede lograr creando un archivo en su directorio pages llamado: pages/post/[pid].js!

Next.js coincidirá automáticamente con solicitudes como /post/1, /post/hello-nextjs, etc. y renderizará la página definida en pages/post/[pid].js. El segmento de URL coincidente se pasará como un parámetro de consulta a su página con el nombre especificado entre los [corchetes].

Por ejemplo: dada la siguiente página y la solicitud /post/hello-nextjs, el objeto query será { pid: 'hello-nextjs' }:

static async getInitialProps({ query }) {
  // pid = 'hello-nextjs'
  const { pid } = query
 
  const postContent = await fetch(
    `https://api.example.com/post/${encodeURIComponent(pid)}`
  ).then(r => r.text())
 
  return { postContent }
}

¡También se admiten múltiples segmentos dinámicos de URL!

La sintaxis [param] es compatible con nombres de directorios y archivos, lo que significa que funcionan los siguientes ejemplos:

./pages/blog/[blogId]/comments/[commentId].js
./pages/posts/[pid]/index.js

Puede leer más sobre esta característica en la Documentación de Next.js o en la sección Next.js Learn.

Optimización Estática Automática

Next.js agregó soporte para generación de sitios web estáticos en la versión 3, lanzada hace aproximadamente dos años. En ese momento, esta era la característica más solicitada para agregar a Next.js.

Y con buena razón: no se puede negar que los sitios web estáticos son ¡rápidos! No requieren cálculo del lado del servidor y pueden transmitirse instantáneamente al usuario final desde ubicaciones CDN.

Sin embargo, la elección entre una aplicación renderizada del lado del servidor o generada estáticamente era binaria, o elegías el renderizado del lado del servidor o la generación estática. No había término medio.

En realidad, las aplicaciones pueden tener diferentes requisitos. Estos requisitos requieren diferentes estrategias de renderizado y compensaciones.

Por ejemplo, una página de inicio y páginas de marketing generalmente contienen contenido estático y son excelentes candidatos para optimización estática.

Por otro lado, un panel de productos puede beneficiarse de ser renderizado del lado del servidor donde los datos se actualizan con frecuencia.

Comenzamos a explorar cómo podríamos dar a los usuarios lo mejor de ambos mundos y ser rápidos por defecto. ¿Cómo podríamos dar a los usuarios páginas de marketing estáticas y páginas dinámicas renderizadas por el servidor?

A partir de Next.js 9, los usuarios ya no tienen que elegir entre renderizar completamente del lado del servidor o exportar estáticamente su aplicación. Dándole lo mejor de ambos mundos en una base por página.

Exportación Estática Parcial Automática

Se introdujo una heurística para determinar automáticamente si una página se puede prerrenderizar a HTML estático.

Esta determinación se hace según si la página tiene requisitos de datos bloqueantes mediante el uso de getInitialProps.

Esta heurística permite que Next.js emita aplicaciones híbridas que contienen páginas renderizadas del lado del servidor y generadas estáticamente.

El servidor integrado de Next.js (next start) y la API programática (app.getRequestHandler()) admiten esta salida de construcción de manera transparente. No se requiere configuración ni manejo especial.

Las páginas generadas estáticamente siguen siendo reactivas: Next.js hidratará su aplicación del lado del cliente para darle interactividad completa.

Además, Next.js actualizará su aplicación después de la hidratación si la página depende de parámetros de consulta en la URL.

Next.js le informará visualmente si una página se generará estáticamente durante el desarrollo. Este artefacto visual se puede ocultar haciendo clic en él.

Indicador de Optimización Estática de Next.js

Indicador de Optimización Estática de Next.js

Las páginas generadas estáticamente también se mostrarán en la salida de construcción de Next.js:

Indicador de Tipo de Salida de Construcción de Next.js

Indicador de Tipo de Salida de Construcción de Next.js

Rutas API

En muchos casos, al construir aplicaciones React, terminas necesitando algún tipo de backend. Ya sea para recuperar datos de una base de datos o para procesar datos proporcionados por tus usuarios (por ejemplo, un formulario de contacto).

Descubrimos que muchos usuarios que necesitaban un backend construían su API usando un servidor personalizado. Al hacerlo, se encontraban con varios problemas. Por ejemplo, Next.js no compila código de servidor personalizado, lo que significa que no podías usar import / export o TypeScript.

Por esta razón, muchos usuarios terminaban implementando su propia canalización de compilación personalizada sobre el servidor personalizado. Si bien esto resolvía su objetivo, es propenso a muchas desventajas: por ejemplo, cuando se configura incorrectamente, la eliminación de código muerto (tree shaking) se deshabilitaría para toda su aplicación.

Esto planteó la pregunta: ¿qué pasa si llevamos la experiencia del desarrollador que proporciona Next.js a la construcción de backends API?

Hoy nos complace presentar las rutas API, la mejor experiencia para el desarrollador de Next.js para construir su backend.

Para comenzar a usar rutas API, crea un directorio llamado api/ dentro del directorio pages/.

Cualquier archivo en este directorio se mapeará automáticamente a /api/<su ruta>, de la misma manera que otros archivos de página se mapean a rutas.

Por ejemplo, pages/api/contact.js se mapeará a /api/contact.

Nota: ¡Las Rutas API también admiten Rutas Dinámicas!

Todos los archivos dentro del directorio pages/api/ exportan una función manejadora de solicitudes en lugar de un Componente React:

export default function handle(req, res) {
  res.end('Hello World');
}

Generalmente, los endpoints API reciben algunos datos entrantes, como la cadena de consulta, el cuerpo de la solicitud o las cookies, y responden con otros datos.

Al investigar la adición de soporte para rutas API en Next.js, notamos que en muchos casos los usuarios no usaban directamente los objetos de solicitud y respuesta de Node.js. En su lugar, usaban una abstracción proporcionada por bibliotecas de servidor como Express.

La razón para hacer esto es que en muchos casos los datos entrantes son alguna forma de texto que primero debe analizarse para ser útil. Por lo tanto, estas bibliotecas específicas de servidor ayudan a eliminar la carga de analizar manualmente los datos, más comúnmente a través de middlewares. Los más utilizados proporcionan análisis de cadena de consulta, cuerpo y cookies, pero aún requieren cierta configuración para comenzar.

Las rutas API en Next.js proporcionarán estos middlewares por defecto para que pueda ser productivo creando endpoints API inmediatamente:

export default function handle(req, res) {
  console.log(req.body); // El cuerpo de la solicitud
  console.log(req.query); // La cadena de consulta de la URL
  console.log(req.cookies); // Las cookies pasadas
  res.end('Hello World');
}

Además de usar datos entrantes, su endpoint API generalmente también devuelve datos. Comúnmente, esta respuesta será JSON. Next.js proporciona res.json() por defecto para facilitar el envío de datos:

export default function handle(req, res) {
  res.json({ title: 'Hello World' });
}

Al realizar cambios en los endpoints API en desarrollo, el código se recarga automáticamente, por lo que no es necesario reiniciar el servidor.

Optimizaciones para Producción

Next.js 9 prefetchará automáticamente los componentes <Link> a medida que aparezcan en el viewport.

Esta característica mejora la capacidad de respuesta de su aplicación al hacer que las navegaciones a nuevas páginas sean más rápidas.

Next.js usa un Intersection Observer para prefetch los recursos necesarios en segundo plano.

Estas solicitudes tienen baja prioridad y ceden ante solicitudes fetch() o XHR. Next.js evitará el prefetching automático si el usuario tiene el ahorro de datos habilitado.

Puede optar por no usar esta característica para páginas poco visitadas estableciendo la propiedad prefetch en false:

<Link href="/terms" prefetch={false}>
  <a>Términos de Servicio</a>
</Link>

AMP optimizado por defecto

Next.js 9 ahora renderiza AMP optimizado por defecto para páginas AMP-first e híbridas.

Aunque las páginas AMP son opcionales, Next.js optimizará automáticamente su salida. ¡Estas optimizaciones pueden resultar en una velocidad de renderizado hasta un 50% más rápida!

Este cambio fue posible gracias al increíble trabajo de Sebastian Benz en el AMP Optimizer.

Eliminación de código muerto para ramas typeof window

Next.js 9 reemplaza typeof window con su valor apropiado (undefined o object) durante las compilaciones del servidor y del cliente. Este cambio permite que Next.js elimine automáticamente código muerto de su aplicación compilada para producción.

Los usuarios deberían ver una reducción en el tamaño de sus paquetes del lado del cliente si tienen código exclusivo del servidor en getInitialProps u otras partes de su aplicación.

Mejoras en la experiencia del desarrollador

Indicador de compilación

En versiones anteriores a la 9, la única forma de saber que ocurriría un reemplazo de código en caliente (y que la cadena de herramientas de compilación de Next.js está trabajando) era mirar la consola del desarrollador.

Sin embargo, muchas veces uno está mirando el renderizado resultante, lo que dificulta saber si Next.js todavía está realizando trabajos de compilación o no. Por ejemplo, podrías estar haciendo cambios sutiles en los estilos de la página y no notarías inmediatamente si se actualizaron.

Por esta razón creamos un RFC / "good first issue" para discutir soluciones potenciales al problema de indicar que se está realizando trabajo.

Recibimos retroalimentación de muchos diseñadores e ingenieros en el RFC, por ejemplo sobre sus preferencias y posibles direcciones para el diseño del indicador.

Rafael Almeida aprovechó esta oportunidad para colaborar con nuestro equipo e implementar un nuevo indicador que ahora está disponible por defecto en Next.js 9.

¡Cada vez que Next.js esté realizando trabajos de compilación verás un pequeño triángulo aparecer en la esquina inferior derecha de la página!

Indicador de compilación de Next.js

Salida de consola

Tradicionalmente, al realizar cambios en desarrollo, Next.js mostraba un estado de indicador de compilación con barras de carga que se llenaban y limpiaba continuamente la pantalla mientras realizabas cambios.

Este comportamiento causaba algunos problemas. Principalmente, borraba la salida de la consola tanto de tu código de aplicación (por ejemplo cuando agregabas console.log a tus componentes) como de herramientas externas que unen la salida de registros como la CLI de Vercel o docker-compose.

A partir de Next.js 9, la salida de registros salta menos y ya no limpia la pantalla. Esto permite una mejor experiencia general ya que tu terminal tendrá información más relevante y parpadeará menos, mientras que Next.js se integrará mejor con las herramientas que ya estés usando.

Salida de consola de desarrollo de Next.js

Un agradecimiento especial a Justin Chase por colaborar en el borrado de salida.

Estadísticas de salida de compilación

Al compilar tu aplicación para producción usando next build, ahora obtendrás una vista detallada de todas las páginas que se compilaron.

Cada página recibe algunas estadísticas automáticamente.

La más prominente es el tamaño del paquete. A medida que tu aplicación crece, tus paquetes JavaScript también lo harán. Esta indicación en tiempo de compilación te ayudará a monitorear el crecimiento de tus paquetes de producción. En el futuro también podrás establecer presupuestos de rendimiento para páginas que fallarán la compilación de producción.

Tamaño de página compilada en Next.js

Tamaño de página compilada en Next.js

Además de los tamaños de paquete, también mostramos cuántos componentes del proyecto y componentes de node_modules se usan en cada página. Esto da una indicación de la complejidad de la página.

Conteo de paquetes por página en Next.js

Conteo de paquetes por página en Next.js

Cada página también tiene una indicación de si está optimizada estáticamente o renderizada del lado del servidor, ya que cada página puede comportarse de manera diferente.

Tipo de página compilada en Next.js

Tipo de página compilada en Next.js

Objeto de configuración por página

Cada página ahora puede exportar un objeto de configuración. Inicialmente esta configuración te permite optar por AMP, pero en el futuro podrás configurar más opciones específicas por página.

pages/about.js
export const config = { amp: true };
 
export default function AboutPage(props) {
  return <h3>¡Mi página AMP About!</h3>;
}

Para optar por renderizado híbrido AMP puedes usar el valor 'hybrid':

pages/about.js
import { useAmp } from 'next/amp';
 
export const config = { amp: 'hybrid' };
 
export default function AboutPage(props) {
  const isAmp = useAmp();
  return <h3>¡Mi página About!{isAmp ? <> ¡Potenciado por AMP!</> : ''}</h3>;
}

El componente de orden superior withAmp fue eliminado en favor de esta nueva configuración.

Hemos proporcionado un codemod que convierte automáticamente el uso de withAmp al nuevo objeto de configuración. Puedes leer más sobre esto en la guía de actualización.

Mejoras en la base de código

Recientemente hemos hecho algunos cambios en nuestras herramientas para proporcionar una mejor experiencia al contribuir a la base de código y garantizar estabilidad a medida que la base de código crece.

Como has leído en la sección de TypeScript, el núcleo de Next.js ahora está escrito en TypeScript y los tipos se generan automáticamente para que las aplicaciones Next.js los usen. Además de ser útil para aplicaciones construidas con Next.js, también es útil cuando se trabaja en el código base del núcleo, ya que obtienes errores de tipo y autocompletado automáticamente.

Next.js ya tenía un conjunto bastante grande de pruebas de integración que consiste en 50+ aplicaciones Next.js con pruebas que se ejecutan contra ellas. Estas pruebas aseguran que cuando se lanza una nueva versión, la actualización sea fluida ya que las características disponibles anteriormente fueron probadas contra el mismo conjunto de pruebas.

La mayoría de nuestras pruebas son de integración porque en muchos casos replican desarrolladores "reales" usando Next.js en desarrollo. Por ejemplo, tenemos pruebas que replican hacer cambios en una aplicación Next.js para ver si el reemplazo de módulos en caliente funciona.

Nuestras pruebas de integración están basadas principalmente en Selenium webdriver, que combinamos con chromedriver para probar en Chrome sin cabeza. Sin embargo, con el tiempo surgieron ciertos problemas en otros navegadores, especialmente navegadores antiguos como Internet Explorer 11.

Como usamos Selenium, pudimos ejecutar nuestras pruebas automáticamente en múltiples navegadores.

Actualmente estamos ejecutando nuestro conjunto de pruebas en Chrome, Firefox, Safari e Internet Explorer 11.

Colaboración con Google Chrome

El equipo de Google Chrome ha estado trabajando en mejorar Next.js contribuyendo RFCs y pull-requests.

El objetivo de esta colaboración son mejoras de rendimiento a gran escala, enfocadas en tamaños de paquetes, tiempo de arranque e hidratación.

Por ejemplo, estos cambios mejorarán la experiencia de sitios web pequeños, pero también de aplicaciones masivas como Hulu, Twitch y Deliveroo.

Module / Nomodule

El primer área de enfoque es enviar JavaScript moderno a navegadores que lo soportan.

Por ejemplo, actualmente Next.js debe proporcionar polyfills para la sintaxis async/await ya que el código podría ejecutarse en navegadores que no soportan async/await, lo que causaría errores.

RFC de colaboración Module/Nomodule en Next.js

RFC de colaboración Module/Nomodule en Next.js

Para evitar romper navegadores antiguos mientras aún se envía JavaScript moderno a navegadores que lo soportan, Next.js utilizará el patrón module/nomodule. Este patrón proporciona un mecanismo confiable para servir JavaScript moderno a navegadores modernos mientras permite que navegadores antiguos recurran a ES5 con polyfills.

El RFC para module/nomodule en Next.js puede encontrarse aquí.

División mejorada de paquetes

La estrategia actual de división de paquetes en Next.js se basa en una heurística de proporción para incluir módulos en un único chunk "commons". Debido a que hay muy poca granularidad (solo hay un paquete), el código se descarga innecesariamente (porque el chunk commons podría incluir código que no es requerido para una ruta particular) o el código se duplica a través de múltiples paquetes de página.

RFC de colaboración en chunking de Next.js

RFC de colaboración en chunking de Next.js

El RFC para la división mejorada de paquetes puede encontrarse aquí.

Otras mejoras

El equipo de Chrome también está trabajando en muchas otras optimizaciones y cambios que mejorarán Next.js. Los RFCs para estos se compartirán pronto.

Estos RFCs y pull-requests están etiquetados como "Collaboration" para que puedan encontrarse fácilmente en el rastreador de issues de Next.js.

Comunidad

Estamos emocionados de ver el crecimiento continuo de la comunidad de Next.js.

Este lanzamiento tuvo más de 65 autores de pull-requests contribuyendo mejoras al núcleo o ejemplos.

Hablando de ejemplos, ¡ahora proporcionamos más de 200 ejemplos sobre cómo integrar Next.js con diferentes bibliotecas y tecnologías! Incluyendo la mayoría de bibliotecas css-in-js y de obtención de datos.

  • Hemos tenido más de 720 contribuyentes que han enviado al menos 1 commit.
  • En GitHub, el proyecto ha sido marcado con estrella más de 38,600 veces.
  • Se han enviado más de 3,400 pull requests desde el primer lanzamiento, ¡eso es más de 800 desde el último lanzamiento mayor!

La comunidad de Next.js se ha duplicado desde el último lanzamiento mayor con más de 8,600 miembros. ¡Únete a nosotros!

Estamos agradecidos con nuestra comunidad y toda la retroalimentación externa y contribuciones que ayudaron a dar forma a este lanzamiento.