Saltar al contenido

@astrojs/ markdoc

Esta integración de Astro habilita el uso de Markdoc para crear componentes, páginas y entradas de colecciones de contenido.

Markdoc te permite mejorar tu Markdown con componentes de Astro. Si tienes contenido existente escrito en Markdoc, esta integración te permite llevar esos archivos a tu proyecto de Astro utilizando colecciones de contenido.

Astro incluye un comando astro add para automatizar la configuración de las integraciones oficiales. Si lo prefieres, puedes instalar las integraciones manualmente en su lugar.

Ejecuta uno de los siguientes comandos en una nueva ventana de terminal.

Ventana de la terminal
npx astro add markdoc

Si tienes algún problema, no dudes en informarnos en GitHub e intenta los pasos de instalación manual a continuación.

Primero, instala el paquete @astrojs/markdoc:

Ventana de la terminal
npm install @astrojs/markdoc

Luego, aplica la integración a tu archivo astro.config.* usando la propiedad integrations:

astro.config.mjs
import { defineConfig } from 'astro/config';
import markdoc from '@astrojs/markdoc';
export default defineConfig({
// ...
integrations: [markdoc()],
});

Si usas VS Code, existe una extensión de lenguaje oficial de Markdoc que incluye resaltado de sintaxis y autocompletado para las etiquetas configuradas. Consulta el servidor de lenguaje en GitHub para obtener más información.

Para configurar la extensión, crea un archivo markdoc.config.json en la raíz del proyecto con el siguiente contenido:

markdoc.config.json
[
{
"id": "my-site",
"path": "src/content",
"schema": {
"path": "markdoc.config.mjs",
"type": "esm",
"property": "default",
"watch": true
}
}
]

Establece markdoc.config.mjs como tu archivo de configuración con el objeto schema, y define dónde se almacenan tus archivos Markdoc usando la propiedad path. Dado que Markdoc es específico de las colecciones de contenido, puedes usar src/content.

Los archivos de Markdoc solo se pueden usar dentro de colecciones de contenido. Agrega entradas a cualquier colección de contenido usando la extensión .mdoc:

  • Directoriosrc/
    • Directoriocontent/
      • Directoriodocs/
        • why-markdoc.mdoc
        • quick-start.mdoc

Luego, consulta y muestra tus publicaciones y colecciones:

src/pages/why-markdoc.astro
---
import { getEntry, render } from 'astro:content';
const entry = await getEntry('docs', 'why-markdoc');
const { Content } = await render(entry);
---
<!--Access frontmatter properties with `data`-->
<h1>{entry.data.title}</h1>
<!--Render Markdoc contents with the Content component-->
<Content />
Consulta la documentación de Colecciones de contenido de Astro para obtener más información.

Es posible que necesites pasar variables a tu contenido. Esto es útil al pasar parámetros de SSR como pruebas A/B.

Las variables se pueden pasar como props a través del componente Content:

src/pages/why-markdoc.astro
---
import { getEntry, render } from 'astro:content';
const entry = await getEntry('docs', 'why-markdoc');
const { Content } = await render(entry);
---
<!--Pass the `abTest` param as a variable-->
<Content abTestGroup={Astro.params.abTestGroup} />

Ahora, abTestGroup está disponible como una variable en docs/why-markdoc.mdoc:

src/content/docs/why-markdoc.mdoc
{% if $abTestGroup === 'image-optimization-lover' %}
Let me tell you about image optimization...
{% /if %}

Para hacer que una variable sea global para todos los archivos Markdoc, puedes usar el atributo variables de tu markdoc.config.mjs|ts:

markdoc.config.mjs
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
variables: {
environment: process.env.IS_PROD ? 'prod' : 'dev',
},
});

Acceder al frontmatter desde tu contenido de Markdoc

Sección titulada «Acceder al frontmatter desde tu contenido de Markdoc»

Para acceder al frontmatter, puedes pasar la propiedad data de la entrada como una variable donde renderizas tu contenido:

src/pages/why-markdoc.astro
---
import { getEntry, render } from 'astro:content';
const entry = await getEntry('docs', 'why-markdoc');
const { Content } = await render(entry);
---
<Content frontmatter={entry.data} />

Esto ahora se puede acceder como $frontmatter en tu Markdoc.

@astrojs/markdoc ofrece opciones de configuración para usar todas las características de Markdoc y conectar componentes de interfaz de usuario a tu contenido.

Usar componentes de Astro como etiquetas de Markdoc

Sección titulada «Usar componentes de Astro como etiquetas de Markdoc»

Puedes configurar etiquetas de Markdoc que se mapean a componentes .astro. Puedes añadir una nueva etiqueta creando un archivo markdoc.config.mjs|ts en la raíz de tu proyecto y configurando el atributo tag.

