lenec ru

← все посты

Astro: getStaticPaths must be defined — что делать

15K

Запускаешь сборку Astro и получаешь:

[ERROR] getStaticPaths() function is required for dynamic routes.
Make sure that you export a function called getStaticPaths from /src/pages/posts/[slug].astro

Сообщение прямое: динамическая страница есть, а функции, которая возвращает список параметров для генерации, — нет. Astro в SSG-режиме без неё не понимает, какие страницы создавать.

Это одна из самых регулярных ошибок у людей, которые мигрируют на Astro с Next или Nuxt. Там логика построения динамических роутов другая, и привычка переносится автоматически. У меня в команде эта ошибка ловилась на ревью пять раз, прежде чем все привыкли.

Что это за функция вообще

Astro по умолчанию работает в режиме генерации статики. Если у тебя есть файл src/pages/posts/[slug].astro, фреймворк не знает, какие именно посты существуют. Ты ему говоришь сам:

---
export async function getStaticPaths() {
  const posts = await fetchAllPosts();
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

const { post } = Astro.props;
---
<article>
  <h1>{post.title}</h1>
  <div set:html={post.content} />
</article>

Astro вызывает getStaticPaths на сборке, проходит по массиву и для каждого элемента генерит отдельную страницу с нужными параметрами и пропсами.

Если функции нет — конкретно эта ошибка.

Самые частые причины

1. Просто забыл

Поставил [slug].astro, написал шаблон, забыл функцию. Лечится её добавлением.

2. Не export

Объявил, но без export:

// плохо — Astro не увидит
async function getStaticPaths() {
  return [...];
}

В Astro фреймпсы из frontmatter (между ---) — это нормальный TypeScript-модуль. Чтобы Astro прочитал функцию, она должна быть экспортирована: export async function getStaticPaths().

3. Опечатка в имени

getStaticPath, getStaticPathss, getStaticPaths — Astro смотрит на точное имя. Любая вариация приведёт к той же ошибке.

4. Возвращаешь не массив

Иногда возвращают объект или ничего:

// плохо
export async function getStaticPaths() {
  return { '/foo': {...} };
}

Должен быть массив объектов с полями params и опционально props:

return [
  { params: { slug: 'a' }, props: { post: {...} } },
  { params: { slug: 'b' }, props: { post: {...} } },
];

Когда динамический роут — не SSG

Если у тебя адаптер с SSR (@astrojs/node, @astrojs/vercel, @astrojs/cloudflare и так далее) и страница рендерится на сервере, getStaticPaths не нужен. Но для этого надо явно отметить страницу как SSR. В Astro 5 это делается через export const prerender = false;:

---
export const prerender = false;

const { slug } = Astro.params;
const post = await fetchPost(slug);
---
<article>
  <h1>{post.title}</h1>
</article>

Без этой строки и без getStaticPaths — будет ошибка. Astro по умолчанию в режиме static, а ты пишешь страницу как серверную. Либо добавь функцию, либо отключи prerender.

Если параметров много

Несколько динамических сегментов — массив объектов с несколькими полями в params:

// src/pages/[lang]/[slug].astro
export async function getStaticPaths() {
  return [
    { params: { lang: 'ru', slug: 'about' } },
    { params: { lang: 'en', slug: 'about' } },
    { params: { lang: 'ru', slug: 'contact' } },
  ];
}

Все динамические сегменты файла должны быть в params, иначе будет ошибка про несоответствие.

Пагинация

Часто список постов нужно разбить на страницы. Astro даёт paginate для этого:

// src/pages/blog/[page].astro
import type { GetStaticPathsOptions } from 'astro';

export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
  const posts = await fetchAllPosts();
  return paginate(posts, { pageSize: 10 });
}

const { page } = Astro.props;
---
<ul>
  {page.data.map((p) => <li>{p.title}</li>)}
</ul>

Astro сам сгенерит страницы /blog/1, /blog/2 и так далее. Если этого не сделать — ошибка та же.

Дебаг-трюк

Иногда хочется посмотреть, что вообще возвращает getStaticPaths и почему страница не строится. Делаю так:

export async function getStaticPaths() {
  const posts = await fetchAllPosts();
  console.log('posts count:', posts.length);
  if (posts.length === 0) {
    console.warn('No posts to generate');
  }
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

Если в логе сборки posts count: 0 — функция работает, но данных нет. Тогда это уже проблема источника данных, а не Astro.

Чек-лист

  • Файл с динамическими сегментами ([slug].astro) — есть.
  • export async function getStaticPaths — есть и экспортирована.
  • Возвращает массив объектов с полем params.
  • Если SSR — export const prerender = false;.
  • Если пагинация — используешь paginate из аргумента.

Когда привыкаешь, добавление getStaticPaths уходит в мышечную память. Astro заставляет тебя думать о том, какие страницы реально существуют, на этапе сборки — это даёт быструю и предсказуемую генерацию без runtime-сюрпризов.

Комментарии 0

  • Будьте первым, кто оставит комментарий.

Войдите, чтобы оставить комментарий.