Saltearse al contenido

Enrutamiento

Astro utiliza enrutamiento basado en archivos para generar las URLs finales según el contenido de la carpeta src/pages/.

Astro usa elementos HTML estándar <a> para navegar entre rutas. No se proporciona ningún componente <Link> específico en Astro.

src/pages/index.astro
<p>¡Leer más <a href="/about/">sobre</a> Astro!</p>

Los componentes página .astro así como los archivos Markdown y MDX (.md, .mdx) dentro del directorio src/pages/ se convierten automáticamente en páginas de tu sitio web. La ruta de cada página corresponde a su ruta y nombre de archivo dentro del directorio src/pages/.

# Ejemplo: Rutas estáticas
src/pages/index.astro -> mysite.com/
src/pages/about.astro -> mysite.com/about
src/pages/about/index.astro -> mysite.com/about
src/pages/about/me.astro -> mysite.com/about/me
src/pages/posts/1.md -> mysite.com/posts/1

Un archivo de página Astro puede especificar parámetros de ruta dinámicos en su nombre para generar múltiples páginas emparejadas. Por ejemplo, src/pages/authors/[author].astro que generará una página por cada autor en tu blog. author se convierte en un parámetro al que puedes acceder dentro de la página.

En el modo de generación estático por defecto de Astro, estas páginas serán generadas en tiempo de compilación, así que deberías definir previamente la lista de authors para ese archivo. En modo SSR, se generará una página bajo petición para cada ruta que coincida.

Debido a que todas las rutas deben definirse en tiempo de compilación, una ruta dinámica debe exportar una función getStaticPaths() que devuelva un array de objetos con una propiedad params. Cada uno de estos objetos generará su ruta correspondiente.

[dogs].astro define el parámetro dinámico dog en su nombre de archivo, así que los objetos devueltos por getStaticPaths() deben incluir dog en sus params. De esta manera la página puede acceder a este parámetro por medio de Astro.params.

src/pages/dogs/[dog].astro
---
export function getStaticPaths() {
return [
{params: {dog: 'clifford'}},
{params: {dog: 'rover'}},
{params: {dog: 'spot'}},
];
}
const { dog } = Astro.params;
---
<div>¡Buen chico, {dog}!</div>

Esto generará tres páginas: /dogs/clifford, /dogs/rover y /dogs/spot, cada una mostrando el nombre de perro correspondiente.

El nombre de archivo puede incluir múltiples parámetros, los cuales deben estar todos incluidos en los objetos params de getStaticPaths():

src/pages/[lang]-[version]/info.astro
---
export function getStaticPaths () {
return [
{params: {lang: 'en', version: 'v1'}},
{params: {lang: 'fr', version: 'v2'}},
];
}
const { lang, version } = Astro.params;
---
...

Esto generará /en-v1/info y /fr-v2/info.

Los parámetros pueden incluirse en distintas partes del path. Por ejemplo, el archivo src/pages/[lang]/[version]/info.astro con la misma getStaticPaths() arriba generará las rutas /en/v1/info y /fr/v2/info.

Lee más sobre getStaticPaths().
Receta relacionada: Agrega características i18n

Si necesitas más flexibilidad en el enrutamiento de la URL, puedes usar un parámetro rest ([...param]) en el nombre de archivo .astro para emparejar rutas de archivos de cualquier profundidad:

src/pages/sequences/[...path].astro
---
export function getStaticPaths() {
return [
{params: {path: 'uno/dos/tres'}},
{params: {path: 'cuatro'}},
{params: {path: undefined }}
]
}
const { path } = Astro.params;
---
...

Esto generará /sequences/uno/dos/tres, /sequences/cuatro y /sequences. (Definir el parámetro restante como undefined permite emparejar con la página del nivel más alto.)

Los parámetros rest pueden usarse con otros parámetros nombrados. Por ejemplo, el visor de archivos de GitHub puede ser representado con la siguiente ruta dinámica:

/[org]/[repo]/tree/[branch]/[...file]

En este ejemplo, una solicitud a /withastro/astro/tree/main/docs/public/favicon.svg daría como resultado los siguientes parámetros con nombre:

{
org: 'withastro',
repo: 'astro',
branch: 'main',
file: 'docs/public/favicon.svg'
}

Ejemplo: Páginas dinámicas en múltiples niveles

Sección titulada Ejemplo: Páginas dinámicas en múltiples niveles

En el siguiente ejemplo, un parámetro rest ([...slug]) y la característica props de getStaticPaths() para generar páginas para slugs de diversa profundidad.

src/pages/[...slug].astro
---
export async function getStaticPaths() {
const pages = [
{
slug: undefined,
title: "Tienda de Astro",
text: "¡Te damos la bienvenida a la tienda de Astro!",
},
{
slug: "products",
title: "Productos de Astro",
text: "Tenemos muchos productos para ti",
},
{
slug: "products/astro-handbook",
title: "El libro definitivo de Astro",
text: "Si quieres aprender sobre Astro, debes leer este libro.",
},
];
return pages.map(({ slug, title, text }) => {
return {
params: { slug },
props: { title, text },
};
});
}
const { title, text } = Astro.props;
---
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<p>{text}</p>
</body>
</html>

En el modo SSR, las rutas dinámicas se definen de la misma manera: incluyendo [param] o [...path] en corchetes a los nombres de tus archivos para emparejar con strings o paths arbitrarios. Pero, como esas rutas no se compilan con anticipación, la página va a servirse con cualquier ruta que coincida. Como estas no son rutas “estáticas”, no debemos usar getStaticPaths.

src/pages/resources/[resource]/[id].astro
---
const { resource, id } = Astro.params;
---
<h1>{resource}: {id}<h1>

Esta página será servida para cualquier valor de resource y id: resources/users/1, resources/colors/blue, etc.

Modificando el ejemplo [...slug] para SSR

Sección titulada Modificando el ejemplo [...slug] para SSR

Debido a que las páginas SSR no pueden usar getStaticPaths, no pueden recibir props. El ejemplo anterior puede ser adaptado para el modo SSR buscando el valor del parámetro slug en un objeto. Si la ruta está en la raíz (”/”), el parámetro slug va a ser undefined. Si el valor no existe en el objeto, redirigiremos a una página 404.

src/pages/[...slug].astro
---
const pages = [
{
slug: undefined,
title: 'Tienda de Astro',
text: '¡Te damos la bienvenida a la tienda de Astro!',
},
{
slug: 'products',
title: 'Productos de Astro',
text: 'Tenemos muchos productos para ti',
},
{
slug: 'products/astro-handbook',
title: 'El libro definitivo de Astro',
text: 'Si quieres aprender sobre Astro, debes leer este libro.',
}
];
const { slug } = Astro.params;
const page = pages.find((page) => page.slug === slug);
if (!page) return Astro.redirect("/404");
const { title, text } = page;
---
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<p>{text}</p>
</body>
</html>

A veces necesitarás redirigir a tus lectores a una nueva página, ya sea de forma permanente debido a cambios en la estructura de tu sitio o como respuesta a una acción como iniciar sesión en una ruta autenticada.

Puedes definir reglas para redirigir a los usuarios a páginas movidas permanentemente en tu configuración de Astro. O puedes redirigir a los usuarios dinámicamente a medida que utilizan tu sitio.

Agregado en: astro@2.9.0

Puedes especificar un mapeo de redirecciones permanentes en la configuración de Astro con el valor redirects. Para la mayoría de las redirecciones, esto es un mapeo de una ruta antigua a la nueva ruta:

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
'/old-page': '/new-page'
}
});

Estas redirecciones siguen las mismas reglas que las rutas basadas en archivos. Se permiten rutas dinámicas siempre y cuando tanto las rutas nuevas como las antiguas contengan los mismos parámetros, por ejemplo:

{
"/blog/[...slug]": "/articles/[...slug]"
}

Usando SSR o un adaptador estático, también puedes proporcionar un objeto como valor, lo que te permite especificar el código de estado (status) además del nuevo destino (destination):

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
'/old-page': {
status: 302,
destination: '/new-page'
}
}
});

Al ejecutar astro build, Astro generará archivos HTML con la etiqueta meta refresh de forma predeterminada. En cambio, los adaptadores compatibles escribirán el archivo de configuración del host con las redirecciones.

Por defecto, el código de estado es 301. Si estás generando archivos HTML estáticos, el servidor no utiliza el código de estado.

En el objeto global Astro, el método Astro.redirect te permite redirigir a otra página de forma dinámica. Puedes hacer esto después de verificar si el usuario ha iniciado sesión obteniendo su sesión desde una cookie.

src/pages/account.astro
---
import { isLoggedIn } from '../utils';
const cookie = Astro.request.headers.get('cookie');
// Si el usuario no ha iniciado sesión, redirígelos a la página de inicio de sesión
if (!isLoggedIn(cookie)) {
return Astro.redirect('/login');
}
---
<html>
<!-- Aquí está la página... -->
</html>

Es posible que varias rutas definidas intenten construir la misma ruta de URL. Por ejemplo, todas estas rutas podrían construir /posts/create:

  • Directorysrc/pages/
    • […slug].astro
    • Directoryposts/
      • create.astro
      • [page].astro
      • [pid].ts
      • […slug].astro

Astro necesita saber qué ruta debe usarse para construir la página. Para ello, los ordena de acuerdo con las siguientes reglas en orden:

  • Las rutas con más segmentos de ruta tendrán prioridad sobre las rutas con menos parámetros. En el ejemplo anterior, todas las rutas bajo /posts/ tienen prioridad sobre /[...slug].astro en la raíz.
  • Las rutas estáticas sin parámetros de ruta tendrán prioridad sobre las rutas dinámicas. Por ejemplo, /posts/create.astro tiene prioridad sobre todas las demás rutas del ejemplo.
  • Las rutas dinámicas que usan parámetros nombrados tienen prioridad sobre los parámetros restantes. Por ejemplo, /posts/[page].astro tiene prioridad sobre /posts/[...slug].astro.
  • Las rutas dinámicas pre-renderizadas tienen prioridad sobre las rutas dinámicas del servidor.
  • Los endpoints tienen prioridad sobre las páginas.
  • Si ninguna de las reglas anteriores decide el orden, las rutas se ordenan alfabéticamente según la configuración regional predeterminada de tu instalación de Node.

Dado el ejemplo anterior, aquí hay algunos ejemplos de cómo las reglas harán coincidir una URL solicitada con la ruta utilizada al compilar el HTML:

  • pages/posts/create.astro - Solo construirá /posts/create
  • pages/posts/[pid].ts - Construirá /posts/abc, /posts/xyz, etc. Pero no /posts/create
  • pages/posts/[page].astro - Construirá /posts/1, /posts/2, etc. Pero no /posts/create, /posts/abc ni /posts/xyz
  • pages/posts/[...slug].ts - Construirá /posts/1/2, /posts/a/b/c, etc. Pero no /posts/create, /posts/1, /posts/abc, etc.
  • pages/[...slug].astro - Construirá /abc, /xyz, /abc/xyz, etc. Pero no /posts/create, /posts/1, /posts/abc, , etc.

Astro mantiene la paginación automática integrada para grandes colecciones de datos que deben dividirse en varias páginas. Astro incluirá automáticamente metadatos de paginación como la URL de la página anterior/siguiente, el número total de páginas y más.

Los nombres de rutas paginadas deben usar la misma sintaxis [corchete] que una ruta dinámica estándar. Por ejemplo, el nombre de archivo /astronautas/[page].astro generará rutas para /astronautas/1, /astronautas/2, etc., donde [page] es el número de página generado.

Puedes usar la función paginate() para generar estas páginas para un array de valores como este:

src/pages/astronauts/[page].astro
---
export async function getStaticPaths({ paginate }) {
const astronautPages = [{
astronaut: 'Neil Armstrong',
}, {
astronaut: 'Buzz Aldrin',
}, {
astronaut: 'Sally Ride',
}, {
astronaut: 'John Glenn',
}];
// Genera páginas para nuestro array de astronautas, con 2 elementos por página
return paginate(astronautPages, { pageSize: 2 });
}
// Todos los datos paginados se pasan en la prop "page"
const { page } = Astro.props;
---
<!--Muestra el número de página actual. ¡También puedes utilizar Astro.params.page!-->
<h1>Página {page.currentPage}</h1>
<ul>
<!--Enumera el array con información sobre astronautas-->
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>