Este ejemplo renderiza un componente Aside y permite pasar una prop type como una cadena de texto:

markdoc.config.mjs
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
tags: {
aside: {
render: component('./src/components/Aside.astro'),
attributes: {
// Markdoc requires type defs for each attribute.
// These should mirror the `Props` type of the component
// you are rendering.
// See Markdoc's documentation on defining attributes
// https://markdoc.dev/docs/attributes#defining-attributes
type: { type: String },
},
},
},
});

Este componente ahora se puede usar en tus archivos Markdoc con la etiqueta {% aside %}. Los elementos hijos se pasarán al slot por defecto de tu componente:

# Welcome to Markdoc 👋
{% aside type="tip" %}
Use tags like this fancy "aside" to add some _flair_ to your docs.
{% /aside %}

Usar componentes de interfaz de usuario del lado del cliente

Sección titulada «Usar componentes de interfaz de usuario del lado del cliente»

Las etiquetas y los nodos están restringidos a archivos .astro. Para integrar componentes de interfaz de usuario del lado del cliente en Markdoc, usa un componente wrapper .astro que renderice un componente de framework con la directiva client: deseada.

Este ejemplo envuelve un componente React Aside.tsx con un componente ClientAside.astro:

src/components/ClientAside.astro
---
import Aside from './Aside';
---
<Aside {...Astro.props} client:load />

Este componente de Astro ahora se puede pasar a la prop render para cualquier tag o node en tu configuración:

markdoc.config.mjs
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
tags: {
aside: {
render: component('./src/components/ClientAside.astro'),
attributes: {
type: { type: String },
},
},
},
});

Usar componentes de Astro desde paquetes de npm y archivos de TypeScript

Sección titulada «Usar componentes de Astro desde paquetes de npm y archivos de TypeScript»

Es posible que necesites utilizar componentes de Astro expuestos como exportaciones con nombre desde archivos TypeScript o JavaScript. Esto es común cuando se utilizan paquetes de npm y sistemas de diseño.

Puedes pasar el nombre de la importación como segundo argumento a la función component():

markdoc.config.mjs
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
tags: {
tabs: {
render: component('@astrojs/starlight/components', 'Tabs'),
},
},
});

Esto genera la siguiente declaración de importación internamente:

import { Tabs } from '@astrojs/starlight/components';

La etiqueta {% partial /%} te permite renderizar otros archivos .mdoc dentro de tu contenido de Markdoc.

Esto es útil para reutilizar contenido en múltiples documentos, y te permite tener archivos de contenido .mdoc que no sigan el esquema de tu colección.

Este ejemplo muestra un parcial de Markdoc para un pie de página que se utilizará dentro de las entradas de la colección de blogs:

src/content/blog/_footer.mdoc
Social links:
- [Twitter / X](https://twitter.com/astrodotbuild)
- [Discord](https://astro.build/chat)
- [GitHub](https://github.com/withastro/astro)

Usa la etiqueta {% partial /%} para renderizar el pie de página al final de una entrada de blog. Aplica el atributo file con la ruta al archivo, utilizando una ruta relativa o un alias de importación:

src/content/blog/post.mdoc
# My Blog Post
{% partial file="./_footer.mdoc" /%}

@astrojs/markdoc proporciona extensiones de Shiki y Prism para resaltar tus bloques de código.

Aplica la extensión shiki() a tu configuración de Markdoc usando la propiedad extends. Opcionalmente, puedes pasar un objeto de configuración de Shiki:

markdoc.config.mjs
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
import shiki from '@astrojs/markdoc/shiki';
export default defineMarkdocConfig({
extends: [
shiki({
// Choose from Shiki's built-in themes (or add your own)
// Default: 'github-dark'
// https://shiki.style/themes
theme: 'dracula',
// Enable word wrap to prevent horizontal scrolling
// Default: false
wrap: true,
// Pass custom languages
// Note: Shiki has countless langs built-in, including `.astro`!
// https://shiki.style/languages
langs: [],
}),
],
});

Aplica la extensión prism() a tu configuración de Markdoc usando la propiedad extends.

markdoc.config.mjs
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
import prism from '@astrojs/markdoc/prism';
export default defineMarkdocConfig({
extends: [prism()],
});
Para obtener información sobre cómo configurar las hojas de estilo de Prism, consulta nuestra guía de resaltado de sintaxis.

Es posible que desees renderizar elementos estándar de Markdown, como párrafos y texto en negrita, como componentes de Astro. Para ello, puedes configurar un nodo de Markdoc. Si un nodo dado recibe atributos, estos estarán disponibles como props del componente.

Este ejemplo renderiza citas de bloque con un componente personalizado Quote.astro:

markdoc.config.mjs
import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
nodes: {
blockquote: {
...nodes.blockquote, // Apply Markdoc's defaults for other options
render: component('./src/components/Quote.astro'),
},
},
});
Consulta la documentación de nodos de Markdoc para conocer todos los nodos y atributos incorporados.

@astrojs/markdoc añade automáticamente enlaces de anclaje a tus encabezados y genera una lista de encabezados a través de la API de colecciones de contenido. Para personalizar aún más cómo se renderizan los encabezados, puedes aplicar un componente de Astro como un nodo de Markdoc.

Este ejemplo renderiza un componente Heading.astro usando la propiedad render:

markdoc.config.mjs
import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
nodes: {
heading: {
...nodes.heading, // Preserve default anchor link generation
render: component('./src/components/Heading.astro'),
},
},
});

Todos los encabezados de Markdown renderizarán el componente Heading.astro y pasarán los siguientes atributos como props del componente:

  • level: number El nivel de encabezado 1 - 6
  • id: string Un id generado a partir del contenido de texto del encabezado. Esto corresponde al slug generado por la función render() de contenido.

Por ejemplo, el encabezado ### Level 3 heading! pasará level: 3 y id: 'level-3-heading' como props del componente.

El componente <Image /> de Astro no se puede utilizar directamente en Markdoc. Sin embargo, puedes configurar un componente de Astro para sobrescribir el nodo de imagen predeterminado cada vez que se use la sintaxis de imagen nativa ![](), o como una etiqueta personalizada de Markdoc para permitirte especificar atributos de imagen adicionales.

Sobrescribir el nodo de imagen predeterminado de Markdoc

Sección titulada «Sobrescribir el nodo de imagen predeterminado de Markdoc»

Para sobrescribir el nodo de imagen predeterminado, puedes configurar un componente .astro para que se renderice en lugar de un <img> estándar.

  1. Crea un componente personalizado MarkdocImage.astro para pasar las propiedades src y alt requeridas desde tu imagen al componente <Image />:

    src/components/MarkdocImage.astro
    ---
    import type { ImageMetadata } from "astro";
    import { Image } from "astro:assets";
    interface Props {
    src: ImageMetadata;
    alt: string;
    }
    const { src, alt } = Astro.props;
    ---
    <Image src={src} alt={alt} />
  2. El componente <Image /> requiere un width y height para imágenes remotas que no se pueden proporcionar utilizando la sintaxis ![](). Para evitar errores al usar imágenes remotas, actualiza tu componente para renderizar una etiqueta HTML <img> estándar cuando se encuentre un URL remoto en src:

    src/components/MarkdocImage.astro
    ---
    import type { ImageMetadata } from "astro";
    import { Image } from "astro:assets";
    interface Props {
    src: ImageMetadata | string;
    alt: string;
    }
    const { src, alt } = Astro.props;
    ---
    <Image src={src} alt={alt} />
    {
    typeof src === 'string' ? <img src={src} alt={alt} /> : <Image src={src} alt={alt} />
    }
  3. Configura Markdoc para sobrescribir el nodo de imagen predeterminado y renderizar MarkdocImage.astro:

    markdoc.config.mjs
    import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';
    export default defineMarkdocConfig({
    nodes: {
    image: {
    ...nodes.image, // Apply Markdoc's defaults for other options
    render: component('./src/components/MarkdocImage.astro'),
    },
    },
    });
  4. La sintaxis de imagen nativa en cualquier archivo .mdoc ahora utilizará el componente <Image /> para optimizar tus imágenes locales. Las imágenes remotas aún se pueden usar, pero no serán renderizadas por el componente <Image /> de Astro.

    src/content/blog/post.mdoc
    <!-- Optimized by <Image /> -->
    ![A picture of a cat](/cat.jpg)
    <!-- Unoptimized <img> -->
    ![A picture of a dog](https://example.com/dog.jpg)

Crear una etiqueta de imagen personalizada de Markdoc

Sección titulada «Crear una etiqueta de imagen personalizada de Markdoc»

Una etiqueta de imagen de Markdoc te permite establecer atributos adicionales en tu imagen que no son posibles con la sintaxis ![](). Por ejemplo, las etiquetas de imagen personalizadas te permiten usar el componente <Image /> de Astro para imágenes remotas que requieren un width y height.

Los siguientes pasos crearán una etiqueta de imagen personalizada de Markdoc para mostrar un elemento <figure> con una leyenda, utilizando el componente <Image /> de Astro para optimizar la imagen.

  1. Crea un componente MarkdocFigure.astro para recibir las props necesarias y renderizar una imagen con una leyenda:

    src/components/MarkdocFigure.astro
    ---
    import type { ImageMetadata } from "astro";
    import { Image } from "astro:assets";
    interface Props {
    src: ImageMetadata | string;
    alt: string;
    width: number;
    height: number;
    caption: string;
    }
    const { src, alt, width, height, caption } = Astro.props;
    ---
    <figure>
    <Image {src} {alt} {width} {height} />
    {caption && <figcaption>{caption}</figcaption>}
    </figure>
  2. Configura tu etiqueta de imagen personalizada para renderizar tu componente de Astro:

    markdoc.config.mjs
    import { component, defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
    export default defineMarkdocConfig({
    tags: {
    image: {
    attributes: {
    width: {
    type: String,
    },
    height: {
    type: String,
    },
    caption: {
    type: String,
    },
    ...nodes.image.attributes
    },
    render: component('./src/components/MarkdocFigure.astro'),
    },
    },
    });
  3. Usa la etiqueta image en los archivos de Markdoc para mostrar una figura con una leyenda, proporcionando todos los atributos necesarios para tu componente:

    {% image src="./astro-logo.png" alt="Astro Logo" width="100" height="100" caption="a caption!" /%}

El archivo markdoc.config.mjs|ts acepta todas las opciones de configuración de Markdoc, incluyendo tags y functions.

Puedes pasar estas opciones desde la exportación por defecto en tu archivo markdoc.config.mjs|ts:

markdoc.config.mjs
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
functions: {
getCountryEmoji: {
transform(parameters) {
const [country] = Object.values(parameters);
const countryToEmojiMap = {
japan: '🇯🇵',
spain: '🇪🇸',
france: '🇫🇷',
};
return countryToEmojiMap[country] ?? '🏳';
},
},
},
});

