lenec ru

← все посты

Astro 4 → 5: что сломалось и как чинить

12K

Я мигрировал три проекта с Astro 4 на 5. Один — контент-сайт со статикой, второй — гибрид с серверным рендером и API-роутами, третий — большой монорепозиторий с собственными интеграциями. Опыт у каждого свой, но общая картина одинаковая: миграция не страшная, но без чек-листа теряется время на перерывы и поиск решения по issue-трекеру.

Здесь — что реально ломается, что хочется поправить заранее и какие шаги стоит проделать в правильном порядке.

Версии Node и пакетов

Astro 5 требует Node 18.20.8+ или 20.3+, либо 22+. Если у тебя в CI всё ещё крутится 18.0.0 — обнови до 18.20+ или сразу до 22 LTS. У меня на одном проекте именно из-за старой ноды отвалилась сборка, причём в ошибке было указано не «обновите Node», а нечитаемый stack от Vite.

Astro 5 идёт на Vite 6, поэтому интеграции, которые жёстко прибиты к Vite 4 или 5, придётся обновить. Список таких пакетов короткий, но если у вас был свой плагин — пройдитесь по changelog Vite 6 и убедитесь, что не используете удалённые API.

Конфиг: output, hybrid и prerender

Главное концептуальное изменение. В Astro 4 поле output могло быть 'static', 'server' или 'hybrid'. В Astro 5 'hybrid' исчез: теперь любой проект, где есть SSR-страницы, объявляется как output: 'server', а статичные страницы помечаются export const prerender = true.

// Astro 4
export default defineConfig({ output: 'hybrid', adapter: node({ mode: 'standalone' }) });

// Astro 5
export default defineConfig({ output: 'server', adapter: node({ mode: 'standalone' }) });

В каждой странице, которая раньше неявно билдилась статически, проставь prerender = true. Можно всё пометить разом через хук в middleware.ts, но я предпочитаю явный экспорт — так видно поведение по файлам.

Content Collections и content layer

Если у тебя в проекте использовались коллекции через defineCollection с локальными MDX/Markdown — на четвёрке всё работало, но на пятёрке тебе предложат перейти на новый Content Layer API.

Старый код останется работать, ты получишь предупреждение о деплое. Если коллекция простая — миграция дело десяти минут. Если сложная (с глоссарием, кастомными loader-ами через скрипты) — закладывай день на переписывание.

import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';

const posts = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/data/posts' }),
  schema: z.object({
    title: z.string(),
    pubDate: z.coerce.date(),
    tags: z.array(z.string()).default([]),
  }),
});

export const collections = { posts };

Главное отличие от старой схемы — теперь явно указываешь loader. Это полезно, потому что коллекцию можно собрать из чего угодно: API, БД, удалённого репозитория. Я этим уже воспользовался: вытаскиваю заметки из Notion-копии и сразу собираю их в коллекцию без промежуточных скриптов.

API endpoints: только заглавные методы

В Astro 4 разрешалось писать export async function get() в API-роуте. В пятёрке поддерживаются только GET, POST, PUT, DELETE, PATCH, OPTIONS, ALL. Если оставить нижний регистр — endpoint просто не зарегистрируется. Это ловится глобальным поиском по export async function (get|post|put|delete|patch)\( и заменой.

Astro DB

Если использовал @astrojs/db, в пятёрке его статус сменился. Команда отметила, что фокусируется на ядре, и активная разработка остановлена. Сами таблицы продолжают работать, но новых фич ждать не стоит. Если ты только закладываешь хранилище — присмотрись к Drizzle напрямую, выйдет надёжнее.

Image Service

В пятёрке поведение <Image /> немного изменилось: при SSR оптимизация по умолчанию делается через сервис sharp, и он выполняется в рантайме. Если у тебя был кастомный сервис с тонкой логикой кэширования — проверь, что он переписан на новый интерфейс SharedAdapter.

Самая частая проблема, которую я видел: на проде картинки отдаются медленно, потому что Sharp обрабатывает их по запросу без слоя кэширования. Решение простое — поставь перед сервером CDN, либо включи на адаптере опцию хранения предобработанных изображений.

Client islands

API клиентских островов client:idle, client:visible и client:load остались. Что изменилось — внутренний механизм генерации границы. Если у тебя были runtime-хаки, которые работали через перехват data-island-id или похожих атрибутов, они почти наверняка отвалились. Лечится переписыванием на стандартный client:*.

Чек-лист перед миграцией

  • Обнови Node до 20.3+ (а лучше 22 LTS) и подними версию в CI.
  • Запиши версии всех интеграций до апдейта — пригодится, если что-то откатывать.
  • Перейди на output: 'server', расставь prerender.
  • Проверь все API-endpoints на регистр методов.
  • Перепиши коллекции на content layer, если они нетривиальные.
  • Прогон визуальных регрессионных тестов после билда — даже если у тебя их два.

Шаг, который я бы не пропускал

До миграции запусти полный билд на четвёрке, сохрани dist/. После пятёрки сравни хотя бы по размерам файлов и количеству чанков. Я однажды поймал ситуацию, когда после апдейта появлялся лишний серверный entry-чанк, потому что одна страница случайно перестала быть статической. Без сравнения это бы заметили только через мониторинг производительности на проде.

В сухом остатке

Astro 5 — не революция. Это аккуратный апдейт, в котором команда давно собиралась убрать 'hybrid', перейти на новый content layer и почистить наследие. Все три проекта перевёл за совокупно три рабочих дня, и больше всего времени ушло не на миграцию как таковую, а на актуализацию интеграций сторонних пакетов. Если откладывал — самое время взяться, в шестёрке наверняка снова придётся переписывать конфиги.

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

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

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