Cómo migrar de Vite a Next.js
Esta guía te ayudará a migrar una aplicación existente de Vite a Next.js.
¿Por qué cambiar?
Existen varias razones por las que podrías querer cambiar de Vite a Next.js:
Tiempo de carga inicial lento
Si has construido tu aplicación con el plugin por defecto de Vite para React, tu aplicación es puramente del lado del cliente. Las aplicaciones solo del lado del cliente, también conocidas como aplicaciones de una sola página (SPAs), suelen experimentar tiempos de carga inicial lentos. Esto ocurre por varias razones:
- El navegador necesita esperar a que el código de React y todo el paquete de tu aplicación se descarguen y ejecuten antes de que tu código pueda enviar solicitudes para cargar algunos datos.
- El código de tu aplicación crece con cada nueva característica y dependencia adicional que agregues.
Sin división de código automática
El problema anterior de tiempos de carga lentos puede manejarse parcialmente con división de código. Sin embargo, si intentas hacer la división de código manualmente, a menudo empeorarás el rendimiento. Es fácil introducir inadvertidamente cascadas de red al dividir el código manualmente. Next.js proporciona división de código automática integrada en su enrutador.
Cascadas de red
Una causa común de bajo rendimiento ocurre cuando las aplicaciones hacen solicitudes secuenciales cliente-servidor para obtener datos. Un patrón común para la obtención de datos en una SPA es renderizar inicialmente un marcador de posición y luego obtener los datos después de que el componente se haya montado. Desafortunadamente, esto significa que un componente hijo que obtiene datos no puede comenzar a obtenerlos hasta que el componente padre haya terminado de cargar sus propios datos.
Si bien Next.js admite la obtención de datos en el cliente, también te da la opción de mover la obtención de datos al servidor, lo que puede eliminar las cascadas cliente-servidor.
Estados de carga rápidos e intencionales
Con soporte integrado para transmisión mediante React Suspense, puedes ser más intencional sobre qué partes de tu interfaz de usuario quieres cargar primero y en qué orden sin introducir cascadas de red.
Esto te permite construir páginas que se cargan más rápido y eliminar cambios de diseño.
Elige la estrategia de obtención de datos
Dependiendo de tus necesidades, Next.js te permite elegir tu estrategia de obtención de datos por página y componente. Puedes decidir obtener en tiempo de construcción, en tiempo de solicitud en el servidor o en el cliente. Por ejemplo, puedes obtener datos de tu CMS y renderizar tus publicaciones de blog en tiempo de construcción, que luego pueden almacenarse en caché eficientemente en una CDN.
Middleware
El middleware de Next.js te permite ejecutar código en el servidor antes de que se complete una solicitud. Esto es especialmente útil para evitar mostrar contenido no autenticado cuando el usuario visita una página solo para autenticados redirigiéndolo a una página de inicio de sesión. El middleware también es útil para experimentación e internacionalización.
Optimizaciones integradas
Imágenes, fuentes y scripts de terceros suelen tener un impacto significativo en el rendimiento de una aplicación. Next.js viene con componentes integrados que los optimizan automáticamente.
Pasos de migración
Nuestro objetivo con esta migración es obtener una aplicación Next.js funcional lo más rápido posible, para que luego puedas adoptar las características de Next.js incrementalmente. Para empezar, la mantendremos como una aplicación puramente del lado del cliente (SPA) sin migrar tu enrutador existente. Esto ayuda a minimizar las posibilidades de encontrar problemas durante el proceso de migración y reduce los conflictos de fusión.
Paso 1: Instalar la dependencia de Next.js
Lo primero que necesitas hacer es instalar next
como dependencia:
Paso 2: Crear el archivo de configuración de Next.js
Crea un next.config.mjs
en la raíz de tu proyecto. Este archivo contendrá tus opciones de configuración de Next.js.
Bueno saber: Puedes usar tanto
.js
como.mjs
para tu archivo de configuración de Next.js.
Paso 3: Actualizar la configuración de TypeScript
Si estás usando TypeScript, necesitas actualizar tu archivo tsconfig.json
con los siguientes cambios para hacerlo compatible con Next.js. Si no estás usando TypeScript, puedes omitir este paso.
- Elimina la referencia del proyecto a
tsconfig.node.json
- Agrega
./dist/types/**/*.ts
y./next-env.d.ts
al arregloinclude
- Agrega
./node_modules
al arregloexclude
- Agrega
{ "name": "next" }
al arregloplugins
encompilerOptions
:"plugins": [{ "name": "next" }]
- Establece
esModuleInterop
atrue
:"esModuleInterop": true
- Establece
jsx
apreserve
:"jsx": "preserve"
- Establece
allowJs
atrue
:"allowJs": true
- Establece
forceConsistentCasingInFileNames
atrue
:"forceConsistentCasingInFileNames": true
- Establece
incremental
atrue
:"incremental": true
Aquí tienes un ejemplo de un tsconfig.json
funcional con esos cambios:
Puedes encontrar más información sobre la configuración de TypeScript en la documentación de Next.js.
Paso 4: Crear el diseño raíz
Una aplicación de App Router de Next.js debe incluir un archivo de diseño raíz, que es un Componente de Servidor React que envolverá todas las páginas de tu aplicación. Este archivo se define en el nivel superior del directorio app
.
El equivalente más cercano al archivo de diseño raíz en una aplicación Vite es el archivo index.html
, que contiene tus etiquetas <html>
, <head>
y <body>
.
En este paso, convertirás tu archivo index.html
en un archivo de diseño raíz:
- Crea un nuevo directorio
app
en tu carpetasrc
. - Crea un nuevo archivo
layout.tsx
dentro de ese directorioapp
:
Bueno saber: Se pueden usar extensiones
.js
,.jsx
o.tsx
para los archivos de diseño.
- Copia el contenido de tu archivo
index.html
en el componente<RootLayout>
creado anteriormente, reemplazando las etiquetasbody.div#root
ybody.script
con<div id="root">{children}</div>
:
- Next.js ya incluye por defecto las etiquetas meta charset y meta viewport, por lo que puedes eliminarlas de tu
<head>
:
- Cualquier archivo de metadatos como
favicon.ico
,icon.png
,robots.txt
se agrega automáticamente a la etiqueta<head>
de la aplicación siempre que los coloques en el nivel superior del directorioapp
. Después de mover todos los archivos admitidos al directorioapp
, puedes eliminar sus etiquetas<link>
:
- Finalmente, Next.js puede gestionar tus últimas etiquetas
<head>
con la API de Metadatos. Mueve tu información final de metadatos a un objetometadata
exportado:
Con los cambios anteriores, pasaste de declarar todo en tu index.html
a usar el enfoque basado en convenciones de Next.js integrado en el framework (API de Metadatos). Este enfoque te permite mejorar más fácilmente el SEO y la capacidad de compartir tus páginas en la web.
Paso 5: Crear la página de entrada (Entrypoint)
En Next.js, se declara un punto de entrada para la aplicación creando un archivo page.tsx
. El equivalente más cercano de este archivo en Vite es el archivo main.tsx
. En este paso, configurarás el punto de entrada de tu aplicación.
- Crea un directorio
[[...slug]]
dentro de tu directorioapp
.
Como en esta guía buscamos primero configurar Next.js como una SPA (Aplicación de Página Única), necesitas que el punto de entrada de tu página capture todas las rutas posibles de tu aplicación. Para ello, crea un nuevo directorio [[...slug]]
dentro de tu directorio app
.
Este directorio es lo que se conoce como un segmento de ruta opcional catch-all. Next.js utiliza un enrutador basado en el sistema de archivos donde las carpetas se usan para definir rutas. Este directorio especial asegurará que todas las rutas de tu aplicación sean dirigidas al archivo page.tsx
que contiene.
- Crea un nuevo archivo
page.tsx
dentro del directorioapp/[[...slug]]
con el siguiente contenido:
Nota importante: Se pueden usar las extensiones
.js
,.jsx
o.tsx
para los archivos de Página.
Este archivo es un Componente del Servidor (Server Component). Cuando ejecutas next build
, el archivo se prerenderiza en un recurso estático. No requiere ningún código dinámico.
Este archivo importa nuestro CSS global y le indica a generateStaticParams
que solo generaremos una ruta, la ruta de índice en /
.
Ahora, movamos el resto de nuestra aplicación Vite que se ejecutará solo en el cliente.
Este archivo es un Componente del Cliente (Client Component), definido por la directiva 'use client'
. Los Componentes del Cliente aún se prerenderizan a HTML en el servidor antes de enviarse al cliente.
Como queremos comenzar con una aplicación solo del cliente, podemos configurar Next.js para desactivar el prerenderizado desde el componente App
hacia abajo.
Ahora, actualiza tu página de entrada para usar el nuevo componente:
Paso 6: Actualizar las importaciones de imágenes estáticas
Next.js maneja las importaciones de imágenes estáticas de manera ligeramente diferente a Vite. Con Vite, importar un archivo de imagen devuelve su URL pública como una cadena:
Con Next.js, las importaciones de imágenes estáticas devuelven un objeto. Este objeto puede usarse directamente con el componente <Image>
de Next.js, o puedes usar la propiedad src
del objeto con tu etiqueta <img>
existente.
El componente <Image>
tiene los beneficios adicionales de la optimización automática de imágenes. El componente <Image>
establece automáticamente los atributos width
y height
del <img>
resultante basándose en las dimensiones de la imagen. Esto evita cambios de diseño cuando la imagen se carga. Sin embargo, esto puede causar problemas si tu aplicación contiene imágenes con solo una de sus dimensiones estilizada sin que la otra esté configurada como auto
. Cuando no está configurada como auto
, la dimensión tomará el valor predeterminado del atributo de dimensión del <img>
, lo que puede hacer que la imagen aparezca distorsionada.
Mantener la etiqueta <img>
reducirá la cantidad de cambios en tu aplicación y evitará los problemas mencionados. Luego, opcionalmente, puedes migrar al componente <Image>
para aprovechar la optimización de imágenes configurando un loader, o migrando al servidor predeterminado de Next.js que tiene optimización automática de imágenes.
- Convierte las rutas de importación absolutas para imágenes importadas desde
/public
en importaciones relativas:
- Pasa la propiedad
src
de la imagen en lugar del objeto completo a tu etiqueta<img>
:
Alternativamente, puedes referenciar la URL pública del recurso de imagen basado en el nombre del archivo. Por ejemplo, public/logo.png
servirá la imagen en /logo.png
para tu aplicación, que sería el valor de src
.
Advertencia: Si estás usando TypeScript, podrías encontrar errores de tipo al acceder a la propiedad
src
. Puedes ignorarlos de manera segura por ahora. Se solucionarán al final de esta guía.
Paso 7: Migrar las variables de entorno
Next.js tiene soporte para variables de entorno en archivos .env
similar a Vite. La principal diferencia es el prefijo usado para exponer variables de entorno en el lado del cliente.
- Cambia todas las variables de entorno con el prefijo
VITE_
aNEXT_PUBLIC_
.
Vite expone algunas variables de entorno integradas en el objeto especial import.meta.env
, que no son compatibles con Next.js. Debes actualizar su uso de la siguiente manera:
import.meta.env.MODE
⇒process.env.NODE_ENV
import.meta.env.PROD
⇒process.env.NODE_ENV === 'production'
import.meta.env.DEV
⇒process.env.NODE_ENV !== 'production'
import.meta.env.SSR
⇒typeof window !== 'undefined'
Next.js tampoco proporciona una variable de entorno BASE_URL
integrada. Sin embargo, aún puedes configurar una si la necesitas:
- Añade lo siguiente a tu archivo
.env
:
- Configura
basePath
comoprocess.env.NEXT_PUBLIC_BASE_PATH
en tu archivonext.config.mjs
:
- Actualiza los usos de
import.meta.env.BASE_URL
aprocess.env.NEXT_PUBLIC_BASE_PATH
Paso 8: Actualizar los scripts en package.json
Ahora deberías poder ejecutar tu aplicación para probar si migraste exitosamente a Next.js. Pero antes, necesitas actualizar los scripts
en tu package.json
con comandos relacionados a Next.js, y añadir .next
y next-env.d.ts
a tu .gitignore
:
Ahora ejecuta npm run dev
y abre http://localhost:3000
. Deberías ver tu aplicación ejecutándose ahora en Next.js.
Ejemplo: Revisa esta solicitud de extracción (pull request) para ver un ejemplo funcional de una aplicación Vite migrada a Next.js.
Paso 9: Limpieza
Ahora puedes limpiar tu código de los artefactos relacionados con Vite:
- Elimina
main.tsx
- Elimina
index.html
- Elimina
vite-env.d.ts
- Elimina
tsconfig.node.json
- Elimina
vite.config.ts
- Desinstala las dependencias de Vite
Próximos pasos
Si todo salió según lo planeado, ahora tienes una aplicación Next.js funcional que se ejecuta como una aplicación de página única. Sin embargo, aún no estás aprovechando la mayoría de los beneficios de Next.js, pero ahora puedes comenzar a hacer cambios incrementales para obtenerlos. Esto es lo que podrías hacer a continuación: