astro-mystv0.3.0

astro-myst is an Astro integration and content loader for MyST, the Markedly Structured Text toolchain behind Jupyter Book. Point a content collection at a folder of MyST files and every file becomes an entry, compiled by the official mystmd engine: numbered sections, figures, tables and equations, cross-references between pages, citations, math, LaTeX sources and notebooks all arrive resolved. Your layout, routing and styling stay yours.

MyST sources are compiled by mystmd, rendered to HTML by astro-myst and served by Astro.

Figure 1: How a page gets from a MyST source file to your Astro site.

Why#

Astro’s Markdown pipeline renders one file at a time, so it cannot number a figure in one file and reference it from another. MyST is built for exactly that, and mystmd resolves numbering, references and citations across a whole collection of files (Cockett, 2022). astro-myst runs that compiler and hands the result to Astro, as shown in Figure 1. This site is itself an example: it is written in MyST and rendered by astro-myst.

Numbering and cross-references

Sections, figures, sub-figures, tables, equations, code listings and theorems are numbered automatically, and @label references resolve across pages.

Citations

BibTeX keys and bare DOIs (<doi:10.…>) become citations with a bibliography on every page.

LaTeX and notebooks

.tex files and Jupyter notebooks are pages like any other, with the same numbering and references.

No myst.yml

MyST options go in your Astro config. Nothing is generated next to your content or in public/.

Astro-native

Entries work with getCollection(), render() and <Content />, keep your own frontmatter for your schema, and links follow your routes, base and trailingSlash.

Your styles

The default styles only make MyST content work and never win against your CSS, so Tailwind and prose just work. An optional theme is one option away.

Quick example#

Install astro-myst and the MyST compiler:

npm install astro-myst mystmd

Then add the integration, a collection and a route. There is no myst.yml:

import { defineConfig } from 'astro/config';
import myst from 'astro-myst';

export default defineConfig({
  integrations: [myst()],
});
import { defineCollection } from 'astro:content';
import { mystLoader } from 'astro-myst/loaders';

export const collections = {
  blog: defineCollection({ loader: mystLoader({ base: './src/content/blog' }) }),
};
---
import { getCollection, render } from 'astro:content';

export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map((post) => ({ params: { slug: post.id === 'index' ? undefined : post.id }, props: { post } }));
}

const { post } = Astro.props;
const { Content } = await render(post);
---

<article>
  <h1>{post.data.title}</h1>
  <Content />
</article>

Every Markdown file and notebook in src/content/blog becomes an entry. The files are compiled together, so a post can reference another post’s figures and equations.

The same setup scales from a blog to a book. A blog keeps its own frontmatter (pubDate, draft, heroImage) and types it with your schema. A book orders its chapters with the loader’s toc option, numbers them with MyST’s numbering options and builds a sidebar from each entry’s position in that table of contents.

A taste#

Write this in a MyST file:

The energy of a photon is given by @eq-photon.

```{math}
:label: eq-photon
E = h\nu
```

and you get a numbered equation with a working reference — here rendered live:

E=hνE = h\nu
(1)

The energy of a photon is given by (1). Hover the reference to preview the equation; the same works for references to other pages, like the routing guide.

Next steps#

References

  1. Cockett, R. (2022). MyST Markdown. Zenodo. 10.5281/zenodo.6476040