Как в Astro программно задать Layout для всех файлов Markdown в коллекции

Для вставки статьи, написанной c помощью Markdown, в шаблон страницы сайта на Astro, в документации предлагается указать Layout в секции Frontmatter файла Markdown:

// post.md
---
layout: ../../layouts/Post.astro
title: Заголовок статьи
---

А в самом шаблоне страницы, посредством тега slot, необходимо указать то место, куда будет вставлен текст Markdown после рендеринга:

// Post.astro
---
const {frontmatter} = Astro.props;
---

<html>
  ...
  <body>
    ...
    <h1>{frontmatter.title}</h1>
    <slot />
    ...
  </body>
</html>

Но у этого способа есть существенный недостаток - корректный Layout необходимо явно указать во всех файлах Markdown и, при этом, не ошибиться. А если таких файлов сотни или даже тысячи?

В Netlify CMS, при создании нового файла Markdown, эту процедуру можно автоматизировать, добавив скрытое поле со значением по умолчанию:

// config.yml
...
collections:
  - name: "posts"
    label: "Блог"
    label_singular: "Пост"
    folder: "src/pages/posts"
    create: true
    fields:
      - { label: "Шаблон", name: "layout", widget: "hidden", default: "../../layouts/Post.astro" }
      - { label: "Заголовок", name: "title", widget: "string" }
...

Тем не менее, в случае изменения структуры сайта или при переносе файлов Markdown с другого ресурса, необходимо будет прописать новый Layout во всех этих файлах и это может превратиться в головную боль.

А можно не прописывать Layout в каждом файле Markdown, а указать его один раз для всех файлов Markdown в коллекции (папке)?

Да, можно.

Для этого необходимо воспользоваться динамической маршрутизацией и в этой статье я покажу как это сделать.

Первым делом переносим все файлы Markdown за пределы папки pages, чтобы Astro не генерировал для них страницы со статической маршрутизацией:

# project folder
src
 layouts
 ...
 pages
 posts
 [slug].astro
 ...
 posts
 post.md
 other.md
 ...

Внутри папки pages, в подпапке, где должны были располагаться файлы Markdown, создаём шаблон динамической маршрутизации [slug].astro со следующим содержимым:

// [slug].astro
---
export async function getStaticPaths() {
  const posts = await Astro.glob("../../posts/*.md");
  return posts.map((post) => {
    const path = post.file.split("/");
    const slug = path[path.length - 1].split(".")[0];
    return {
      params: {
        slug: slug,
      },
      props: {
        post,
      },
    };
  });
}

const { frontmatter, Content } = Astro.props.post;
---

<html>
  ...
  <body>
    ...
    <h1>{frontmatter.title}</h1>
    <Content />
    ...
  </body>
</html>

Теперь, ко всей коллекции файлов Markdown, полученной при помощи функции Astro.glob(), будет применяться Layout динамической маршрутизации [slug].astro.

В этом примере переменная динамического маршрута [slug] заменяется на название файла Markdown без расширения. Но для этой цели можно использовать любое другое поле из Frontmatter. Например, можно создать поле slug для явного назначения адреса странице.

AG & Dev © 2020 Moscow