Esto genera las siguientes páginas, con 2 elementos por página:

  • /astronauts/1 - Página 1: muestra “Neil Armstrong” y “Buzz Aldrin”
  • /astronauts/2 - Página 2: Muestra “Sally Ride” y “John Glenn”

Cuando usas la función paginate(), a cada página se le pasarán los datos a través de una prop page. La prop page tiene muchas propiedades útiles, pero estas son las más destacadas:

  • page.data - array que contiene la porción de datos de página que introdujo a la función paginate()
  • page.url.next - enlace a la página siguiente del mismo conjunto de datos
  • page.url.prev - enlace a la página anterior del mismo conjunto de datos
src/pages/astronauts/[page].astro
---
// Paginar la misma lista de objetos { astronaut } como en el ejemplo anterior
export async function getStaticPaths({ paginate }) { /* ... */ }
const { page } = Astro.props;
---
<h1>Página {page.currentPage}</h1>
<ul>
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>
{page.url.prev ? <a href={page.url.prev}>Anterior</a> : null}
{page.url.next ? <a href={page.url.next}>Siguiente</a> : null}
interface Page<T = any> {
/** resultado */
data: T[];
/** metadatos */
/** el recuento del primer elemento de la página, a partir de 0 */
start: number;
/** el recuento del último elemento de la página, a partir de 0 */
end: number;
/** el número total de resultados */
total: number;
/** el número de la página actual, a partir de 1 */
currentPage: number;
/** el número de elementos por página (predeterminado: 25) */
size: number;
/** el número de la última página */
lastPage: number;
url: {
/** la url de la página actual */
current: string;
/** la url de la página anterior (si hay alguna) */
prev: string | undefined;
/** la url de la página siguiente (si hay alguna) */
next: string | undefined;
};
}

Un caso de uso más avanzado de la paginación es la paginación anidada. Aquí es cuando la paginación se combina con otros parámetros de rutas dinámicas. Puedes usar la paginación anidada para agrupar la colección paginada por alguna propiedad o etiqueta.

Por ejemplo, si prefieres agrupar las publicaciones de Markdown paginadas por alguna etiqueta, usarás la paginación anidada creando una página /src/pages/[tag]/[page].astro que coincida con las siguientes URL:

  • /red/1 (tag=red)
  • /red/2 (tag=red)
  • /blue/1 (tag=blue)
  • /green/1 (tag=green)

La paginación anidada funciona devolviendo un array de resultados paginate() de getStaticPaths(), uno para cada grupo.

En el siguiente ejemplo, implementaremos la paginación anidada para crear las URL enumeradas anteriormente:

src/pages/[tag]/[page].astro
---
export async function getStaticPaths({paginate}) {
const allTags = ['rojo', 'azul', 'verde'];
const allPosts = await Astro.glob('../../posts/*.md');
// Para cada etiqueta, devuelve un resultado de paginate().
// Asegúrate de pasar `{params: {tag}}` a `paginate()`
// Así Astro sabrá qué agrupación de etiquetas usar.
return allTags.flatMap((tag) => {
const filteredPosts = allPosts.filter((post) => post.frontmatter.tag === tag);
return paginate(filteredPosts, {
params: { tag },
pageSize: 10
});
});
}
const { page } = Astro.props;
const params = Astro.params;

Puedes excluir la generación de páginas o directorios añadiendo el prefijo (_). Los archivos con el prefijo _ no serán reconocidos por el router y no serán generados en el directorio dist/.

Puedes usar esto para inhabilitar páginas temporalmente y también para poner tests, utilidades y componentes en la misma carpeta junto a sus páginas correspondientes.

En este ejemplo, solo src/pages/index.astro y src/pages/posts/post1.md serán generados como rutas y archivos .html.

  • Directorysrc/pages/
    • Directory_hidden-directory/
      • page1.md
      • page2.md
    • _hidden-page.astro
    • index.astro
    • Directoryposts/
      • _SomeComponent.astro
      • _utils.js
      • post1.md