Ahora, puedes llamar a esta función desde cualquier entrada de contenido de Markdoc:

¡Hola {% getCountryEmoji("spain") %}!
Consulta la documentación de Markdoc para obtener más información sobre el uso de variables o funciones en tu contenido.

Markdoc envuelve los documentos con una etiqueta <article> por defecto. Esto se puede cambiar desde el nodo document de Markdoc. Esto acepta un nombre de elemento HTML o null si prefieres eliminar el elemento contenedor:

markdoc.config.mjs
import { defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
nodes: {
document: {
...nodes.document, // Apply defaults for other options
render: null, // default 'article'
},
},
});

Opciones de configuración de la integración

Sección titulada «Opciones de configuración de la integración»

La integración Astro Markdoc se encarga de configurar las opciones y capacidades de Markdoc que no están disponibles a través del archivo markdoc.config.js.

Type: boolean
Default: false

Agregado en: @astrojs/markdoc@0.4.4

Permite escribir marcado HTML junto con etiquetas y nodos de Markdoc.

Por defecto, Markdoc no reconocerá el marcado HTML como contenido semántico.

Para lograr una experiencia más similar a Markdown, donde se pueden incluir elementos HTML junto con tu contenido, establece allowHTML:true como una opción de la integración markdoc. Esto habilitará el análisis de HTML en el marcado de Markdoc.

astro.config.mjs
import { defineConfig } from 'astro/config';
import markdoc from '@astrojs/markdoc';
export default defineConfig({
// ...
integrations: [markdoc({ allowHTML: true })],
});

Type: boolean
Default: false

Agregado en: @astrojs/markdoc@0.7.0

Por defecto, cualquier contenido que esté sangrado por cuatro espacios se trata como un bloque de código. Desafortunadamente, este comportamiento dificulta el uso de niveles arbitrarios de sangría para mejorar la legibilidad de documentos con estructura compleja.

Al usar etiquetas anidadas en Markdoc, puede ser útil sangrar el contenido dentro de las etiquetas para que el nivel de profundidad sea claro. Para admitir la sangría arbitraria, tenemos que deshabilitar los bloques de código basados en sangría y modificar varias otras reglas de análisis de markdown-it que tienen en cuenta los bloques de código basados en sangría. Estos cambios se pueden aplicar habilitando la opción ignoreIndentation.

astro.config.mjs
import { defineConfig } from 'astro/config';
import markdoc from '@astrojs/markdoc';
export default defineConfig({
// ...
integrations: [markdoc({ ignoreIndentation: true })],
});
# Welcome to Markdoc with indented tags 👋
# Note: Can use either spaces or tabs for indentation
{% custom-tag %}
{% custom-tag %} ### Tags can be indented for better readability
{% another-custom-tag %}
This is easier to follow when there is a lot of nesting
{% /another-custom-tag %}
{% /custom-tag %}
{% /custom-tag %}

Más integraciones

Frameworks de front-end

Adaptadores

Otras integraciones

Contribuir Comunidad Patrocinar