Migrar desde NuxtJS
Aquí hay algunos conceptos clave y estrategias de migración para ayudarte a empezar. ¡Usa el resto de nuestra documentación y nuestra comunidad de Discord para seguir adelante!
Esta guía se refiere a Nuxt 2, no al más nuevo Nuxt 3. Aunque algunos de los conceptos son similares, Nuxt 3 es una versión más nueva del framework y puede requerir estrategias diferentes para partes de tu migración.
Similitudes clave entre Nuxt y Astro
Sección titulada “Similitudes clave entre Nuxt y Astro”Nuxt y Astro comparten algunas similitudes que te ayudarán a migrar tu proyecto:
- Los proyectos de Astro también pueden ser SSG o SSR con pre-renderizado a nivel de página.
- Astro usa enrutamiento basado en archivos, y permite que páginas con nombres especiales creen rutas dinámicas.
- Astro está basado en componentes, y tu estructura de markup será similar antes y después de tu migración.
- Astro tiene una integración oficial para usar componentes de Vue.
- Astro soporta instalar paquetes NPM, incluyendo librerías de Vue. Puede que puedas conservar algunos o todos tus componentes y dependencias de Vue existentes.
Diferencias clave entre Nuxt y Astro
Sección titulada “Diferencias clave entre Nuxt y Astro”Cuando reconstruyas tu sitio de Nuxt en Astro, notarás algunas diferencias importantes:
-
Nuxt es una SPA (single-page application) basada en Vue. Los sitios de Astro son apps multi-página construidas usando componentes
.astro, pero también pueden soportar React, Preact, Vue.js, Svelte, SolidJS, AlpineJS, y plantillas HTML crudo. -
Enrutamiento de páginas: Nuxt usa
vue-routerpara enrutamiento SPA, yvue-metapara gestionar<head>. En Astro, crearás rutas de páginas HTML separadas y controlarás el<head>de tu página directamente, o en un componente de layout. -
orientado a contenido: Astro fue diseñado para mostrar tu contenido y permitirte optar por la interactividad solo cuando sea necesario. Una app existente de Nuxt puede estar construida para alta interactividad del lado del cliente. Astro tiene capacidades integradas para trabajar con tu contenido, como la generación de páginas, pero puede requerir técnicas avanzadas de Astro para incluir elementos que son más difíciles de replicar usando componentes
.astro, como dashboards.
Convierte tu proyecto de NuxtJS
Sección titulada “Convierte tu proyecto de NuxtJS”Cada migración de proyecto será diferente, pero hay algunas acciones comunes que realizarás al convertir de Nuxt a Astro.
Crea un nuevo proyecto de Astro
Sección titulada “Crea un nuevo proyecto de Astro”Usa el comando create astro de tu gestor de paquetes para lanzar el asistente CLI de Astro o elige un tema de la comunidad del Astro Theme Showcase.
Puedes pasar un argumento --template al comando create astro para iniciar un nuevo proyecto de Astro con uno de nuestros starters oficiales (p. ej. docs, blog, portfolio). O, puedes iniciar un nuevo proyecto desde cualquier repositorio existente de Astro en GitHub.
# launch the Astro CLI Wizardnpm create astro@latest
# create a new project with an official examplenpm create astro@latest -- --template <example-name># launch the Astro CLI Wizardpnpm create astro@latest
# create a new project with an official examplepnpm create astro@latest --template <example-name># launch the Astro CLI Wizardyarn create astro@latest
# create a new project with an official exampleyarn create astro@latest --template <example-name>Luego, copia los archivos existentes de tu proyecto de Nuxt a tu nuevo proyecto de Astro en una carpeta separada fuera de src.
Visita https://astro.new para la lista completa de plantillas oficiales de inicio, y enlaces para abrir un nuevo proyecto en StackBlitz o CodeSandbox.
Instalar integraciones (opcional)
Sección titulada “Instalar integraciones (opcional)”Puede que te resulte útil instalar algunas de las integraciones opcionales de Astro para usar mientras conviertes tu proyecto de Nuxt a Astro:
-
@astrojs/vue: para reutilizar algunos componentes de UI de Vue existentes en tu nuevo sitio de Astro, o seguir escribiendo con componentes de Vue.
-
@astrojs/mdx: para traer archivos MDX existentes de tu proyecto de Nuxt, o para usar MDX en tu nuevo sitio de Astro.
Pon tu código fuente en src
Sección titulada “Pon tu código fuente en src”-
Mueve el contenido de la carpeta
static/de Nuxt apublic/.Astro usa el directorio
public/para assets estáticos, similar a la carpetastatic/de Nuxt. -
Copia o mueve otros archivos y carpetas de Nuxt (p. ej.
pages,layoutsetc.) a la carpetasrc/de Astro.Como Nuxt, la carpeta
src/pages/de Astro es una carpeta especial usada para enrutamiento basado en archivos. Todas las demás carpetas son opcionales, y puedes organizar el contenido de tu carpetasrc/como quieras. Otras carpetas comunes en proyectos de Astro incluyensrc/layouts/,src/components,src/styles,src/scripts.
Convertir páginas Vue SFC a archivos .astro
Sección titulada “Convertir páginas Vue SFC a archivos .astro”Aquí hay algunos tips para convertir un componente .vue de Nuxt en un componente .astro:
-
Usa el
<template>de la función del componente existente de NuxtJS como base para tu plantilla HTML. -
Cambia cualquier sintaxis de Nuxt o Vue a sintaxis de Astro o a estándares web de HTML. Esto incluye
<NuxtLink>,:class,{{variable}}, yv-if, por ejemplo. -
Mueve el JavaScript de
<script>a un “code fence” (---). Convierte las propiedades de data-fetching de tu componente a JavaScript del lado del servidor - consulta Data fetching de Nuxt a Astro. -
Usa
Astro.propspara acceder a cualquier prop adicional que se pasara previamente a tu componente de Vue. -
Decide si algún componente importado también necesita convertirse a Astro. Con la integración oficial instalada, puedes usar componentes de Vue existentes en tu archivo de Astro. Pero, puede que quieras convertirlos a Astro, ¡especialmente si no necesitan ser interactivos!
Ve un ejemplo de una app Nuxt convertida paso a paso.
Comparar: Vue vs Astro
Sección titulada “Comparar: Vue vs Astro”Compara el siguiente componente de Nuxt y un componente de Astro correspondiente:
<template> <div> <p v-if="message === 'Not found'"> The repository you're looking up doesn't exist </p> <div v-else> <Header/> <p class="banner">Astro has {{stars}} 🧑🚀</p> <Footer /> </div> </div></template>
<script>import Vue from 'vue'
export default Vue.extend({ name: 'IndexPage', async asyncData() { const res = await fetch('https://api.github.com/repos/withastro/astro') const json = await res.json(); return { message: json.message, stars: json.stargazers_count || 0, }; }});</script>
<style scoped>.banner { background-color: #f4f4f4; padding: 1em 1.5em; text-align: center; margin-bottom: 1em;}</style>---import Header from "./header";import Footer from './footer';import "./layout.css";
const res = await fetch('https://api.github.com/repos/withastro/astro')const json = await res.json()const message = json.message;const stars = json.stargazers_count || 0;---
{message === "Not Found" ? <p>The repository you're looking up doesn't exist</p> : <> <Header /> <p class="banner">Astro has {stars} 🧑🚀</p> <Footer /> </>}
<style> .banner { background-color: #f4f4f4; padding: 1em 1.5em; text-align: center; margin-bottom: 1em; }</style>Migrar archivos de layout
Sección titulada “Migrar archivos de layout”Puede que te resulte útil comenzar convirtiendo tus layouts y plantillas de Nuxt en componentes de layout de Astro.
Cada página de Astro requiere explícitamente que las etiquetas <html>, <head>, y <body> estén presentes. Tu layout.vue y plantillas de Nuxt no incluirán estos.
Ten en cuenta las plantillas HTML estándar, y el acceso directo a <head>:
<html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> <title>Astro</title> </head> <body> <!-- Wrap the slot element with your existing layout templating --> <slot /> </body></html>También puedes querer reutilizar código de la propiedad head de la página de Nuxt para incluir metadatos adicionales del sitio. Ten en cuenta que Astro no usa vue-meta ni la propiedad head de un componente sino que crea <head> directamente. Puedes importar y usar componentes, incluso dentro de <head>, para separar y organizar el contenido de tu página.
Migrar páginas y posts
Sección titulada “Migrar páginas y posts”En NuxtJS, tus pages viven en /pages. En Astro, todo el contenido de tus páginas debe vivir dentro de src/ a menos que uses content collections.
Páginas de Vue
Sección titulada “Páginas de Vue”Tus páginas Vue (.vue) de Nuxt existentes necesitarán ser convertidas de archivos Vue a páginas .astro. No puedes usar un archivo de página Vue existente en Astro.
Estas páginas .astro deben estar ubicadas dentro de src/pages/ y tendrán rutas de página generadas automáticamente basadas en su ruta de archivo.
Nomenclatura dinámica de rutas de archivo
Sección titulada “Nomenclatura dinámica de rutas de archivo”En Nuxt, tus páginas dinámicas usan un guión bajo para representar una propiedad de página dinámica que luego se pasa a la generación de páginas:
Directoriopages/
Directorypokemon/
- _name.vue
- index.vue
- nuxt.config.js
Para convertir a Astro, cambia esta propiedad de ruta dinámica con guión bajo (p. ej. _name.vue) para envolverla en un par de corchetes (p. ej. [name].astro):
Directoriosrc/
Directoriopages/
Directorypokemon/
- [name].astro
- index.astro
- astro.config.mjs
Páginas Markdown y MDX
Sección titulada “Páginas Markdown y MDX”Astro tiene soporte integrado para Markdown y una integración opcional para archivos MDX. Puedes reutilizar cualquier página Markdown y MDX existente, pero pueden requerir algunos ajustes en su frontmatter, como añadir la propiedad especial de frontmatter layout de Astro.
Ya no necesitarás crear páginas manualmente para cada ruta generada por Markdown o usar un paquete externo como @nuxt/content. Estos archivos pueden colocarse dentro de src/pages/ para aprovechar el enrutamiento automático basado en archivos.
Cuando son parte de una content collection, generarás páginas dinámicamente desde tus entradas de contenido.
Migrar tests
Sección titulada “Migrar tests”Como Astro devuelve HTML crudo, es posible escribir tests end-to-end usando la salida del paso de build. Cualquier test end-to-end escrito previamente podría funcionar out-of-the-box, si has podido igualar el markup de tu sitio de Nuxt. Librerías de testing como Jest y Vue Testing Library pueden importarse y usarse en Astro para testear tus componentes de Vue.
Consulta la guía de testing de Astro para más.
Referencia: Convertir sintaxis de NuxtJS a Astro
Sección titulada “Referencia: Convertir sintaxis de NuxtJS a Astro”Variables locales de Nuxt a Astro
Sección titulada “Variables locales de Nuxt a Astro”Para usar variables locales en el HTML de un componente de Astro, cambia el conjunto de dos llaves por un único conjunto de llaves:
---const message = "Hello!"---<p>{{message}}</p><p>{message}</p>Paso de props de Nuxt a Astro
Sección titulada “Paso de props de Nuxt a Astro”Para vincular un atributo o propiedad de componente en un componente de Astro, cambia esta sintaxis a lo siguiente:
------<p v-bind:aria-label="message">...</p><!-- Or --><p :aria-label="message">...</p><!-- Also support component props --><Header title="Page"/>
<p aria-label={message}>...</p><!-- Also support component props --><Header title={"Page"}/>Links de Nuxt a Astro
Sección titulada “Links de Nuxt a Astro”Convierte cualquier componente <NuxtLink to=""> de Nuxt a etiquetas HTML <a href="">.
<NuxtLink to="/blog">Blog</Link><a href="/blog">Blog</a>Astro no usa ningún componente especial para links, aunque eres libre de construir componentes de link personalizados. Luego puedes importar y usar este <Link> igual que cualquier otro componente.
---const { to } = Astro.props---<a href={to}><slot /></a>Imports de Nuxt a Astro
Sección titulada “Imports de Nuxt a Astro”Si es necesario, actualiza cualquier importación de archivos para referenciar rutas de archivos relativas exactamente. Esto se puede hacer usando alias de importación, o escribiendo una ruta relativa completa.
Ten en cuenta que los archivos .astro y varios otros tipos de archivo deben importarse con su extensión completa.
---import Card from `../../components/Card.astro`;---<Card />Generación de páginas dinámicas de Nuxt a Astro
Sección titulada “Generación de páginas dinámicas de Nuxt a Astro”En Nuxt, para generar una página dinámica debes:
- Usar SSR.
- Usa la función
generateennuxt.config.jspara definir todas las rutas estáticas posibles.
En Astro, de manera similar tienes dos opciones:
- Usar SSR.
- Exporta una función
getStaticPaths()en el frontmatter de una página de Astro para indicar al framework qué rutas estáticas generar dinámicamente.
Convierte una función generate de Nuxt a una función getStaticPaths de Astro.
Sección titulada “Convertir una función generate de Nuxt a una función getStaticPaths de Astro.”Para generar múltiples páginas, reemplaza la función para crear rutas en tu nuxt.config.js con getStaticPaths() directamente dentro de una página de enrutamiento dinámico:
{ // ... generate: { async routes() { // Axios is required here unless you're using Node 18 const res = await axios.get("https://pokeapi.co/api/v2/pokemon?limit=151") const pokemons = res.data.results; return pokemons.map(pokemon => { return '/pokemon/' + pokemon.name }) } }}---export const getStaticPaths = async () => { const res = await fetch("https://pokeapi.co/api/v2/pokemon?limit=151") const resJson = await res.json(); const pokemons = resJson.results; return pokemons.map(({ name }) => ({ params: { name }, }))}// ...---<!-- Your template here -->Data Fetching de Nuxt a Astro
Sección titulada “Data Fetching de Nuxt a Astro”Nuxt tiene dos métodos para obtener datos del lado del servidor:
En Astro, obtén los datos dentro del code fence de tu página.
Migra lo siguiente:
{ // ... async asyncData() { const res = await fetch("https://pokeapi.co/api/v2/pokemon?limit=151") const resJson = await res.json(); const pokemons = resJson.results; return { pokemons, } },}A un code fence sin una función wrapper:
---const res = await fetch("https://pokeapi.co/api/v2/pokemon?limit=151")const resJson = await res.json();const pokemons = resJson.results;---
<!-- Your template here -->Styling de Nuxt a Astro
Sección titulada “Styling de Nuxt a Astro”Nuxt utiliza el styling de componentes de Vue para generar el estilo de una página.
<template> <!-- Your template here --></template>
<script> // Your server logic here</script>
<style scoped> .class { color: red; }</style>De manera similar, en Astro puedes añadir un elemento <style> en la plantilla de tu página para proporcionar estilos con scope al componente.
---// Your server logic here---
<style> .class { color: red; }</style>Styling global
Sección titulada “Styling global”Las etiquetas <style> tienen scope por defecto en Astro. Para hacer que una etiqueta <style> sea global, márcala con el atributo is:global:
<style is:global> p { color: red; }</style>Soporte de pre-procesadores
Sección titulada “Soporte de pre-procesadores”Astro soporta los pre-procesadores CSS más populares instalándolos como una dependencia de desarrollo. Por ejemplo, para usar SCSS:
npm install -D sassDespués de hacer esto, podrás usar estilos .scss o .sass sin modificaciones desde tus componentes de Vue.
<p>Hello, world</p><style lang="scss">p { color: black;
&:hover { color: red; }}</style>Ve más sobre estilos en Astro.
Nuxt Image Plugin a Astro
Sección titulada “Nuxt Image Plugin a Astro”Convierte cualquier componente Nuxt <nuxt-img/> o <nuxt-picture/> a el propio componente de imagen de Astro en archivos .astro o .mdx, o a una etiqueta HTML estándar <img> o <picture> según corresponda en tus componentes de Vue.
El componente <Image /> de Astro funciona solo en archivos .astro y .mdx. Consulta una lista completa de sus atributos de componente y ten en cuenta que varios diferirán de los atributos de Nuxt.
---import { Image } from 'astro:assets';import rocket from '../assets/rocket.png';---<Image src={rocket} alt="A rocketship in space." /><img src={rocket.src} alt="A rocketship in space.">En componentes de Vue (.vue) dentro de tu app de Astro, usa sintaxis de imagen JSX estándar (<img />). Astro no optimizará estas imágenes, pero puedes instalar y usar paquetes NPM para más flexibilidad.
Puedes aprender más sobre el uso de imágenes en Astro en la guía de Images.
Ejemplo guiado: ¡Mira los pasos!
Sección titulada “Ejemplo guiado: ¡Mira los pasos!”Aquí hay un ejemplo de data fetching de la Pokédex de Nuxt convertido a Astro.
pages/index.vue obtiene y muestra una lista de los primeros 151 Pokémon usando la REST PokéAPI.
Aquí te mostramos cómo recrear eso en src/pages/index.astro, reemplazando asyncData() con fetch().
-
Identifica el
<template>y el<style>en el SFC de Vue.pages/index.vue <template><ul class="plain-list pokeList"><li v-for="pokemon of pokemons" class="pokemonListItem" :key="pokemon.name"><NuxtLink class="pokemonContainer" :to="`/pokemon/${pokemon.name}`"><p class="pokemonId">No. {{pokemon.id}}</p><imgclass="pokemonImage":src="`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`":alt="`${pokemon.name} picture`"/><h2 class="pokemonName">{{pokemon.name}}</h2></NuxtLink></li></ul></template><script>import Vue from 'vue'export default Vue.extend({name: 'IndexPage',layout: 'default',async asyncData() {const res = await fetch("https://pokeapi.co/api/v2/pokemon?limit=151")const resJson = await res.json();const pokemons = resJson.results.map(pokemon => {const name = pokemon.name;// https://pokeapi.co/api/v2/pokemon/1/const url = pokemon.url;const id = url.split("/")[url.split("/").length - 2];return {name,url,id}});return {pokemons,}},head() {return {title: "Pokedex: Generation 1"}}});</script><style scoped>.pokeList {display: grid;grid-template-columns: repeat( auto-fit, minmax(250px, 1fr) );gap: 1rem;}/* ... */</style> -
Crea
src/pages/index.astroUsa las etiquetas
<template>y<style>del SFC de Nuxt. Convierte cualquier sintaxis de Nuxt o Vue a Astro.Ten en cuenta que:
-
El
<template>se elimina -
El
<style>tiene su atributoscopedeliminado -
v-forse convierte en.map. -
:attr="val"se convierte enattr={val} -
<NuxtLink>se convierte en<a>. -
El fragment
<> </>no es necesario en las plantillas de Astro.
src/pages/index.astro ------<ul class="plain-list pokeList">{pokemons.map((pokemon) => (<li class="pokemonListItem" key={pokemon.name}><a class="pokemonContainer" href={`/pokemon/${pokemon.name}`}><p class="pokemonId">No. {pokemon.id}</p><img class="pokemonImage" src={`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`} alt={`${pokemon.name} picture`}/><h2 class="pokemonName">{pokemon.name}</h2></a></li>))}</ul><style>.pokeList {display: grid;grid-template-columns: repeat( auto-fit, minmax(250px, 1fr) );gap: 1rem;}/* ... */</style> -
-
Añade cualquier import, prop y JavaScript necesario
Ten en cuenta que:
- La función
asyncDataya no es necesaria. Los datos de la API se obtienen directamente en el code fence. - A
<Layout>component is imported, and wraps the page templating.- Nuestro método
head()de Nuxt se pasa al componente<Layout>, que se pasa al elemento<title>como una propiedad.
- Nuestro método
src/pages/index.astro ---import Layout from '../layouts/layout.astro';const res = await fetch("https://pokeapi.co/api/v2/pokemon?limit=151");const resJson = await res.json();const pokemons = resJson.results.map(pokemon => {const name = pokemon.name;// https://pokeapi.co/api/v2/pokemon/1/const url = pokemon.url;const id = url.split("/")[url.split("/").length - 2];return {name,url,id}});---<Layout title="Pokedex: Generation 1"><ul class="plain-list pokeList">{pokemons.map((pokemon) => (<li class="pokemonListItem" key={pokemon.name}><a class="pokemonContainer" href={`/pokemon/${pokemon.name}`}><p class="pokemonId">No. {pokemon.id}</p><img class="pokemonImage" src={`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png`} alt={`${pokemon.name} picture`}/><h2 class="pokemonName">{pokemon.name}</h2></a></li>))}</ul></Layout><style>.pokeList {display: grid;grid-template-columns: repeat( auto-fit, minmax(250px, 1fr) );gap: 1rem;}/* ... */</style> - La función
Recursos de la comunidad
Sección titulada "Recursos de la comunidad"Si encontraste (¡o hiciste!) un video o blog post útil sobre convertir un sitio de Nuxt a Astro, añádelo a esta lista!